
  /* ============================================================
     TOKENS

     Two blocks, in this order:
       1. :root                    — light, and the default for everyone
       2. :root[data-theme="dark"] — dark, and ONLY when the toggle asks for it

     Light is the default outright: the site no longer follows
     prefers-color-scheme (owner call, 2026-07-30). That is deliberate rather
     than an oversight, so there is no @media (prefers-color-scheme: dark)
     block anywhere in this file. Adding one back would hand a dark-OS visitor
     a theme the toggle then reports as "light", because the toggle reads the
     data-theme attribute and an @media block leaves no attribute behind.

     Shell identity: cool tinted neutrals + one committed accent (a blue tuned
     to sit near the product's own Temporary Faculty bucket color, the one
     deliberate bridge between marketing shell and product UI). --accent is
     for text/links/borders; --accent-solid is what a button sits on; they
     diverge because a single shade can't pass AA as both body text on --bg
     and as a fill under white button text without failing one or the other.

     --bucket-1..4 are FIXED across both themes — they are the product's own
     signature colors (see PRODUCT-UI-SPEC.md), not shell-adaptive tokens.
     ============================================================ */
  :root{
    /* Warm paper, warm ink. The hue shift from the previous cool-blue neutrals
       is the whole point: a ledger is printed stock, not a screen surface. */
    --bg:         oklch(97.6% 0.008 85);   /* warm paper */
    --bg-inset:   oklch(95.4% 0.011 85);   /* ruled band */
    --surface:    oklch(99.2% 0.005 85);
    --ink:        oklch(22%   0.014 60);   /* warm near-black, never #000 */
    --ink-muted:  oklch(47%   0.012 60);
    --rule:       oklch(86%   0.010 75);   /* hairline */
    --rule-firm:  oklch(72%   0.012 70);   /* section and total rules */

    /* Chroma is near-absent by design. The only saturated colours on the page
       are the four product bucket colours, plus red strictly for over-
       allocation. The interactive accent IS bucket-1, so the palette gains no
       fifth hue for links and buttons. */
    --accent:        oklch(44% 0.15 258);
    --accent-line:   oklch(64% 0.10 258);
    --accent-solid:  oklch(26% 0.016 60);  /* CTA is ink-filled: near-neutral, not brown */
    --accent-hover:  oklch(22% 0.014 60);
    --on-accent:     oklch(97.6% 0.008 85);
    --accent-wash:   oklch(44% 0.15 258 / 7%);

    --good:      oklch(45% 0.11 150);
    --good-wash: oklch(45% 0.11 150 / 9%);
    --warn-ink:  oklch(46% 0.10 70);
    --warn-wash: oklch(80% 0.12 80 / 16%);
    --negative:  oklch(48% 0.19 27);       /* ledger red: over-allocation only */

    --bucket-1: #1B5FBF;
    --bucket-2: #5BA4E8;
    --bucket-3: #7BC77B;
    --bucket-4: #F0C070;

    /* A ledger has no drop shadows. Depth comes from rules. */
    --shadow: none;
    --shadow-sm: none;

    --display: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", "Helvetica Neue", Arial, sans-serif;
    --body: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif;
    --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;

    --ease: cubic-bezier(.22,1,.36,1);
    --t-fast: 130ms;
    --t-med: 340ms;

    color-scheme: light;
  }

  :root[data-theme="dark"]{
    --bg:       oklch(15.5% 0.010 60);   /* warm black, the ink-inversion */
    --bg-inset:   oklch(19%   0.012 60);
    --surface:    oklch(18%   0.011 60);
    --ink:      oklch(93%   0.008 85);   /* paper, now the foreground */
    --ink-muted:  oklch(70%   0.010 75);
    --rule:     oklch(32%   0.012 60);
    --rule-firm:  oklch(46%   0.014 62);

    --accent:      oklch(76% 0.12 250);
    --accent-line:   oklch(56% 0.10 255);
    --accent-solid:  oklch(90% 0.010 85);  /* inverted: paper-filled CTA */
    --accent-hover:  oklch(98% 0.006 85);
    --on-accent:     oklch(15.5% 0.010 60);
    --accent-wash:   oklch(76% 0.12 250 / 14%);

    --good:    oklch(76% 0.15 150);
    --good-wash: oklch(76% 0.15 150 / 12%);
    --warn-ink:  oklch(82% 0.12 80);
    --warn-wash: oklch(80% 0.12 80 / 14%);
    --negative:  oklch(70% 0.17 27);

    --shadow: none;
    --shadow-sm: none;
    color-scheme: dark;
  }

  *{box-sizing:border-box;}
  html{scroll-behavior:smooth;}
  @media (prefers-reduced-motion: reduce){
    html{scroll-behavior:auto;}
    *{animation-duration:.001ms !important; animation-iteration-count:1 !important; transition-duration:.001ms !important;}
  }
  body{
    margin:0; background:var(--bg); color:var(--ink);
    font-family:var(--body); font-size:16px; line-height:1.6;
    -webkit-font-smoothing:antialiased;
    overflow-x:hidden;
  }
  img,svg{max-width:100%;}
  a{color:inherit;}
  .wrap{max-width:1160px; margin:0 auto; padding:0 28px;}
  @media (max-width:640px){ .wrap{padding:0 20px;} }

  .sr-only{
    position:absolute; width:1px; height:1px; padding:0; margin:-1px;
    overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;
  }

  .eyebrow{
    font-family:var(--mono); font-size:.7rem; letter-spacing:.13em; text-transform:uppercase;
    color:var(--ink-muted);
  }
  .eyebrow b{color:var(--accent); font-weight:600;}

  h1,h2,h3,h4{
    font-family:var(--display); font-weight:700; margin:0;
    line-height:1.15; letter-spacing:-.02em; text-wrap:balance;
  }
  h1{line-height:1.03; letter-spacing:-.03em;}
  h3,h4{font-weight:650; letter-spacing:-.01em;}
  p{margin:0; text-wrap:pretty;}

  :focus-visible{outline:2px solid var(--accent); outline-offset:3px; border-radius:2px;}

  .skip-link{
    position:absolute; left:16px; top:-100px; z-index:100;
    background:var(--surface); color:var(--ink); border:1px solid var(--accent);
    padding:0 18px; min-height:44px; display:inline-flex; align-items:center;
    border-radius:6px; text-decoration:none; box-shadow:var(--shadow);
    font-family:var(--mono); font-size:.72rem; letter-spacing:.06em; text-transform:uppercase;
    transition:top var(--t-fast) var(--ease);
  }
  .skip-link:focus{top:12px;}
  main :target, main [id]{scroll-margin-top:88px;}

  /* ---------- header ---------- */
  header.site{
    position:sticky; top:0; z-index:50;
    background:color-mix(in srgb, var(--bg) 86%, transparent);
    backdrop-filter: blur(10px);
    border-bottom:1px solid var(--rule);
  }
  .nav{
    display:flex; align-items:center; justify-content:space-between;
    /* padding-block, NOT the `padding` shorthand. This element is `wrap nav`,
       and `.wrap` supplies the 28px/20px gutter at the same specificity
       earlier in source — a shorthand here silently reset it to 0, which only
       showed below 1160px where .wrap's centering no longer fakes a margin. */
    padding-block:16px;
  }
  .brand{display:flex; align-items:center; gap:11px; text-decoration:none; min-height:44px;}
  /* The mark is a literal 2x2 of the product's own bucket colors — the shell's
     first and clearest statement of the "one deliberate bridge" to the
     product UI, before a single word of copy. */
  .nav-links a, .theme-toggle{transition:color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);}

  .nav-links{display:flex; align-items:center; gap:20px;}
  .nav-links a{
    font-family:var(--mono); font-size:.72rem; letter-spacing:.05em; text-transform:uppercase;
    text-decoration:none; color:var(--ink-muted); font-weight:600;
    display:inline-flex; align-items:center; min-height:44px; padding:0 6px;
    white-space:nowrap;
  }
  .nav-links a:hover{color:var(--accent);}
  .nav-links .cta{
    color:var(--on-accent); background:var(--accent-solid); padding:0 16px; border-radius:6px;
  }
  .nav-links .cta:hover{background:var(--accent-hover);}
  .theme-toggle{
    border:1px solid var(--rule); background:var(--surface); color:var(--ink-muted);
    width:36px; height:36px; border-radius:50%; cursor:pointer;
    display:flex; align-items:center; justify-content:center;
    font-size:.9rem; line-height:1; flex:none;
  }
  .theme-toggle:hover{color:var(--accent); border-color:var(--accent);}
  .theme-toggle:active{transform:scale(.94);}

  @media (max-width:940px){
    .nav-links{gap:12px;}
    .nav-links a{font-size:.68rem; padding:0 4px;}
  }
  @media (max-width:820px){
      .nav-links a[href="#features"], .nav-links a[href="#how-it-works"]{display:none;}
  }
  @media (max-width:480px){
    .nav-links a[href="#pricing"]{display:none;}
    .nav-links .cta{padding:0 12px; font-size:.64rem;}
  }

  /* ---------- hero ---------- */
  /* Top padding is deliberately tighter than the bottom: with the orientation
     list now sitting between the sub and the CTA, the old 108px ceiling pushed
     the primary action below the fold on a 900px laptop. The page's one job is
     getting a budget office to email; the ask has to be visible. */
  .hero{padding:clamp(44px, 6vh, 72px) 0 clamp(72px, 10vh, 120px);}
  /* align-items:start, not center. The product panel is ~1100px tall and the
     text column ~700px; centring them dumped ~185px of dead space above the
     headline and pushed the CTA off the fold. Top-aligned also reads as a
     deliberate asymmetric composition rather than a centred stack. */
  .hero-grid{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.08fr); gap:clamp(36px,5vw,64px); align-items:start;}
  /* Plain 1fr here (instead of minmax(0,1fr)) let the panel's own min-content
     — the nav tab row's white-space:nowrap labels — blow the track out past
     the container; a single fr track still needs the min-width:0 override. */
  @media (max-width:980px){ .hero-grid{grid-template-columns:minmax(0,1fr); gap:48px;} }

  /* 3.4rem, not 3.9rem: at 3.9 the headline wrapped to five lines in this
     column and cost the fold ~80px for no extra impact. Still the largest
     thing on the page by a wide margin. */
  h1.headline{
    font-size:clamp(2.2rem, 4.1vw, 3.4rem); line-height:1.06; max-width:15ch;
  }
  .hero-sub{
    margin-top:clamp(22px, 3vh, 32px); max-width:52ch;
    font-size:1.1rem; line-height:1.65; color:var(--ink-muted);
  }
  .hero-actions{
    margin-top:clamp(28px, 4vh, 40px);
    display:flex; align-items:center; gap:16px; flex-wrap:wrap;
  }
  .btn{
    font-family:var(--body); font-size:.95rem; font-weight:600; text-decoration:none;
    padding:13px 22px; border-radius:7px; border:1px solid transparent;
    display:inline-flex; align-items:center; justify-content:center; min-height:44px;
    transition:background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
  }
  .btn:active{transform:translateY(1px);}
  .btn-primary{background:var(--accent-solid); color:var(--on-accent);}
  .btn-primary:hover{background:var(--accent-hover);}
  .btn-ghost{border-color:var(--rule); color:var(--ink);}
  .btn-ghost:hover{border-color:var(--accent); color:var(--accent); background:var(--accent-wash);}

  @keyframes rise-in{ from{opacity:0; transform:translateY(14px);} to{opacity:1; transform:translateY(0);} }
  .hero-grid > *{animation:rise-in var(--t-med) var(--ease) both;}
  .hero-grid > *:nth-child(2){animation-delay:80ms;}

  /* ---------- sections ---------- */
  section{padding:88px 0;}
  section.tint{background:var(--bg-inset);}
  .section-head{max-width:60ch; margin-bottom:48px;}
  .section-head h2{font-size:clamp(1.6rem,2.6vw,2.15rem);}
  .section-head p{margin-top:16px; color:var(--ink-muted); font-size:1.03rem; line-height:1.65;}

  .divider{height:1px; background:var(--rule); border:none; margin:0;}

  /* Decorative reprise of the bucket-color motif, used sparingly as a section
     seam rather than a plain rule — the one other place the shell borrows the
     product's own palette. Purely decorative: aria-hidden, no meaning by
     color alone. */
  .bucket-seam{height:3px; display:flex; border:none; margin:0;}
  .bucket-seam span{flex:none;}
  .bucket-seam span:nth-child(1){background:var(--bucket-1); width:81.4%;}
  .bucket-seam span:nth-child(2){background:var(--bucket-2); width:15%;}
  .bucket-seam span:nth-child(3){background:var(--bucket-3); width:2.5%;}
  .bucket-seam span:nth-child(4){background:var(--bucket-4); width:1.2%;}

  /* ---------- problem ---------- */
  .problem-grid{display:grid; grid-template-columns:1fr 1fr; gap:56px; align-items:start;}
  @media (max-width:800px){.problem-grid{grid-template-columns:minmax(0,1fr);}}
  .problem-grid p{color:var(--ink-muted); font-size:1.03rem; line-height:1.7;}
  .problem-grid p + p{margin-top:16px;}
  .problem-grid .lede{font-family:var(--display); font-weight:650; font-size:1.4rem; color:var(--ink); line-height:1.35; letter-spacing:-.01em;}

  /* ---------- traced total (signature) ---------- */
  .traced{
    margin-top:56px; padding:40px; background:var(--surface); border:1px solid var(--rule); border-radius:14px;
    box-shadow:var(--shadow);
  }
  .traced-label{font-family:var(--mono); font-size:.66rem; letter-spacing:.13em; text-transform:uppercase; color:var(--ink-muted); text-align:center; margin-bottom:28px;}
  .traced-row{display:flex; align-items:center; gap:0; justify-content:center; flex-wrap:wrap;}
  .traced-card{
    width:200px; padding:18px; border:1px solid var(--rule); border-radius:8px; background:var(--bg);
    text-align:center;
  }
  .traced-card .tc-label{font-family:var(--mono); font-size:.62rem; letter-spacing:.1em; text-transform:uppercase; color:var(--ink-muted); margin-bottom:10px;}
  .traced-card .tc-value{font-family:var(--mono); font-size:1.3rem; font-weight:700; color:var(--accent); font-variant-numeric:tabular-nums;}
  .traced-card .tc-context{font-size:.78rem; color:var(--ink-muted); margin-top:6px;}
  .traced-link{flex:none; width:56px; height:1px; background:var(--accent-line); position:relative;}
  .traced-link::after{
    content:"◆"; position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
    font-size:.5rem; color:var(--accent);
  }
  @media (max-width:760px){
    .traced-row{flex-direction:column;}
    .traced-link{width:1px; height:32px;}
  }
  .traced-caption{text-align:center; margin-top:26px; font-size:.95rem; color:var(--ink-muted);}
  .traced-caption b{color:var(--ink); font-weight:600;}

  /* ============================================================
     PRODUCT UI RECREATIONS

     Fixed, non-theme-adaptive: these are meant to read like a screenshot of
     Lightning Experience embedded in the page, not a themed component — real
     Salesforce doesn't switch palettes with the OS, so a screenshot that did
     would read as fake. Colors below are lifted verbatim from
     PRODUCT-UI-SPEC.md. The outer .pui-frame is the only themed part: the
     card/mat the "screenshot" sits on, matching the marketing shell.

     Two tiers of content, and the distinction is load-bearing:

       DECORATIVE (aria-hidden) — the chrome header, the app nav, the record
       card. Inert span/div, never button/a. A screen reader user gets the
       .sr-only summary instead of dozens of fake controls.

       REAL (exposed) — the budget rail and the plan grid. These carry actual
       controls and actual arithmetic, so they are announced normally. Nothing
       focusable may ever be placed inside an aria-hidden subtree.
     ============================================================ */
  .pui-frame{
    background:var(--surface); border:1px solid var(--rule); border-radius:16px;
    box-shadow:var(--shadow); overflow:hidden;
  }
  .pui-chrome-header{
    background:#1B4F9C; color:#fff; display:flex; align-items:center; justify-content:space-between;
    padding:0 14px; height:34px; font-family:var(--body);
  }
  .pui-chrome-header .pui-app-name{font-size:.76rem; font-weight:600; display:flex; align-items:center; gap:8px;}
  .pui-chrome-header .pui-app-name::before{content:""; width:16px; height:16px; border-radius:4px; background:rgba(255,255,255,.9); flex:none;}
  .pui-chrome-header .pui-search{
    flex:1; max-width:220px; margin:0 20px; height:20px; border-radius:10px;
    background:rgba(255,255,255,.16); display:flex; align-items:center; padding:0 10px;
    font-size:.66rem; color:rgba(255,255,255,.7);
  }
  .pui-chrome-header .pui-head-right{display:flex; align-items:center; gap:12px; font-size:.66rem; color:rgba(255,255,255,.82); flex:none;}
  .pui-chrome-header .pui-avatar{width:18px; height:18px; border-radius:50%; background:rgba(255,255,255,.35);}
  @media (max-width:520px){ .pui-chrome-header .pui-search{display:none;} }

  .pui-navbar{
    background:#FFFFFF; border-bottom:1px solid #E5E5E5; display:flex; align-items:center;
    gap:20px; padding:0 14px; height:38px; overflow-x:auto; scrollbar-width:none;
  }
  .pui-navbar::-webkit-scrollbar{display:none;}
  .pui-navbar .pui-app-title{font-size:.76rem; font-weight:700; color:#181818; flex:none;}
  .pui-navbar .pui-tab{
    font-size:.7rem; color:#514F4D; padding:0 2px; height:100%; display:flex; align-items:center;
    border-bottom:3px solid transparent; flex:none; white-space:nowrap;
  }
  .pui-navbar .pui-tab.active{color:#0176D3; border-bottom-color:#0176D3; font-weight:600;}

  .pui-ground{background:#F3F3F3; padding:20px;}
  @media (max-width:560px){ .pui-ground{padding:14px;} }

  .pui-card{background:#FFFFFF; border:1px solid #E5E5E5; border-radius:8px; box-shadow:0 1px 2px rgba(0,0,0,.05);}
  .pui-card + .pui-card{margin-top:14px;}

  /* record header */
  .pui-record{padding:18px 20px;}
  .pui-record-top{display:flex; align-items:flex-start; gap:14px; flex-wrap:wrap;}
  .pui-icon-badge{
    width:40px; height:40px; border-radius:8px; background:#1B5FBF; color:#fff; flex:none;
    display:flex; align-items:center; justify-content:center; font-family:var(--body); font-size:.72rem; font-weight:700;
  }
  .pui-record-id{flex:1; min-width:180px;}
  .pui-record-eyebrow{font-size:.66rem; letter-spacing:.07em; text-transform:uppercase; color:#6B7280; font-family:var(--body); font-weight:600;}
  .pui-record-title{font-size:1.15rem; font-weight:700; color:#181818; font-family:var(--body); margin-top:2px; letter-spacing:0;}
  .pui-record-actions{display:flex; gap:8px; flex:none;}
  .pui-btn{
    font-family:var(--body); font-size:.68rem; font-weight:700; height:26px; padding:0 12px;
    border-radius:4px; display:inline-flex; align-items:center; white-space:nowrap;
  }
  .pui-btn.neutral{background:#fff; border:1px solid #C9C9C9; color:#0176D3;}
  .pui-btn.primary{background:#0176D3; color:#fff;}
  .pui-fields{display:grid; grid-template-columns:repeat(4,1fr); gap:14px; margin-top:16px; padding-top:14px; border-top:1px solid #E5E5E5;}
  @media (max-width:640px){ .pui-fields{grid-template-columns:1fr 1fr;} }
  .pui-field-label{font-size:.62rem; text-transform:uppercase; letter-spacing:.05em; color:#6B7280; font-family:var(--body); font-weight:600;}
  .pui-field-value{font-size:.78rem; color:#181818; font-family:var(--body); margin-top:3px;}
  .pui-pill{display:inline-flex; align-items:center; border-radius:10px; font-size:.66rem; font-weight:600; padding:2px 10px; font-family:var(--body);}
  .pui-pill.pending{background:#E8F1FB; color:#0B5CAB;}
  .pui-pill.draft{background:#E8F5E9; color:#2E7D32;}

  /* budget rail */
  .pui-budget{padding:18px 20px;}
  .pui-budget-head{display:flex; align-items:center; justify-content:space-between;}
  .pui-budget-title{font-size:.85rem; font-weight:700; color:#181818; font-family:var(--body);}
  .pui-live{font-size:.6rem; color:#2E7D32; font-family:var(--body); font-weight:700; text-transform:uppercase; display:flex; align-items:center; gap:4px;}
  .pui-live::before{content:""; width:6px; height:6px; border-radius:50%; background:#2E7D32;}
  .pui-total-label{font-size:.62rem; text-transform:uppercase; letter-spacing:.05em; color:#6B7280; font-family:var(--body); font-weight:600; margin-top:14px;}
  .pui-total-value{font-size:1.9rem; font-weight:700; color:#181818; font-family:var(--body); margin-top:2px; letter-spacing:-.01em;}
  .pui-seg-bar{height:8px; border-radius:4px; overflow:hidden; display:flex; margin-top:14px; background:#F3F3F3;}
  .pui-seg-bar span{flex:none; height:100%;}
  .pui-alloc-row{display:flex; justify-content:space-between; margin-top:10px; font-size:.72rem; font-family:var(--body);}
  .pui-alloc-row .a-left{color:#6B7280;}
  .pui-alloc-row .a-right{color:#2E7D32; font-weight:700;}
  .pui-bucket-rows{margin-top:16px; border-top:1px solid #E5E5E5;}
  .pui-bucket-row{display:flex; align-items:flex-start; gap:10px; padding:12px 0; border-top:1px solid #E5E5E5; font-family:var(--body);}
  .pui-bucket-row:first-child{border-top:none;}
  .pui-swatch{width:10px; height:10px; border-radius:2px; flex:none; margin-top:4px;}
  .pui-bucket-name{font-size:.78rem; color:#181818; font-weight:600;}
  .pui-bucket-basis{font-size:.68rem; color:#6B7280; margin-top:2px;}
  .pui-bucket-amt{margin-left:auto; text-align:right; flex:none;}
  .pui-bucket-amt .amt{font-size:.82rem; font-weight:700; color:#181818; font-variant-numeric:tabular-nums;}
  .pui-bucket-amt .pct{font-size:.66rem; color:#6B7280; margin-top:2px;}

  /* plan builder table */
  .pui-table-wrap{overflow-x:auto; -webkit-overflow-scrolling:touch;}
  table.pui-table{width:100%; min-width:640px; border-collapse:collapse; font-family:var(--body); font-size:.76rem;}
  table.pui-table caption{
    caption-side:top; text-align:left; padding:14px 18px; font-size:.68rem; color:#6B7280;
    border-bottom:1px solid #E5E5E5; font-weight:600;
  }
  table.pui-table th, table.pui-table td{padding:10px 14px; text-align:right; border-bottom:1px solid #F0F0F0; white-space:nowrap;}
  table.pui-table th:first-child, table.pui-table td:first-child{text-align:left;}
  table.pui-table thead th{
    font-size:.62rem; text-transform:uppercase; letter-spacing:.05em; color:#6B7280; font-weight:700;
    border-bottom:1px solid #E5E5E5;
  }
  table.pui-table .pui-course{display:flex; align-items:center; gap:8px;}
  table.pui-table .pui-chev{color:#706E6B; font-size:.6rem; flex:none;}
  table.pui-table .pui-code{color:#0176D3; font-weight:700;}
  table.pui-table .pui-cname{color:#181818; margin-left:6px;}
  table.pui-table .num{font-variant-numeric:tabular-nums; color:#181818;}
  table.pui-table tfoot td{font-weight:700; color:#181818; border-top:2px solid #E5E5E5; border-bottom:none; padding-top:12px;}
  .pui-qpill{display:inline-flex; border-radius:9px; font-size:.64rem; font-weight:700; padding:1px 8px;}
  .pui-qpill.fall{background:#E8F1FB; color:#0B5CAB;}
  .pui-qpill.winter{background:#E6F4EA; color:#2E7D32;}
  .pui-qpill.spring{background:#FDF3E2; color:#92600A;}

  /* approval chain */
  .pui-stepper{display:flex; align-items:flex-start; padding:6px 4px 0;}
  .pui-step{flex:1; text-align:center; position:relative;}
  .pui-step-connector{position:absolute; top:11px; left:-50%; width:100%; height:2px; background:#D8D8D8; z-index:0;}
  .pui-step:first-child .pui-step-connector{display:none;}
  .pui-step.done .pui-step-connector{background:#2E7D32;}
  .pui-step-dot{
    width:22px; height:22px; border-radius:50%; background:#D8D8D8; color:#fff; margin:0 auto;
    display:flex; align-items:center; justify-content:center; font-size:.66rem; font-weight:700; position:relative; z-index:1;
  }
  .pui-step.done .pui-step-dot{background:#2E7D32;}
  .pui-step.current .pui-step-dot{background:#0176D3;}
  .pui-step-name{font-size:.68rem; font-weight:700; color:#181818; margin-top:8px;}
  .pui-step-date{font-size:.62rem; color:#6B7280; margin-top:1px;}
  .pui-history{margin-top:16px; border-top:1px solid #E5E5E5; padding-top:12px;}
  .pui-hist-row{display:flex; align-items:baseline; gap:8px; font-size:.7rem; padding:6px 0; flex-wrap:wrap;}
  .pui-hist-dot{width:7px; height:7px; border-radius:50%; background:#0176D3; flex:none;}
  .pui-hist-name{font-weight:700; color:#181818;}
  .pui-hist-role{color:#6B7280;}
  .pui-hist-status{font-weight:700;}
  .pui-hist-status.submitted{color:#0B5CAB;}
  .pui-hist-status.approved{color:#2E7D32;}
  .pui-hist-date{color:#6B7280; margin-left:auto;}

  /* workload board */
  .pui-inst-card{display:flex; gap:10px; padding:12px 0; border-top:1px solid #E5E5E5;}
  .pui-inst-card:first-child{border-top:none;}
  .pui-inst-edge{width:3px; align-self:stretch; border-radius:2px; flex:none;}
  .pui-inst-edge.cap{background:#F28B24;}
  .pui-inst-edge.room{background:#2E7D32;}
  .pui-avatar-ring{width:30px; height:30px; border-radius:50%; background:#1B5FBF; color:#fff; flex:none; display:flex; align-items:center; justify-content:center; font-size:.62rem; font-weight:700;}
  .pui-inst-body{flex:1; min-width:0;}
  .pui-inst-name{font-size:.78rem; font-weight:700; color:#0176D3;}
  .pui-inst-role{font-size:.66rem; color:#6B7280; margin-top:1px;}
  .pui-cap-row{display:flex; align-items:center; gap:8px; margin-top:6px;}
  .pui-cap-track{flex:1; height:5px; border-radius:3px; background:#F3F3F3; overflow:hidden;}
  .pui-cap-fill{height:100%; border-radius:3px;}
  .pui-cap-fill.cap{background:#F28B24;}
  .pui-cap-fill.room{background:#2E7D32;}
  .pui-cap-label{font-size:.62rem; font-weight:700; flex:none;}
  .pui-cap-label.cap{color:#9A4B00;}
  .pui-cap-label.room{color:#2E7D32;}

  .pui-panel-label{font-family:var(--mono); font-size:.66rem; letter-spacing:.1em; text-transform:uppercase; color:var(--ink-muted); margin-bottom:14px;}

  /* ---------- hero product panel ---------- */
  .hero-panel{
    transform:rotate(.4deg);
  }
  @media (max-width:980px){ .hero-panel{transform:none;} }

  /* ---------- showcase (2-up secondary visuals) ---------- */
  .showcase-primary{margin-bottom:16px;}
  .showcase-secondary{display:grid; grid-template-columns:1fr 1fr; gap:16px;}
  @media (max-width:760px){ .showcase-secondary{grid-template-columns:minmax(0,1fr);} }
  .showcase-secondary .pui-ground{height:100%;}

  /* ---------- lifecycle ---------- */
  .lifecycle{
    display:grid; grid-template-columns:repeat(4,1fr); gap:0;
    margin:0; padding:0; list-style:none;
  }
  .lc-step{position:relative; padding:18px 22px 0 0; border-top:2px solid var(--rule);}
  .lc-step:last-child{padding-right:0;}
  .lc-step::before{content:""; position:absolute; top:-2px; right:0; width:22px; height:2px; background:var(--bg);}
  section.tint .lc-step::before{background:var(--bg-inset);}
  .lc-step:last-child::before{display:none;}
  .lc-num{font-family:var(--mono); font-size:.68rem; color:var(--accent); letter-spacing:.08em; font-weight:700;}
  .lc-title{font-family:var(--display); font-weight:700; font-size:1.15rem; margin-top:8px;}
  .lc-desc{font-size:.9rem; color:var(--ink-muted); margin-top:8px; line-height:1.55;}
  @media (max-width:860px){
    .lifecycle{grid-template-columns:1fr 1fr; gap:0 0;}
    .lc-step{padding-bottom:24px;}
    .lc-step:nth-child(2n)::before{display:none;}
  }
  @media (max-width:520px){
    .lifecycle{grid-template-columns:minmax(0,1fr);}
    .lc-step{padding-right:0; padding-bottom:20px;}
    .lc-step::before{display:none;}
  }
  .lc-branch{margin-top:24px; padding-top:18px; border-top:1px dashed var(--rule); font-size:.86rem; color:var(--ink-muted);}
  .lc-branch b{color:var(--ink);}

  /* ---------- feature groups ---------- */

  .tier-tag{display:inline-block; font-family:var(--mono); font-size:.6rem; letter-spacing:.09em; text-transform:uppercase; border:1px solid currentColor; border-radius:3px; padding:.05em .35em; margin-left:.4em; vertical-align:.08em; color:var(--accent); white-space:nowrap;}

  /* ---------- positioning / buy-vs-build callout ---------- */
  .callout{margin-top:32px; padding:28px 32px; background:var(--surface); border:1px solid var(--rule); border-radius:14px; box-shadow:var(--shadow-sm);}
  .callout p{color:var(--ink-muted); font-size:.98rem; line-height:1.7;}
  .callout p b{color:var(--ink); font-weight:600;}
  .callout p + p{margin-top:12px;}

  /* ---------- roadmap teaser ---------- */
  .roadmap-note{
    display:inline-flex; align-items:center; gap:8px; font-family:var(--mono); font-size:.66rem;
    letter-spacing:.1em; text-transform:uppercase; color:var(--warn-ink); margin-bottom:14px;
  }
  .roadmap-note::before{content:"○"; color:var(--warn-ink);}
  .roadmap-cols{display:grid; grid-template-columns:1fr 1fr; gap:36px;}
  @media (max-width:760px){.roadmap-cols{grid-template-columns:minmax(0,1fr);}}
  .roadmap-cols h3{
    font-family:var(--mono); font-size:.72rem; letter-spacing:.08em; text-transform:uppercase;
    color:var(--ink-muted); margin:0 0 14px; font-weight:700;
  }
  .roadmap-cols ul{margin:0; padding:0; list-style:none;}
  .roadmap-cols li{font-size:.92rem; color:var(--ink-muted); padding:10px 0; border-top:1px solid var(--rule);}
  .roadmap-cols li:first-child{border-top:none;}

  /* ---------- pricing ---------- */
  .price-table-wrap{
    overflow-x:auto; border:1px solid var(--rule); border-radius:14px; background:var(--surface);
    background-image:linear-gradient(to right, transparent calc(100% - 48px), color-mix(in srgb, var(--ink) 7%, transparent));
    background-repeat:no-repeat; background-attachment:local, scroll;
  }
  .price-table-wrap:focus-visible{outline:2px solid var(--accent); outline-offset:2px;}
  table.price-table{width:100%; border-collapse:collapse; min-width:720px; font-size:.92rem;}
  table.price-table caption{
    caption-side:top; text-align:left; padding:14px 18px 0;
    font-family:var(--mono); font-size:.66rem; letter-spacing:.08em; text-transform:uppercase; color:var(--ink-muted);
  }
  table.price-table th, table.price-table td{padding:14px 18px; text-align:left; border-bottom:1px solid var(--rule);}
  table.price-table thead th{
    font-family:var(--mono); font-size:.66rem; letter-spacing:.08em; text-transform:uppercase; color:var(--ink-muted);
    border-bottom:1px solid var(--ink-muted);
  }
  table.price-table tbody tr:last-child td{border-bottom:none;}
  table.price-table td.num, table.price-table th.num{font-family:var(--mono); font-variant-numeric:tabular-nums;}
  table.price-table td.tier{font-weight:700;}
  table.price-table td.zero{color:var(--ink-muted); font-family:var(--mono);}
  /* Enterprise is italic because its cells are words, not figures. It is NOT
     the featured tier, so it carries no wash: Premium is what the table
     recommends, and two highlighted blocks would recommend neither. */
  table.price-table tr.enterprise td{color:var(--ink); font-style:italic;}
  table.price-table tr.enterprise td.num:last-child{color:var(--accent); font-style:normal; font-weight:700;}
  table.price-table tr.band-alt{background:var(--bg-inset);}

  /* The three Premium bands are one featured block, not three tinted rows.
     Rules bind the group top and bottom, which is the ledger's own device and
     survives forced-colors mode, where a background wash is discarded. */
  table.price-table tr.featured th, table.price-table tr.featured td{background:var(--accent-wash);}
  table.price-table tr.featured-first th, table.price-table tr.featured-first td{border-top:2px solid var(--accent);}
  table.price-table tr.featured-last th, table.price-table tr.featured-last td{border-bottom:2px solid var(--accent);}
  table.price-table tbody tr{transition:background-color var(--t-fast) var(--ease);}
  table.price-table tbody tr:hover{background:var(--accent-wash);}

  .pricing-note{margin-top:18px; font-size:.85rem; color:var(--ink-muted); line-height:1.6;}
  .pricing-note + .pricing-note{margin-top:8px;}

  .tier-cards{margin-top:44px; display:grid; grid-template-columns:repeat(4,1fr); gap:16px;}
  @media (max-width:900px){.tier-cards{grid-template-columns:1fr 1fr;}}
  @media (max-width:560px){.tier-cards{grid-template-columns:minmax(0,1fr);}}
  .tier-card{border:1px solid var(--rule); border-radius:14px; padding:22px; background:var(--surface);}
  .tier-card.highlight{border-color:var(--accent); box-shadow:0 0 0 1px var(--accent);}
  .tier-card h3{font-family:var(--display); font-size:1.15rem; margin-bottom:4px;}
  .tier-card .tier-kicker{font-family:var(--mono); font-size:.66rem; color:var(--ink-muted); letter-spacing:.06em; text-transform:uppercase; margin-bottom:14px;}
  .tier-card ul{margin:0; padding:0; list-style:none;}
  .tier-card li{font-size:.85rem; color:var(--ink-muted); padding:6px 0; border-top:1px solid var(--rule); line-height:1.5;}
  .tier-card li:first-child{border-top:none;}
  .tier-card li a{
    display:inline-flex; align-items:center; min-height:44px;
    color:var(--accent); font-weight:600; text-decoration:none;
    transition:color var(--t-fast) var(--ease);
  }
  .tier-card li a:hover{color:var(--accent-hover); text-decoration:underline; text-underline-offset:3px;}

  /* ---------- architecture ---------- */
  .arch-grid{display:grid; grid-template-columns:repeat(2,1fr); gap:28px 40px;}
  @media (max-width:760px){.arch-grid{grid-template-columns:minmax(0,1fr);}}
  .arch-item{padding-top:18px; border-top:2px solid var(--rule);}
  .arch-item .ai-label{font-family:var(--mono); font-size:.66rem; letter-spacing:.1em; text-transform:uppercase; color:var(--accent); margin-bottom:8px; font-weight:700;}
  .arch-item p{color:var(--ink-muted); font-size:.94rem; line-height:1.6;}

  /* ---------- footer ---------- */
  footer{padding:56px 0 40px; border-top:1px solid var(--rule);}
  .footer-inner{display:flex; justify-content:space-between; align-items:flex-end; gap:24px; flex-wrap:wrap;}
  .footer-left .brand{margin-bottom:14px;}
  .footer-left p{font-size:.85rem; color:var(--ink-muted); max-width:44ch; line-height:1.6;}
  .footer-right{text-align:right;}
  @media (max-width:600px){.footer-right{text-align:left;}}
  .footer-legal{margin-top:24px; font-family:var(--mono); font-size:.68rem; color:var(--ink-muted); letter-spacing:.03em;}

  /* ============================================================
     LIVE BUDGET RAIL  (overdrive 1 of 2)

     The one part of the recreation that is genuinely interactive. Everything
     it shows is sourced: the three scenario totals and the allocation, so the
     arithmetic on screen is the product's real arithmetic, not a mock.

     Deliberately NOT repriced per bucket. Only the scenario deltas are
     sourced, not their composition, so bucket rows stay baseline and say so
     rather than inventing four numbers to look impressive.
     ============================================================ */
  .pui-scenarios{
    margin-top:16px; padding-top:14px; border-top:1px solid #E5E5E5;
    border:0; padding-inline:0; min-inline-size:0;   /* <fieldset> reset */
    border-top:1px solid #E5E5E5;
  }
  .pui-scenarios legend{
    padding:0; font-family:var(--body); font-size:.64rem; font-weight:600;
    letter-spacing:.07em; text-transform:uppercase; color:#6B7280;
  }
  .pui-scen-list{display:flex; flex-direction:column; gap:6px; margin-top:9px;}
  .pui-scen{
    display:flex; align-items:center; gap:9px; cursor:pointer;
    border:1px solid #E5E5E5; border-radius:6px; padding:9px 11px;
    font-family:var(--body); font-size:.76rem; color:#181818;
    background:#fff; min-height:44px;
    transition:border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
  }
  .pui-scen:hover{border-color:#B7C4D4; background:#FAFBFC;}
  .pui-scen input{
    appearance:none; -webkit-appearance:none; margin:0; flex:none;
    width:15px; height:15px; border-radius:50%; border:1.5px solid #9AA5B1; background:#fff;
    display:grid; place-content:center;
  }
  .pui-scen input::before{
    content:""; width:7px; height:7px; border-radius:50%; transform:scale(0);
    background:#0176D3; transition:transform var(--t-fast) var(--ease);
  }
  .pui-scen input:checked{border-color:#0176D3;}
  .pui-scen input:checked::before{transform:scale(1);}
  .pui-scen input:focus-visible{outline:2px solid #0176D3; outline-offset:2px;}
  .pui-scen:has(input:checked){border-color:#0176D3; background:#F3F8FE;}
  .pui-scen-name{flex:1; min-width:0;}
  .pui-scen-delta{font-variant-numeric:tabular-nums; font-weight:600; flex:none;}
  .pui-scen-delta.up{color:#B3261E;}
  .pui-scen-delta.down{color:#2E7D32;}
  .pui-scen-delta.base{color:#6B7280; font-weight:500;}

  /* Numbers that change need fixed-width digits or the whole rail shivers. */
  .pui-total-value, .pui-alloc-row .a-right, .pui-bucket-amt .amt, .pui-costline-amt,
  .trace-figure{font-variant-numeric:tabular-nums;}

  .pui-alloc-row .a-right.over{color:#B3261E; font-weight:600;}
  .pui-alloc-row .a-right.under{color:#2E7D32;}
  /* Over-allocation is not signalled by red alone: the bar gains a hatch and
     the text says "over". Colour-only status fails both AA and colourblind users. */
  .pui-seg-bar.over{
    background-image:repeating-linear-gradient(45deg,#B3261E 0 4px,#8C1D18 4px 8px);
  }
  .pui-seg-bar.over span{opacity:.28;}
  .pui-baseline-note{
    margin-top:9px; font-family:var(--body); font-size:.68rem; color:#6B7280;
    display:none;
  }
  .pui-budget[data-scenario]:not([data-scenario="base"]) .pui-baseline-note{display:block;}
  .pui-budget[data-scenario]:not([data-scenario="base"]) .pui-bucket-rows{opacity:.45;}
  .pui-bucket-rows{transition:opacity var(--t-med) var(--ease);}

  /* "Recreation, not a live demo." The interactivity makes this label a
     correctness requirement, not decoration: there is no product to try. */
  .demo-note{
    margin-top:10px; font-family:var(--mono); font-size:.64rem; letter-spacing:.04em;
    color:var(--ink-muted); display:flex; align-items:center; gap:7px;
  }
  .demo-note::before{
    content:""; width:6px; height:6px; border-radius:50%; background:var(--accent-line); flex:none;
  }

  /* ---------- expandable course row (overdrive 1, part b) ---------- */
  .pui-row-toggle{
    all:unset; box-sizing:border-box; display:contents; cursor:pointer;
  }
  /* 26px, not the 22px the Lightning chevron would be: WCAG 2.2 sets a 24×24
     minimum target and this is a real control, not screenshot furniture. */
  tr.pui-course-row .pui-disclose{
    all:unset; box-sizing:border-box; cursor:pointer; display:inline-flex;
    align-items:center; justify-content:center; width:26px; height:26px; border-radius:4px;
    color:#6B7280; transition:background var(--t-fast) var(--ease);
  }
  tr.pui-course-row .pui-disclose:hover{background:#EEF3F9;}
  tr.pui-course-row .pui-disclose:focus-visible{outline:2px solid #0176D3; outline-offset:1px;}
  .pui-disclose svg{width:11px; height:11px; transition:transform var(--t-med) var(--ease);}
  .pui-disclose[aria-expanded="true"] svg{transform:rotate(90deg);}
  tr.pui-costlines > td{padding:0; border:0;}
  .pui-costlines-inner{
    display:grid; grid-template-rows:0fr;
    transition:grid-template-rows var(--t-med) var(--ease);
    background:#F8F9FB;
  }
  tr.pui-costlines.open .pui-costlines-inner{grid-template-rows:1fr;}
  .pui-costlines-clip{overflow:hidden; min-height:0;}
  .pui-costlines-body{padding:12px 14px 14px;}
  .pui-cl-head{
    font-family:var(--body); font-size:.6rem; font-weight:600; letter-spacing:.07em;
    text-transform:uppercase; color:#6B7280; margin-bottom:8px;
  }
  .pui-cl{
    display:grid; grid-template-columns:minmax(0,1.4fr) minmax(0,1.2fr) minmax(0,1fr) auto;
    gap:6px 14px; padding:7px 0; border-top:1px solid #E5E5E5;
    font-family:var(--body); font-size:.72rem; color:#181818; align-items:baseline;
  }
  .pui-cl:first-of-type{border-top:0;}
  .pui-cl-basis, .pui-cl-qty{color:#6B7280;}
  .pui-costline-amt{text-align:right; font-weight:600;}
  .pui-cl-sum{
    display:flex; justify-content:space-between; gap:14px; margin-top:10px; padding-top:9px;
    border-top:1.5px solid #C9C9C9; font-family:var(--body); font-size:.74rem; font-weight:600;
  }
  .pui-cl-sum .lbl{color:#6B7280; font-weight:500;}
  @media (max-width:560px){
    .pui-cl{grid-template-columns:minmax(0,1fr) auto;}
    .pui-cl-basis, .pui-cl-qty{grid-column:1 / -1; font-size:.68rem;}
  }

  /* ============================================================
     TRACE  (overdrive 2 of 2)

     Scroll-driven, CSS-only via animation-timeline. Every figure is sourced
     and the chain reconciles: one cost line → course → bucket → plan →
     headroom. Without scroll-timeline support (or with reduced motion) all
     rungs render at full strength, which is a complete static graphic.
     ============================================================ */
  /* ============================================================
     MOTION

     One orchestrated entrance, not scattered micro-interactions. The whole
     block is gated behind prefers-reduced-motion: no-preference rather than
     relying on the global duration override — that way a reduced-motion
     visitor never has an element that starts at opacity:0 at all, so there is
     no path where content could fail to appear.
     ============================================================ */
  @keyframes hero-rise{
    from{opacity:0; transform:translate3d(0,14px,0);}
    to{opacity:1; transform:none;}
  }
  @media (prefers-reduced-motion: no-preference){
    .hero .headline,
    .hero .hero-sub,
    .hero .orient li,
    .hero .hero-actions,
    .hero-panel{
      animation:hero-rise .58s cubic-bezier(.22,1,.36,1) both;
    }
    /* Reading order, with the panel arriving early so the fold never looks
       empty while the text is still settling. */
    .hero-panel{animation-delay:.06s; animation-duration:.72s;}
    .hero .headline{animation-delay:.02s;}
    .hero .hero-sub{animation-delay:.12s;}
    .hero .orient li:nth-child(1){animation-delay:.19s;}
    .hero .orient li:nth-child(2){animation-delay:.24s;}
    .hero .orient li:nth-child(3){animation-delay:.29s;}
    .hero .hero-actions{animation-delay:.36s;}
  }

  /* State feedback, not decoration: the header earns its edge only once the
     page has actually moved under it. */
  header.site{transition:box-shadow var(--t-med) var(--ease), border-color var(--t-med) var(--ease);}
  header.site.is-scrolled{box-shadow:0 1px 0 rgba(0,0,0,.04), 0 6px 24px -12px rgba(0,0,0,.18);}

  /* The bucket segments dim when the plan goes over allocation; without this
     the hatch snaps in and reads as a rendering glitch. */
  .pui-seg-bar span{transition:opacity var(--t-med) var(--ease);}

  /* ---------- onboard: hero orientation ----------
     Answers "where does this run?" before the visitor has to ask. Marks are
     drawn with ::before rather than an icon font — nothing external loads. */
  .orient{
    list-style:none; margin:clamp(22px,3vw,30px) 0 0; padding:0;
    display:grid; gap:11px; max-width:54ch;
  }
  .orient li{
    position:relative; padding-inline-start:26px;
    font-size:.88rem; line-height:1.55; color:var(--ink-muted);
  }
  .orient li b{color:var(--ink); font-weight:600;}
  .orient li::before{
    content:""; position:absolute; inset-inline-start:0; top:.5em;
    width:9px; height:9px; border-radius:2px; background:var(--accent-line);
  }
  .orient li:nth-child(2)::before{background:var(--bucket-2);}
  .orient li:nth-child(3)::before{background:var(--bucket-3);}

  .trace-head{margin-top:clamp(44px,6vw,76px); max-width:56ch;}
  .trace-head h3{font-size:clamp(1.25rem,2.6vw,1.8rem); margin-top:8px;}
  /* Only DS 5100 actually opens. The other chevrons are screenshot detail, so
     they recede rather than promising an interaction that isn't there. */
  table.pui-table .pui-chev{opacity:.4;}
  .trace-rungs{
    margin-top:clamp(28px,4vw,44px); display:grid; gap:0;
    list-style:none; padding:0;
  }
  .trace-rung{
    --rp:clamp(18px,2.6vw,26px);          /* row padding, reused by the spine */
    display:grid; grid-template-columns:auto minmax(0,1fr);
    gap:clamp(16px,3vw,30px); padding:var(--rp) 0;
    border-top:1px solid var(--rule);
  }
  /* Above 900px the rung splits: the figure holds the left column, the
     reasoning sits beside it. Stacked, the right half was dead space and the
     rows read as a narrow ribbon against a very wide rule. */
  @media (min-width:900px){
    .trace-rung{
      grid-template-columns:auto minmax(0,7fr) minmax(0,9fr);
      align-items:start; column-gap:clamp(24px,3.4vw,52px);
    }
    /* One row here, so the mark stops spanning and the detail moves beside
       the figure rather than beneath it. Child-combinator selectors on
       purpose: the base placement rules sit later in the stylesheet, so at
       equal specificity they would otherwise win inside this media query. */
    .trace-rung > .trace-mark{grid-row:1;}
    .trace-rung > .trace-fig{grid-column:2; grid-row:1;}
    .trace-rung > .trace-detail{grid-column:3; grid-row:1;}
    .trace-basis{margin-top:0;}
    .trace-detail{padding-top:calc(0.66rem + 4px);}   /* optical: align to the figure's baseline, not its box */
  }
  .trace-rung:first-child{border-top:0;}
  .trace-mark{
    position:relative; width:12px; display:flex; justify-content:center;
    /* Must span the whole row even under align-items:start, or the spine
       halves have nothing to reach across. */
    align-self:stretch;
    grid-column:1; grid-row:1 / span 2;
  }
  /* Every child is placed explicitly. Auto-placement put the detail block in
     the 12px mark column, which inflated the `auto` track to 334px and pushed
     the page 92px wide on mobile. Three children never auto-place safely into
     a two-column template. */
  .trace-fig{grid-column:2; grid-row:1; min-width:0;}
  .trace-detail{grid-column:2; grid-row:2; min-width:0;}
  .trace-dot{
    width:12px; height:12px; border-radius:50%; margin-top:8px; flex:none;
    background:var(--rung-color,var(--accent-line));
    box-shadow:0 0 0 0 var(--rung-color,var(--accent-line));
  }
  /* The spine is drawn per-rung, in two halves, so it never depends on sibling
     heights: each rung runs a line from its dot down through its own bottom
     padding, and every rung after the first runs one up through its top
     padding to meet the previous one. Offsetting by --rp is what makes the
     two halves actually touch across the row border. */
  .trace-mark::after, .trace-mark::before{
    content:""; position:absolute; width:2px; left:50%; margin-left:-1px;
    background:var(--rung-color,var(--accent-line)); opacity:.32;
  }
  .trace-rung:not(:last-child) .trace-mark::after{
    top:22px; bottom:calc(-1 * var(--rp));
  }
  .trace-rung:not(:first-child) .trace-mark::before{
    top:calc(-1 * var(--rp) - 1px); height:calc(var(--rp) + 9px);
  }
  .trace-dot{position:relative; z-index:1;}
  .trace-figure{
    font-size:clamp(1.5rem,4.2vw,2.5rem); font-weight:700; letter-spacing:-.02em;
    line-height:1.05; color:var(--ink);
  }
  .trace-label{
    font-family:var(--mono); font-size:.66rem; letter-spacing:.12em; text-transform:uppercase;
    color:var(--ink-muted); margin-bottom:7px;
  }
  .trace-basis{
    margin-top:7px; font-size:.88rem; color:var(--ink-muted); max-width:52ch; line-height:1.6;
  }
  .trace-op{
    font-family:var(--mono); font-size:.7rem; letter-spacing:.06em; color:var(--accent);
    margin-top:9px;
  }
  @supports (animation-timeline: view()){
    @media (prefers-reduced-motion: no-preference){
      .trace-rung{
        animation:rung-in linear both;
        animation-timeline:view();
        animation-range:entry 5% cover 34%;
      }
      .trace-dot{
        animation:dot-in linear both;
        animation-timeline:view();
        animation-range:entry 5% cover 34%;
      }
    }
  }
  @keyframes rung-in{
    from{opacity:.32; transform:translateY(10px);}
    to{opacity:1; transform:none;}
  }
  @keyframes dot-in{
    from{box-shadow:0 0 0 0 var(--rung-color,var(--accent-line)); transform:scale(.7);}
    to{box-shadow:0 0 0 6px color-mix(in oklch, var(--rung-color,var(--accent-line)) 18%, transparent); transform:none;}
  }

  /* ---------- adapt: touch + coarse pointers ----------
     Hover affordances are meaningless on touch; targets grow instead. */
  @media (pointer:coarse){
    .pui-scen{min-height:48px;}
    tr.pui-course-row .pui-disclose{width:44px; height:44px;}
  }

  /* ---------- harden: forced colors / Windows high contrast ---------- */
  @media (forced-colors: active){
    .pui-frame, .pui-card, .pui-scen{border:1px solid CanvasText;}
    .pui-scen input:checked{outline:2px solid Highlight;}
    .pui-seg-bar span{forced-color-adjust:none;}
    .trace-dot{border:2px solid CanvasText;}
    .pui-disclose[aria-expanded="true"] svg{forced-color-adjust:none;}
  }

  /* ---------- print ----------
     Budget offices circulate this page as a PDF. Print the argument, not the
     chrome: force the light palette, drop the sticky header, and let the
     pricing table print whole instead of clipped to its scroll box. */
  @media print{
    :root{
      --bg:#fff; --bg-inset:#fff; --surface:#fff;
      --ink:#000; --ink-muted:#333; --rule:#999;
      --accent:#1247A0; --accent-line:#1247A0; --warn-ink:#000;
      --warn-wash:transparent; --accent-wash:transparent; --shadow:none; --shadow-sm:none;
      color-scheme:light;
    }
    header.site, .skip-link, .theme-toggle, .hero-panel, .showcase-primary, .showcase-secondary{display:none !important;}
    body{background:#fff; font-size:11pt;}
    section{padding:22px 0; break-inside:avoid;}
    .wrap{max-width:none; padding:0;}
    .price-table-wrap{overflow:visible; background-image:none;}
    table.price-table{min-width:0;}
    .spec-row, .traced, .tier-card, .arch-item{break-inside:avoid;}
    .hero{padding:12px 0 24px;}
    .hero-actions{display:none;}
    footer .btn{border:none; padding:0; min-height:0; font-weight:600; background:none; color:#000;}

    /* The orientation list is the answer to the first question a procurement
       reader asks, so it prints even though the hero panel doesn't. */
    .orient li{color:#000; break-inside:avoid;}
    .orient li::before{background:#000 !important;}

    /* The trace is the argument in miniature — print it whole, one rung per
       block, with the derivations spelled out rather than hidden. */
    .trace-rungs{margin-top:16px;}
    .trace-rung{break-inside:avoid; padding:10px 0; opacity:1 !important; transform:none !important; animation:none !important;}
    .trace-figure{font-size:15pt;}
    .trace-op{color:#000;}
    .trace-mark{display:none;}
    .trace-rung{grid-template-columns:minmax(0,1fr);}

    /* A printed page has no disclosure affordance, so the cost lines that
       prove the course total print expanded rather than collapsed. */
    .pui-scenarios, .demo-note, .pui-disclose{display:none !important;}
    tr.pui-costlines{display:table-row !important;}
    .pui-costlines-inner{grid-template-rows:1fr !important;}
    .pui-costlines-clip{overflow:visible !important;}

    /* Links in body copy are useless on paper unless the target is shown. */
    .trace-basis a[href^="http"]::after{content:" (" attr(href) ")"; font-size:9pt; color:#333;}
  }

  /* ============================================================
     LEDGER LAYER

     Appended last so it wins on source order. This is what turns the
     token swap into an actual ledger rather than a warm-tinted version
     of the previous shell:

       · rules replace cards as the structural device
       · every figure is tabular and slashed-zero, so columns align and
         a zero can never be read as an O in a money column
       · mono carries figures and labels; the grotesque carries prose
       · shadows and radii are removed from shell components (the product
         UI recreations keep theirs — they are a screenshot of Lightning,
         which does have them)
     ============================================================ */

  /* Figures. `slashed-zero` is not decoration here: these are money columns. */
  .trace-figure, .tc-value, .pui-total-value, .num, .price, .price-note b,
  .stat, .trace-op, .pui-costline-amt, .pui-bucket-amt .amt{
    font-variant-numeric: tabular-nums slashed-zero;
  }

  /* Labels and figures speak mono; prose stays grotesque. */
  .eyebrow, .trace-label, .ai-label, .pui-panel-label, .traced-label,
  .tc-label, .footer-legal, .brand-sub, .nav-links a, .tier-name{
    font-family:var(--mono);
    letter-spacing:.10em; text-transform:uppercase; font-size:.66rem;
  }
  .trace-figure, .tc-value{font-family:var(--mono); letter-spacing:-.02em;}

  /* De-card. A ledger has no floating panels: it has ruled bands. */
  .traced-card, .tier-card, .arch-item, .callout, .traced{
    border-radius:0 !important;
    box-shadow:none !important;
    background:transparent !important;
  }
  /* NOTE: an orphaned declaration block sat here (border:0; border-top:1px
     solid var(--rule-firm); padding:22px 0 0;) with no selector, plus the
     stray closing brace that followed it. CSS error recovery discarded both
     silently, so it never rendered: .arch-item takes 2px/18px from its rule
     above, not the 1px/22px this wanted. Removed to make the sheet parse
     cleanly. Restoring the intent is a deliberate visual change, not a fix. */
  .tier-card{border:0; border-top:2px solid var(--ink); padding:20px 0 0;}
  .callout{border:0; border-top:1px solid var(--rule-firm); border-bottom:1px solid var(--rule-firm); padding:24px 0;}
  .traced-card{border:0; border-top:1px solid var(--rule); padding:16px 0 0;}

  /* Section rhythm: a firm rule opens each section, hairlines divide within. */
  main > section{border-top:1px solid var(--rule); padding:clamp(52px,7vw,88px) 0;}
  main > section:first-child{border-top:0;}
  hr.divider{display:none;}

  /* Headline: grotesque, tight, and not enormous. In a ledger the figures are
     the largest thing on the page, not the prose. */
  h1.headline{
    font-size:clamp(2rem, 3.5vw, 2.9rem); line-height:1.08;
    letter-spacing:-.02em; max-width:17ch; font-weight:650;
  }
  h2{font-size:clamp(1.35rem,2.3vw,1.9rem); letter-spacing:-.015em; font-weight:640;}
  h3{font-size:1.02rem; letter-spacing:-.005em; font-weight:640;}

  /* Buttons: ink-filled, square. No gradient, no radius, no lift. */
  .btn, .nav-links .cta{
    border-radius:2px; box-shadow:none;
    font-family:var(--mono); font-size:.7rem; letter-spacing:.08em; text-transform:uppercase;
  }
  .btn-primary, .nav-links .cta{background:var(--accent-solid); color:var(--on-accent); border:1px solid var(--accent-solid);}
  .btn-primary:hover, .nav-links .cta:hover{background:var(--accent-hover); border-color:var(--accent-hover);}
  .btn-ghost{border:1px solid var(--rule-firm); color:var(--ink); background:transparent;}
  .btn-ghost:hover{border-color:var(--ink); background:transparent;}

  /* Nav: the current page is marked with a rule under it, not a colour swap,
     so it survives forced-colors and reads in both themes. */
  .nav-links a{color:var(--ink-muted); text-decoration:none; padding-bottom:2px;}
  .nav-links a:hover{color:var(--ink);}
  .nav-links a.is-current{
    color:var(--ink); border-bottom:2px solid var(--ink);
  }
  .nav-links a.cta{border-bottom:0;}

  /* Header: a ruled edge, never a shadow. */
  header.site{border-bottom:1px solid var(--rule-firm); background:var(--bg);}
  header.site.is-scrolled{box-shadow:none; border-bottom-color:var(--ink);}

  /* Over-allocation is the one place red is allowed. */
  .pui-alloc-row .a-right.over{color:var(--negative) !important;}

  /* ---------- 404 ---------- */
  .not-found{min-height:56vh;}
  .nf-links{list-style:none; margin:clamp(28px,4vw,44px) 0 0; padding:0; max-width:62ch;}
  .nf-links li{
    display:grid; grid-template-columns:minmax(0,10rem) minmax(0,1fr); gap:8px 24px;
    padding:14px 0; border-top:1px solid var(--rule); align-items:baseline;
  }
  .nf-links a{
    font-family:var(--mono); font-size:.72rem; letter-spacing:.09em; text-transform:uppercase;
    color:var(--ink); text-decoration:none; border-bottom:1px solid var(--accent-line);
  }
  .nf-links a:hover{border-bottom-color:var(--ink);}
  .nf-links span{color:var(--ink-muted); font-size:.88rem;}
  @media (max-width:560px){ .nf-links li{grid-template-columns:minmax(0,1fr);} }

  /* ---------- header at narrow widths ----------
     The mono, letter-spaced, uppercase nav is wider than its sans predecessor
     and stopped fitting beside the brand and CTA at 390px. It wraps to a
     second ruled row rather than collapsing into a hamburger: three links do
     not justify hiding navigation behind a menu. */
  @media (max-width:760px){
    .nav{flex-wrap:wrap; row-gap:0;}
    .brand{flex:1 1 auto; min-width:0;}
    .nav-links{
      order:3; width:100%; justify-content:flex-start; gap:18px;
      margin-top:12px; padding-top:12px; border-top:1px solid var(--rule);
      flex-wrap:wrap;
    }
    .nav-links .cta{margin-inline-start:auto;}
    .theme-toggle{order:2;}
  }

  /* ---------- page masthead ----------
     Every page needs exactly one h1. Splitting the single page left /product
     and /pricing with none, because the only h1 was the home hero. */
  .page-head{padding:clamp(38px,5vw,64px) 0 clamp(26px,3.5vw,40px) !important; border-top:0 !important;}
  .page-head .headline{max-width:20ch; margin-top:10px;}
  .page-head .lede{margin-top:16px; max-width:56ch; color:var(--ink-muted); font-size:1.02rem; line-height:1.6;}

  /* ============================================================
     SPECIFICATION TABLE

     Replaces a 2x3 grid of cards. That grid forced six blocks of very
     different length into equal cells, so three of them ended in large
     dead space, and the tier badges floated mid-sentence where they
     could not be compared. This content is a table: capability,
     what it does, which tier. So it is one now.
     ============================================================ */
  .spec{margin-top:clamp(28px,3.6vw,44px);}
  .spec-group{
    display:flex; align-items:baseline; gap:14px;
    font-family:var(--mono); font-size:.68rem; letter-spacing:.12em; text-transform:uppercase;
    color:var(--ink); font-weight:600;
    padding:0 0 10px; margin:clamp(34px,4vw,52px) 0 0;
    border-bottom:1.5px solid var(--ink);
  }
  .spec-group:first-child{margin-top:0;}
  .spec-num{color:var(--ink-muted); font-weight:400; flex:none;}

  .spec-rows{margin:0; padding:0;}
  .spec-row{
    display:grid;
    grid-template-columns:minmax(0,15rem) minmax(0,1fr) minmax(4.5rem,auto);
    gap:6px 26px; align-items:baseline;
    padding:14px 0; border-bottom:1px solid var(--rule);
    transition:background var(--t-fast) var(--ease);
  }
  /* A ruled row highlights on hover the way a ledger line does when you run a
     finger down it: the tint bleeds into the gutter so the whole line reads as
     one unit rather than three cells. */
  .spec-row:hover{background:var(--bg-inset); box-shadow:0 0 0 12px var(--bg-inset);}
  .spec-row dt{
    font-weight:600; color:var(--ink); font-size:.92rem; line-height:1.45;
    text-wrap:balance;
  }
  .spec-row dd{margin:0;}
  .spec-desc{color:var(--ink-muted); font-size:.9rem; line-height:1.55; max-width:62ch;}
  .spec-tier{
    justify-self:end; align-self:baseline;
    font-family:var(--mono); font-size:.6rem; letter-spacing:.09em; text-transform:uppercase;
    white-space:nowrap;
  }
  .spec-tier span{
    border:1px solid var(--accent-line); color:var(--accent);
    padding:.15em .45em; border-radius:2px; display:inline-block;
  }

  @media (max-width:820px){
    .spec-row{
      grid-template-columns:minmax(0,1fr) auto;
      gap:4px 16px;
    }
    .spec-row dt{grid-column:1;}
    .spec-tier{grid-column:2; grid-row:1;}
    .spec-desc{grid-column:1 / -1;}
    .spec-row:hover{box-shadow:0 0 0 8px var(--bg-inset);}
  }

  /* ============================================================
     CROSS-DOCUMENT VIEW TRANSITIONS

     The site became three documents; without this, every nav click is a
     white flash and a scroll reset. `navigation: auto` makes the browser
     crossfade between documents with no JavaScript at all, and browsers
     without support simply navigate normally.

     Named elements persist rather than crossfade, so the header and the
     rule beneath it hold still while the page body changes — which is
     what makes it read as one continuous document.
     ============================================================ */
  @media (prefers-reduced-motion: no-preference){
    @view-transition{ navigation: auto; }

    ::view-transition-old(root),
    ::view-transition-new(root){
      animation-duration:240ms;
      animation-timing-function:cubic-bezier(.22,1,.36,1);
    }
    header.site{view-transition-name:site-header;}
    footer{view-transition-name:site-footer;}
  }

  /* ---------- spec rows rule themselves in on scroll ---------- */
  @supports (animation-timeline: view()){
    @media (prefers-reduced-motion: no-preference){
      .spec-row{
        animation:spec-in linear both;
        animation-timeline:view();
        animation-range:entry 0% cover 18%;
      }
    }
  }
  @keyframes spec-in{
    from{opacity:.25; transform:translate3d(0,6px,0);}
    to{opacity:1; transform:none;}
  }

  /* A figure mid-tally is not a final figure; dim it very slightly so a
     reader doesn't quote a number that is still counting. */
  .trace-figure[data-counting="true"]{opacity:.78;}

  /* ---------- side-by-side comparison ----------
     Not the specification table: this is two opposing columns, them and us,
     and the reader is meant to scan across rather than down. A single vertical
     rule does the separating; the columns carry no background of their own. */
  .compare{
    display:grid; grid-template-columns:1fr 1fr; gap:0 clamp(28px,4vw,56px);
    margin-top:clamp(26px,3.4vw,40px);
  }
  .compare-col{padding-top:16px; border-top:1.5px solid var(--ink);}
  .compare-us{border-top-color:var(--bucket-1);}
  .compare-col h3{
    font-family:var(--mono); font-size:.66rem; letter-spacing:.11em; text-transform:uppercase;
    font-weight:600; color:var(--ink); margin-bottom:6px;
  }
  .compare-col ul{list-style:none; margin:0; padding:0;}
  .compare-col li{
    font-size:.9rem; line-height:1.55; color:var(--ink-muted);
    padding:11px 0; border-top:1px solid var(--rule);
  }
  .compare-col li b{color:var(--ink); font-weight:600;}
  .compare-us li b{color:var(--accent);}
  @media (max-width:760px){
    .compare{grid-template-columns:minmax(0,1fr); gap:clamp(24px,4vw,34px) 0;}
  }

  /* ============================================================
     LOCKUP

     The press kit's mark, applied as given: four uprights melting into
     the four rules beneath, drips falling left to right. Geometry is
     lifted verbatim from press-kit/svg/planfoundry-lockup-on-light.svg
     into src/lockup.svg — do not re-derive it here.

     Two things about that file decide everything below.

     The wordmark is outlined path data rather than <text>. The press kit
     sets it in Manrope and points the SVGs at the font by name, but
     PRODUCT.md principle 6 forbids external fonts, so live text would
     have silently fallen back to Helvetica on every visit. As geometry
     it is exact, needs no font, and takes fill:currentColor — which is
     the whole reason the mark inverts with --ink in dark theme.

     The bar colours are hard-coded hexes, not var(--bucket-N). The press
     kit's first rule is that the four lines never recolour, including
     between themes; hard-coding is what enforces that. They are the same
     four values --bucket-1..4 carry, so the logo still visibly quotes the
     product's own budget rail.

     Size is driven by one property. Everything in the SVG scales from the
     viewBox, so the lockup is sized by width alone and the 297:65 ratio
     does the rest.
     ============================================================ */
  .brand{display:flex; align-items:center; gap:14px; text-decoration:none; min-height:44px;}
  .pf-lockup{
    display:block; width:164px; height:auto; flex:none;
    color:var(--ink);            /* the wordmark's currentColor */
    overflow:visible;            /* the falling drop leaves the viewBox */
  }
  .pf-lockup .pf-word{transition:fill var(--t-fast) var(--ease);}

  /* The drop rests inside the upright until it is animated out, so a
     visitor with reduced motion, or with the animation already finished,
     never sees a stray dot hanging under the mark. */
  .pf-drop{opacity:0;}

  /* ---- The melt, once per page view ----
     The press kit's CSS embed loops this at 3.4s forever. In a fixed
     header a permanent loop is both a distraction and a WCAG 2.2.2
     problem (moving content over five seconds must be pausable), so it
     runs a single pass on load instead and settles. The sequence and the
     .18s left-to-right stagger are the press kit's.

     Only the header instance animates. The press kit asks for one
     animated lockup per view; the footer's is the static one. */
  @media (prefers-reduced-motion: no-preference){
    .brand-lead .pf-drip{
      transform-box:fill-box; transform-origin:top center;
      animation:pf-drip 1.5s var(--ease) both;
      animation-delay:calc(var(--i) * .18s);
    }
    .brand-lead .pf-drop{
      transform-box:fill-box; transform-origin:center;
      animation:pf-fall 1.5s cubic-bezier(.55,0,.85,.4) both;
      animation-delay:calc(var(--i) * .18s);
    }
    .brand-lead .pf-bar{
      transform-box:fill-box; transform-origin:left center;
      animation:pf-bar 1.5s var(--ease) both;
      animation-delay:calc(var(--i) * .18s);
    }
  }
  /* Stretch, then snap back as the drop detaches. */
  @keyframes pf-drip{
    0%,18%  {transform:scaleY(1);}
    46%     {transform:scaleY(2.4);}
    62%,100%{transform:scaleY(1);}
  }
  /* cy is 44.5 and the rules start at 56, so 11.5 lands the drop exactly
     on the bar rather than near it. */
  @keyframes pf-fall{
    0%,44%  {opacity:0; transform:translateY(0) scale(.7);}
    52%     {opacity:1; transform:translateY(2px) scaleY(1.3) scaleX(.9);}
    76%     {opacity:1; transform:translateY(11.5px) scaleY(1.4) scaleX(.9);}
    88%,100%{opacity:0; transform:translateY(13px) scaleY(.3) scaleX(1.9);}
  }
  /* Each rule draws itself in as its own drop lands, so the mark reads as
     the bars being poured rather than as four things animating at once. */
  @keyframes pf-bar{
    0%,70%  {transform:scaleX(0);}
    100%    {transform:scaleX(1);}
  }

  .brand-sub{
    color:var(--ink-muted); white-space:nowrap;
    font-size:.6rem !important; letter-spacing:.11em;
  }
  @media (max-width:900px){ .brand-sub{display:none;} }

  /* Hover firms the ink. The bars are brand-fixed and stay put. */
  .brand:hover .pf-word{fill:var(--accent);}
  .brand:focus-visible{outline:2px solid var(--accent); outline-offset:4px;}

  /* ---------- FAQ ----------
     A definition list, ruled like everything else. Rendered from the same
     source as the FAQPage structured data, so what a search engine indexes
     and what a reader sees cannot drift apart. */
  .faq{margin:clamp(26px,3.4vw,40px) 0 0; padding:0;}
  .faq-row{
    display:grid; grid-template-columns:minmax(0,20rem) minmax(0,1fr);
    gap:8px 32px; padding:18px 0; border-top:1px solid var(--rule);
    align-items:baseline;
  }
  .faq-row:last-child{border-bottom:1px solid var(--rule);}
  .faq-row dt{font-weight:600; color:var(--ink); font-size:.95rem; line-height:1.45; text-wrap:balance;}
  .faq-row dd{margin:0; color:var(--ink-muted); font-size:.9rem; line-height:1.6; max-width:66ch;}
  @media (max-width:820px){
    .faq-row{grid-template-columns:minmax(0,1fr); gap:6px;}
  }

  /* ============================================================
     RECONCILING DEMO

     Lives inside the Lightning recreation, so it borrows that
     screenshot's fixed palette rather than the shell's theme tokens —
     a control that changed colour with the marketing site's dark mode
     would break the illusion that this is a product screen.
     ============================================================ */
  .pui-cl-edit{display:inline-flex; align-items:baseline; gap:6px;}
  .qty-input{
    width:5.2rem; font:inherit; font-family:var(--mono);
    font-variant-numeric:tabular-nums; font-size:.74rem;
    color:#181818; background:#fff;
    border:1px solid #C9C9C9; border-radius:3px;
    padding:5px 7px; text-align:right; min-height:32px;
    transition:border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
  }
  .qty-input:hover{border-color:#8FA5C0;}
  .qty-input:focus{outline:none; border-color:#0176D3; box-shadow:0 0 0 3px rgba(1,118,211,.18);}
  .qty-input:focus-visible{outline:2px solid #0176D3; outline-offset:1px;}
  .qty-unit{font-family:var(--mono); font-size:.64rem; color:#6B7280; letter-spacing:.04em;}
  /* An edited line is marked structurally, not by colour alone. */
  .pui-cl.is-changed{background:#F3F8FE;}
  .pui-cl.is-changed .pui-costline-amt{font-weight:700;}
  .pui-cl.is-changed .pui-cl-who::before{
    content:"›"; color:#0176D3; font-weight:700; margin-inline-end:5px;
  }

  .reconcile{
    margin-top:16px; padding-top:14px; border-top:1.5px solid #C9C9C9;
    font-family:var(--body);
  }
  .rec-head{display:flex; align-items:baseline; gap:12px; margin-bottom:10px;}
  .rec-title{
    font-size:.6rem; font-weight:600; letter-spacing:.1em; text-transform:uppercase; color:#6B7280;
  }
  .rec-reset{
    margin-inline-start:auto; font-family:var(--mono); font-size:.6rem; letter-spacing:.07em;
    text-transform:uppercase; color:#0176D3; background:none; border:1px solid #0176D3;
    border-radius:3px; padding:5px 9px; min-height:32px; cursor:pointer;
  }
  .rec-reset:hover{background:#F3F8FE;}
  .rec-reset:focus-visible{outline:2px solid #0176D3; outline-offset:2px;}

  .rec-ladder{list-style:none; margin:0; padding:0;}
  .rec-step{
    display:grid; grid-template-columns:minmax(0,1fr) auto minmax(4.5rem,auto);
    gap:4px 14px; align-items:baseline;
    padding:7px 0; border-top:1px solid #EDEDED;
  }
  .rec-step:first-child{border-top:0;}
  /* Each rung sits one notch further right, so the eye reads the chain as
     climbing from a single line up to the whole plan. */
  .rec-step:nth-child(2){padding-inline-start:10px;}
  .rec-step:nth-child(3){padding-inline-start:20px;}
  .rec-step:nth-child(4){padding-inline-start:30px;}
  .rec-step:nth-child(5){padding-inline-start:40px;}
  .rec-k{font-size:.72rem; color:#6B7280;}
  .rec-v{
    font-family:var(--mono); font-variant-numeric:tabular-nums slashed-zero;
    font-size:.8rem; font-weight:600; color:#181818; text-align:right;
  }
  .rec-d{
    font-family:var(--mono); font-variant-numeric:tabular-nums; font-size:.66rem;
    text-align:right; color:transparent;
  }
  .rec-d.up{color:#B3261E;}
  .rec-d.down{color:#2E7D32;}
  .rec-step:last-child .rec-v{font-size:.86rem;}
  .rec-step.is-over .rec-v{color:#B3261E;}
  .rec-step.is-over .rec-k::after{content:" — over allocation"; color:#B3261E;}

  @media (max-width:640px){
    .rec-step{grid-template-columns:minmax(0,1fr) auto; }
    .rec-d{grid-column:2; grid-row:2; }
    .rec-step:nth-child(n){padding-inline-start:0;}
    .qty-input{width:4.6rem;}
  }
  /* A figure that has moved away from the plan of record says so, in the
     same blue the edited line uses, so the eye can follow the change up
     out of the drawer into the table above it. */
  .is-changed-num{color:#0176D3 !important; font-weight:700;}

  /* ============================================================
     FIT NORMALIZATION

     Appended last, additive only: no rule above is edited or removed,
     these just win on source order. Each block fixes a measured
     inconsistency, not a suspected one.
     ============================================================ */

  /* 1. The eyebrow was rendering at two sizes depending on its container.
        Eyebrows are <p>, so `.section-head p {font-size:1.03rem}` (0,1,1)
        outranked `.eyebrow` (0,1,0) and inflated every eyebrow inside a
        section head to 16.48px against 10.56px elsewhere — the same
        component, two sizes, invisible in the markup. */
  :root{
    --label-size: .66rem;
    --label-track: .11em;
    --label-col: 18rem;    /* shared gutter for ruled label/value grids */
    --measure: 64ch;       /* one canonical prose measure */
  }
  .section-head p.eyebrow{
    font-size:var(--label-size);
    line-height:1.4;
    margin-top:0;
  }

  /* 2. One label system. Size and tracking are shared; weight alone carries
        rank, so a section marker and a group heading read as the same family
        at different volumes rather than as two unrelated treatments.
        The Lightning recreation's own labels (.pui-cl-head, .rec-title) are
        deliberately excluded — they belong to the product screenshot's type
        system, not the shell's. */
  .eyebrow,
  .pui-panel-label,
  .traced-label,
  .trace-label,
  .ai-label,
  .spec-group{
    font-size:var(--label-size);
    letter-spacing:var(--label-track);
  }
  .eyebrow, .pui-panel-label, .traced-label, .trace-label{font-weight:500;}
  .ai-label, .spec-group{font-weight:600;}

  /* 3. Ruled label/value grids now share one gutter. The specification table
        and the FAQ sit on the same page as the same pattern and were running
        240px against 320px, so their value columns started in different
        places and the page had two left margins for one idea. */
  .spec-row{grid-template-columns:minmax(0,var(--label-col)) minmax(0,1fr) minmax(4.5rem,auto);}
  .faq-row{grid-template-columns:minmax(0,var(--label-col)) minmax(0,1fr);}
  @media (max-width:820px){
    .spec-row{grid-template-columns:minmax(0,1fr) auto;}
    .faq-row{grid-template-columns:minmax(0,1fr);}
  }

  /* 4. Prose was running at three near-identical measures (562 / 576 / 599px).
        Three values that close read as drift rather than intent. */
  .spec-desc, .faq-row dd, .trace-basis{max-width:var(--measure);}

  /* 5. Same failure mode as the eyebrow, one layer down: `.arch-item .ai-label`
        (0,2,0) outranked the component rule (0,1,0), so architecture labels
        kept their own tracking and a 700 weight while every other label in the
        family moved to the shared system. Matched specificity, later in source. */
  .arch-item .ai-label{
    font-size:var(--label-size);
    letter-spacing:var(--label-track);
    font-weight:600;
  }

  /* ===========================================================================
     BUTTONS: the product's action language
     ---------------------------------------------------------------------------
     Owner call, 2026-07-28. The ledger layer above styles buttons square,
     uppercase, mono and ink-filled, which reads as a printed form rather than
     as the software. These CTAs should carry the same action language as the
     real product (refs/PRODUCT-UI-SPEC.md §3: title-case grotesque, blue fill,
     white text; the neutral variant is a bordered button with blue text).

     Four axes separate the two, and roundness was the smallest of them:
       radius   2px          -> 10px
       family   mono         -> grotesque
       case     UPPERCASE    -> Title case, no tracking
       fill     ink          -> the product's blue

     Radius is 10px, not the product's literal 4px. These buttons stand ~48px
     tall against the product's 32px, so 4px reads as square at this scale;
     10px reproduces the optical roundness the product has at its own size.

     The blue is the EXISTING --accent hue (bucket-1), not a new colour: the
     token block states the palette gains no fifth hue for links and buttons.
     Appended rather than edited so nothing above is disturbed, and because
     source order is what actually decides this cascade.
     =========================================================================== */

  :root{
    --cta-fill:       oklch(44% 0.15 258);
    --cta-fill-hover: oklch(37% 0.15 258);
    --cta-on:         oklch(98%  0.006 85);
    --cta-line:       oklch(62%  0.012 70);  /* 3.40:1 on paper (WCAG 1.4.11 needs 3.0) */
  }
  :root[data-theme="dark"]{
    --cta-fill:       oklch(76% 0.12 250);
    --cta-fill-hover: oklch(84% 0.12 250);
    --cta-on:         oklch(15.5% 0.010 60);
    --cta-line:       oklch(52% 0.014 62);  /* 3.54:1 on ink */
  }

  .btn, .nav-links .cta{
    border-radius:10px;
    font-family:var(--body);
    font-weight:600;
    letter-spacing:0;
    text-transform:none;
  }
  /* Font size only on .btn. A media query at line 220 sizes .nav-links .cta at
     narrow widths with identical specificity, so setting it here would win
     there too and break the compact header. */
  .btn{font-size:.95rem;}
  .nav-links .cta{border-radius:8px;}

  /* The global :focus-visible rule carries border-radius:2px, which would snap
     a rounded button square exactly while it is focused. Higher specificity
     restores the real shape without touching that rule. */
  .btn:focus-visible, .nav-links .cta:focus-visible{border-radius:10px;}
  .nav-links .cta:focus-visible{border-radius:8px;}

  .btn-primary, .nav-links .cta{
    background:var(--cta-fill);
    border:1px solid var(--cta-fill);
    color:var(--cta-on);
  }
  .btn-primary:hover, .nav-links .cta:hover{
    background:var(--cta-fill-hover);
    border-color:var(--cta-fill-hover);
  }

  /* Mirrors .pui-btn.neutral: bordered, transparent, blue label. */
  .btn-ghost{
    background:transparent;
    border:1px solid var(--cta-line);
    color:var(--cta-fill);
  }
  .btn-ghost:hover{
    border-color:var(--cta-fill);
    color:var(--cta-fill);
    background:var(--accent-wash);
  }

  /* ===========================================================================
     THE MODEL MAP  (/ overview)
     ---------------------------------------------------------------------------
     A concept-level map of the data, adapted from the internal ERD. It shows
     WHAT the records are and what they touch, never how they are built: no API
     names, no field lists, no counts, no relationship types.

     Colour: the token block above states the palette gains no fifth hue, and
     seven coloured bands would have broken that outright. So the bands are
     numbered the way .spec-group already numbers its groups, stay hairline
     neutral, and the one colour spent is bucket-1 on the plan band — the same
     "four objects carry the whole idea" emphasis the copy makes.

     Appended, not edited. Nothing above this line is touched.
     =========================================================================== */

  /* The tagline is ~40% longer than the one this breakpoint was set for, and it
     is white-space:nowrap, so it now collides with the nav before 900px. */
  @media (max-width:1060px){ .brand-sub{display:none;} }

  /* ---------- filters ---------- */
  .mdl-controls{
    display:flex; flex-wrap:wrap; gap:8px; align-items:center;
    margin:-24px 0 30px;
  }
  .mdl-fbtn{
    font-family:var(--mono); font-size:var(--label-size); letter-spacing:var(--label-track);
    text-transform:uppercase; font-weight:500;
    background:transparent; border:1px solid var(--rule-firm); color:var(--ink-muted);
    border-radius:2px; padding:8px 13px; min-height:34px; cursor:pointer;
    transition:color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
               background var(--t-fast) var(--ease);
  }
  .mdl-fbtn:hover{color:var(--accent); border-color:var(--accent);}
  .mdl-fbtn[aria-pressed="true"]{
    background:var(--ink); border-color:var(--ink); color:var(--bg);
  }

  /* ---------- canvas and connector layer ---------- */
  .mdl-canvas{position:relative;}
  .mdl-wires{
    position:absolute; inset:0; width:100%; height:100%;
    pointer-events:none; overflow:visible; z-index:0;
  }
  .mdl-wires path{
    fill:none; stroke:var(--rule-firm); stroke-width:1.2; opacity:.5;
    transition:opacity var(--t-fast) var(--ease), stroke var(--t-fast) var(--ease),
               stroke-width var(--t-fast) var(--ease);
  }
  /* While tracing, the wires rise above the bands. An edge is anchored on the
     two boxes it joins, so the only boxes it can cross are the ones in between
     — which are exactly the dimmed ones the reader is not looking at. */
  .mdl-canvas.is-tracing .mdl-wires{z-index:2;}
  .mdl-canvas.is-tracing .mdl-wires path{opacity:.08;}
  /* Both of these must out-specify the dimming rule directly above, which is
     (0,3,1). Written as `.mdl-wires path.on` they would be (0,2,1), lose the
     cascade, and render at 8% while the script insisted they were lit. */
  .mdl-canvas.is-tracing .mdl-wires path.on{
    opacity:1; stroke:var(--accent); stroke-width:2.2;
  }

  /* ---------- bands ---------- */
  .mdl-band{position:relative; z-index:1; margin-bottom:38px;}
  .mdl-band:last-child{margin-bottom:0;}
  .mdl-band.is-hidden{display:none;}
  /* Opaque for the same reason the cards are: everything in the band layer
     occludes the connector layer, so a wire reads as passing behind the page
     rather than being drawn on top of the words. */
  .mdl-band-h{
    display:grid; grid-template-columns:auto minmax(0,1fr); gap:0 18px; align-items:baseline;
    border-bottom:1px solid var(--rule-firm); padding-bottom:12px; margin-bottom:18px;
    background:var(--bg);
  }
  .mdl-num{
    font-family:var(--mono); font-size:var(--label-size); letter-spacing:var(--label-track);
    color:var(--ink-muted); font-weight:500; grid-row:1 / span 2;
  }
  .mdl-band-h h3{font-size:1.05rem; font-weight:650; letter-spacing:-.01em; line-height:1.3;}
  .mdl-band-h p{
    grid-column:2; margin-top:7px; max-width:var(--measure);
    color:var(--ink-muted); font-size:.9rem; line-height:1.6;
  }

  .mdl-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(228px,1fr)); gap:12px;}

  /* ---------- concept cards ---------- */
  /* A button's children are inline by default, which ran the concept name and
     its description together on one line. The column flex is what separates
     them. */
  .mdl-node{
    display:flex; flex-direction:column; align-items:stretch; gap:6px;
    text-align:left; width:100%; font:inherit; color:inherit; cursor:pointer;
    /* Opaque, not transparent. The connector layer sits behind the bands, and a
       see-through card let every wire run straight across its description. The
       fill is the page's own paper, so it still reads as a ruled box rather
       than a floating card. */
    background:var(--bg); border:1px solid var(--rule); border-top:2px solid var(--rule-firm);
    border-radius:0; padding:13px 14px 14px;
    transition:border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease),
               opacity var(--t-fast) var(--ease);
  }
  .mdl-node:hover{border-color:var(--rule-firm); background:var(--bg-inset);}
  .mdl-node[aria-pressed="true"]{
    border-color:var(--accent); border-top-color:var(--accent); background:var(--accent-wash);
  }
  .mdl-node.is-hidden{display:none;}
  .mdl-nm{
    display:block; font-family:var(--display); font-size:.94rem; font-weight:650;
    letter-spacing:-.012em; line-height:1.3;
  }
  .mdl-ds{display:block; color:var(--ink-muted); font-size:.84rem; line-height:1.55;}
  .mdl-tag{
    display:inline-block; margin-left:6px; vertical-align:2px;
    font-family:var(--mono); font-size:.58rem; letter-spacing:.1em; text-transform:uppercase;
    font-weight:500; color:var(--ink-muted);
    border:1px solid var(--rule); border-radius:2px; padding:1px 5px;
  }

  /* The one place colour is spent. */
  .mdl-band.is-spine .mdl-node{border-top-color:var(--bucket-1); background:var(--bg-inset);}
  .mdl-band.is-spine .mdl-node:hover{border-color:var(--bucket-1);}
  .mdl-band.is-spine .mdl-nm{font-size:1rem;}

  .mdl-canvas.is-tracing .mdl-node{opacity:.28;}
  .mdl-canvas.is-tracing .mdl-node.lit,
  .mdl-canvas.is-tracing .mdl-node[aria-pressed="true"]{opacity:1;}

  /* ---------- the reader ---------- */
  .mdl-read{border-top:2px solid var(--rule-firm); margin-top:34px; padding-top:18px;}
  .mdl-read-label{
    font-family:var(--mono); font-size:var(--label-size); letter-spacing:var(--label-track);
    text-transform:uppercase; font-weight:500; color:var(--ink-muted);
  }
  .mdl-read-nm{font-size:1.3rem; font-weight:650; letter-spacing:-.015em; margin-top:6px;}
  .mdl-read-note{margin-top:10px; max-width:var(--measure); color:var(--ink-muted); font-size:.98rem; line-height:1.65;}
  .mdl-read-links{
    margin-top:14px; padding-top:12px; border-top:1px solid var(--rule);
    font-size:.86rem; color:var(--ink-muted); line-height:1.7;
  }
  .mdl-read-links b{
    font-family:var(--mono); font-size:var(--label-size); letter-spacing:var(--label-track);
    text-transform:uppercase; font-weight:500; color:var(--ink); margin-right:10px;
  }
  .mdl-read-links .mdl-jump{
    background:none; border:none; padding:0; font:inherit; color:var(--accent);
    cursor:pointer; text-decoration:underline; text-underline-offset:3px;
  }
  .mdl-read-links .mdl-jump:hover{text-decoration-thickness:2px;}

  .mdl-foot{
    margin-top:30px; padding-top:18px; border-top:1px solid var(--rule);
    max-width:var(--measure); color:var(--ink-muted); font-size:.94rem; line-height:1.7;
  }

  @media (max-width:760px){
    .mdl-grid{grid-template-columns:minmax(0,1fr);}
    .mdl-band-h{grid-template-columns:minmax(0,1fr); gap:0;}
    .mdl-num{grid-row:auto; margin-bottom:6px;}
    .mdl-band-h p{grid-column:1;}
    /* One card per row means every wire would be a vertical stub between
       stacked boxes, carrying no information the band copy does not. */
    .mdl-wires{display:none;}
  }

  @media (forced-colors: active){
    .mdl-node[aria-pressed="true"]{border-color:Highlight;}
    .mdl-canvas.is-tracing .mdl-node{opacity:1;}
  }
  @media print{
    .mdl-controls, .mdl-wires{display:none;}
    .mdl-node{break-inside:avoid;}
    .mdl-band{break-inside:avoid;}
  }

  /* ===========================================================================
     MOBILE NAV
     ---------------------------------------------------------------------------
     Supersedes the "three links do not justify hiding navigation behind a
     menu" note in the narrow-width block above. Owner call: the wrapped second
     row read as two headers stacked, and it grew a row every time the nav did.

     Enhancement-gated on .has-navmenu, which the script adds. Without JS the
     rules below never match and the wrapped layout stands, so the toggle is
     never a button that cannot open anything.
     =========================================================================== */

  .nav-toggle{
    display:none; flex:none; cursor:pointer;
    width:44px; height:44px; align-items:center; justify-content:center;
    background:transparent; border-radius:6px; color:var(--ink);
    /* --cta-line, not --rule. This is a control whose boundary is its only
       affordance, and --rule measures 1.43:1 against paper — under WCAG 1.4.11's
       3.0. --cta-line is the token already documented for exactly this
       (3.40:1 light / 3.54:1 dark). */
    border:1px solid var(--cta-line);
  }
  .nav-toggle:hover{border-color:var(--accent); color:var(--accent);}
  .nav-bars{display:flex; flex-direction:column; gap:4px; width:18px;}
  .nav-bars i{
    display:block; height:1.5px; background:currentColor; border-radius:1px;
    transition:transform var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease);
  }
  .nav-toggle[aria-expanded="true"] .nav-bars i:nth-child(1){transform:translateY(5.5px) rotate(45deg);}
  .nav-toggle[aria-expanded="true"] .nav-bars i:nth-child(2){opacity:0;}
  .nav-toggle[aria-expanded="true"] .nav-bars i:nth-child(3){transform:translateY(-5.5px) rotate(-45deg);}

  @media (max-width:760px){
    /* order 2 with the theme control at order 1: the two bar controls sit as a
       pair at the right edge. Without the auto margin below, .nav's
       space-between spreads three items and strands the menu button in the
       middle of the bar. */
    .has-navmenu .nav-toggle{display:flex; order:2;}

    /* Overrides the wrapped-row rules above, which are all (0,1,0); anchoring
       on .has-navmenu makes these (0,2,0) so the panel wins without !important
       and the fallback layout stays intact when the class is absent. */
    .has-navmenu .nav-links{
      display:none; order:3; width:100%;
      flex-direction:column; align-items:stretch; gap:0;
      margin-top:14px; padding-top:6px; border-top:1px solid var(--rule-firm);
    }
    .has-navmenu .nav-links.is-open{display:flex;}
    .has-navmenu .nav-links a{
      width:100%; padding:0; min-height:52px; font-size:.74rem;
      border-bottom:1px solid var(--rule);
    }
    .has-navmenu .nav-links a.is-current{border-bottom:1px solid var(--rule);}
    /* The CTA is an action, not a destination: it sits below the rules with
       room around it rather than reading as a fourth link. */
    .has-navmenu .nav-links .cta{
      margin:16px 0 6px; justify-content:center; min-height:48px;
      border-bottom:0; font-size:.8rem;
    }
    /* The theme toggle is moved out of the panel and into the bar by script at
       this breakpoint: a visitor switching theme should not have to open
       navigation to do it. It is one node, relocated — never duplicated, which
       would put two controls for one setting in the accessibility tree. */
    .nav > .theme-toggle{order:1; margin-inline-start:auto; margin-right:10px;}
  }

  @media (prefers-reduced-motion: reduce){
    .nav-bars i{transition:none;}
  }

  /* Three roles rather than the two-column .arch-grid. Reuses .arch-item so the
     ruled treatment stays one component, not a near-copy. */
  .roles-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:28px 40px;}
  @media (max-width:900px){.roles-grid{grid-template-columns:repeat(2,1fr);}}
  @media (max-width:640px){.roles-grid{grid-template-columns:minmax(0,1fr);}}

  /* ===========================================================================
     AFFORDANCE — the resting state of a control

     What this fixes is systemic, not local. Every control on the site
     announced itself only on :hover and :focus-visible, which is to say it
     announced itself only after you had already guessed. On touch there is no
     hover at all, so the concept cards below read as prose. And .mdl-node is
     the same ruled-box family as .arch-item — the interactive boxes and the
     decorative ones were the same object.

     The section head already says "Select any part to see what it touches."
     The copy was asking for a click the design never offered.

     SECOND CUT. The first was an 8px hairline corner bracket, and it failed
     for a reason worth writing down: a corner tick has no learned meaning.
     Nobody has ever been taught that it means "press this", so it read as
     more ledger furniture on a page already made of rules. Restraint is only
     legible when the reader already knows what they are looking at.

     It also solved the wrong problem. The ask was to make clear someone
     SHOULD click, which is an invitation, not an affordance. So this cut is
     a verb, in colour, on every card, plus a cue line per interactive zone
     (.act-cue below).

     PRODUCT.md §4 turns out to license this directly: "Buttons carry the
     product's action language, not the ledger's." The ledger's restraint
     governs the page's structure, never its action cues. The first cut
     applied it where it does not apply.

     Deliberately NOT applied to .btn, .mdl-fbtn, .theme-toggle or .nav-toggle.
     Those already read as controls and a second signal on them is noise. The
     rule is: mark the things that look like content.
     =========================================================================== */

  /* Generated content, not 26 hand-written spans. This label is decorative
     repetition — the button's accessible name is already the concept and its
     description — and putting it in CSS keeps the state flip below to one
     rule instead of a JS text swap on every card. */
  .mdl-node::after{
    content:"Trace →";
    /* margin-top:auto against the column flex pins the row to the bottom, so
       the labels line up across a row of unequal-height cards. */
    margin-top:auto; padding-top:9px;
    border-top:1px solid var(--rule);
    font-family:var(--mono); font-size:var(--label-size); letter-spacing:var(--label-track);
    text-transform:uppercase; font-weight:500; color:var(--accent);
    transition:color var(--t-fast) var(--ease);
  }
  /* The label reports state rather than repeating the invitation. */
  .mdl-node[aria-pressed="true"]::after{content:"Tracing ●";}
  .mdl-node:active::after{color:var(--accent-hover);}
  /* The card has room for it: gap:6px already separates the description, and
     the 14px bottom padding becomes the row's breathing room. */
  .mdl-node{min-height:118px;}

  /* The filter chips read as buttons already, so they get the one state they
     were actually missing rather than a mark. */
  .mdl-fbtn:active{background:var(--bg-inset);}
  .mdl-fbtn[aria-pressed="true"]:active{opacity:.85;}

  /* ---------------------------------------------------------------------------
     The Lightning recreation gets SLDS affordances, not ledger ones.

     A corner mark inside .pui-frame would break the claim the frame is making:
     that this is what the product actually looks like. Real Lightning marks a
     live control with brand blue and a helper line, so that is what these use.
     --------------------------------------------------------------------------- */

  /* Genuine SLDS furniture (.slds-form-element__help), and the most direct
     answer to "can I touch this?" available: a sentence saying so. */
  .pui-help{
    margin-top:5px; font-family:var(--body); font-size:.68rem; line-height:1.45; color:#6B7280;
  }
  .pui-scenarios .pui-scen-list{margin-top:8px;}

  /* Focus lands on the radio, which is 15px across; without this the row it
     belongs to gave no indication it was the row in play. */
  .pui-scen:has(input:focus-visible){border-color:#0176D3; background:#F3F8FE;}
  .pui-scen:active{background:#EEF3F9;}

  /* Eight of the nine course rows carry a decorative ▸. One is a real control.
     Blue alone would be information by colour, so the live one also carries a
     resting ring — it differs in shape as well as hue, and it is the only
     thing in the grid that looks like a button because it is the only button. */
  tr.pui-course-row .pui-disclose{
    color:#0176D3; box-shadow:inset 0 0 0 1px #A9CBEE;
    transition:background var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
  }
  tr.pui-course-row .pui-disclose:hover{box-shadow:inset 0 0 0 1px #0176D3;}

  /* ---------------------------------------------------------------------------
     .act-cue — one cue line per interactive zone, site-wide.

     The instruction already existed on the model map, buried mid-paragraph in
     grey body copy: "Select any part to see what it touches." Nobody read it,
     including the person who asked for this twice. An instruction that is not
     visually distinct from the prose around it is not an instruction.

     Every cue ships hidden and is revealed by the same script that activates
     the control it describes, so a no-JS visitor is never told to click
     something inert. That gating is the reason this is a class and not three
     one-off lines.
     --------------------------------------------------------------------------- */
  .act-cue{
    display:flex; align-items:baseline; gap:9px;
    font-family:var(--mono); font-size:.78rem; letter-spacing:.01em; line-height:1.5;
    color:var(--accent);
  }
  .act-cue::before{
    content:"▸"; flex:none; font-size:.92em; line-height:1;
  }
  .act-cue[hidden]{display:none;}          /* [hidden] loses to display:flex */
  .mdl-controls .act-cue{flex:0 0 100%; margin-bottom:4px;}
  /* Under the hero panel and the plan grid the cue is the shell talking about
     the recreation, so it sits outside .pui-frame, never inside it. */
  .showcase-primary .act-cue, .hero-panel .act-cue{margin-top:12px;}
  .hero-panel .act-cue + .demo-note{margin-top:7px;}

  @media (forced-colors: active){
    .mdl-node::after{color:LinkText;}
    .act-cue{color:LinkText;}
    tr.pui-course-row .pui-disclose{box-shadow:none; border:1px solid ButtonBorder;}
  }
  @media print{
    /* Paper has no affordances, and no instruction to use one. */
    .mdl-node::after, .pui-help, .act-cue{display:none;}
  }

  /* ===========================================================================
     LOCKUP SCALE

     Successor to the WORDMARK SCALE block that stood here, which sized a
     CSS-drawn wordmark by font-size and then propagated that by hand into bar
     height, bar gap, baseline gap and an optical tracking correction. The
     press-kit lockup is one SVG with a fixed 297:65 viewBox, so all of that
     collapses into a single width and the proportions cannot drift.

     164px is chosen against two floors and a ceiling.

       Press-kit floor.  Its usage note sets a 160px minimum for the lockup and
                         says to fall back to the mark alone below that. The
                         SVG box IS the drawn width here — content spans the
                         full 0..297 viewBox — so 164 clears the minimum with a
                         little margin rather than sitting on it. The footer
                         takes 172px, where there is more room.

       Touch-target floor. .brand carries min-height:44px for WCAG 2.5.8. At
                         164px the lockup is 35.9px tall, so the 44px floor
                         still absorbs it and nothing below the nav moves.

       Header ceiling.   Past ~200px the lockup drives .nav's height instead of
                         sitting inside the 44px floor, every section shifts
                         down, and the hero loses the fold it was tuned to.
     =========================================================================== */

  .footer-left .pf-lockup{width:172px;}

  /* The tagline holds its size. Growing both would keep the ratio and lose the
     point — the hierarchy between mark and descriptor is the reason to do this
     at all. */

  /* ===========================================================================
     GUIDE CARETS — the in-app-guidance beacon

     One per interactive zone, never one per control. That restraint IS the
     idiom: a guidance beacon points at a single thing, and 26 bobbing arrows
     on 26 concept cards would be a shimmering wall rather than a pointer.

     Injected by script, never authored into the HTML, for the same reason the
     .act-cue lines ship hidden: without JS the controls are inert and nothing
     should be pointing at them. Decorative reinforcement of a cue line that
     already says the same thing in words, so every one is aria-hidden.

     A border-triangle rather than an SVG. It is the same caret shape as the ▸
     already carrying .act-cue and the decorative course rows, so the page
     gains a motion, not a new glyph.
     =========================================================================== */

  .is-guided{position:relative;}
  .guide{
    position:absolute; width:0; height:0;
    border:6px solid transparent;
    /* Never intercepts a click. The beacon points at a control; it must not
       become a 12px dead zone in front of one. */
    pointer-events:none; z-index:3;
    transition:opacity var(--t-med) var(--ease);
  }
  .guide-down{ border-top-color:var(--accent); border-bottom-width:0; }
  .guide-right{ border-left-color:var(--accent); border-right-width:0; }

  /* Inside the Lightning recreation the beacon speaks SLDS, not ledger. Real
     Salesforce In-App Guidance floats over the app in brand blue, so a shell
     accent here would be the one wrong note. */
  .pui-frame .guide-down{border-top-color:#0176D3;}
  .pui-frame .guide-right{border-left-color:#0176D3;}

  /* Dismissed on first interaction with its own zone, which is what separates
     a beacon from decoration: it has a job and then it is finished. */
  .guide-off .guide, .guide.is-off{opacity:0;}

  @media (prefers-reduced-motion: no-preference){
    .guide-down{animation:guide-bob-y 2.1s var(--ease) infinite;}
    .guide-right{animation:guide-bob-x 2.1s var(--ease) infinite;}
  }
  /* Travel is 4px. Large enough to read as deliberate at the edge of vision,
     small enough that it never reads as something coming loose. */
  @keyframes guide-bob-y{ 0%,100%{transform:translateY(0);} 50%{transform:translateY(4px);} }
  @keyframes guide-bob-x{ 0%,100%{transform:translateX(0);} 50%{transform:translateX(4px);} }

  /* The other reading of "hovering arrows": each card's own Trace → nudges
     under the cursor. Costs nothing, animates only the one card being pointed
     at, and gives the 25 cards without a beacon the same answer on contact.

     text-indent, not transform. The ruled separator above this label is the
     ::after box's own border-top, so translating the box would slide the rule
     off the card's left edge with it. text-indent moves the text inside a box
     that stays exactly where it is. */
  .mdl-node::after{
    transition:color var(--t-fast) var(--ease), text-indent var(--t-fast) var(--ease);
  }
  @media (prefers-reduced-motion: no-preference){
    .mdl-node:hover::after, .mdl-node:focus-visible::after{text-indent:5px;}
  }

  @media print{ .guide{display:none;} }

  /* ===========================================================================
     SHIFFY ALIGNMENT

     Owner call: bring the design language closer to Shiffy (~/dev/shiffy).

     Which Shiffy, though. There are two, and they point opposite ways:

       - The DASHBOARD / iOS language, codified in shiffy/DESIGN.md, which
         calls itself the source of truth: cream paper, ink, --radius 2px,
         "no friendly rounded SaaS look", and mono caps on buttons, which it
         names "the loudest signal of the register".
       - The MARKETING SITE, which is rounded-lg (8px), shadow-md and title
         case — very nearly what this site already had.

     Taking the dashboard language, because this site already IS it: warm
     paper, hairline rules, 2px chips, mono caps labels, and the identical
     cubic-bezier(.22,1,.36,1) easing curve, arrived at independently. Two
     elements had opted out, which is exactly the incoherence reported. The
     marketing site would have preserved that; it is also the outlier inside
     Shiffy's own house, being the thing its DESIGN.md anti-references warn
     about.

     NOT taken, deliberately:
       - Shiffy's terracotta. This palette's blue is bucket-1, the product's
         own Temporary Faculty colour, and the wordmark bar quotes the budget
         bar. Terracotta would orphan the mark from the thing it quotes.
       - Bricolage / Hanken / Space Mono. Owner chose to stay on system
         stacks; Shiffy loads them off the Google Fonts CDN, which PRODUCT.md
         §6 forbids here outright.
       - Card shadows. This site replaced cards with rules and sets
         --shadow: none on purpose.
     =========================================================================== */

  /* Shiffy's §4 radius scale, as real tokens rather than scattered literals. */
  :root{
    --radius:    2px;   /* every control */
    --radius-lg: 4px;   /* the rare enclosing surface */
  }

  /* ---- Shiffy §7.1: sharp rectangles, 1px border, mono caps ---- */
  .btn, .nav-links .cta{
    border-radius:var(--radius);
    font-family:var(--mono);
    text-transform:uppercase;
    /* Shiffy's form/button tracking. Caps without tracking reads as shouting;
       tracked caps reads as a label, which is the register. */
    letter-spacing:.08em;
    font-weight:500;
  }
  /* Shiffy's §3.1 button size, 15px, now reachable. The first cut sat at
     .8rem because the primary CTA was 36 characters ("Talk to us about a
     design partnership") and tracked caps at 15px made it the widest object
     on the page. That copy is now "Talk to us", so the compromise is spent
     and this can match the spec outright. */
  .btn{font-size:.94rem; padding:13px 22px;}
  .nav-links .cta{font-size:.7rem; letter-spacing:.09em;}

  /* Supersedes the earlier rounded-focus fix: with a 2px control the global
     :focus-visible radius is now correct, so these only need to not fight it. */
  .btn:focus-visible, .nav-links .cta:focus-visible{border-radius:var(--radius);}

  /* Shiffy: "Hover always lifts contrast." The ghost variant fills rather than
     merely tinting, which is its .btn-secondary behaviour. */
  .btn-ghost:hover{
    background:var(--cta-fill);
    border-color:var(--cta-fill);
    color:var(--cta-on);
  }

  /* Heading tracking to Shiffy's -.02em. h1/h2 were already there; this is the
     smaller tier catching up. */
  h3,h4{letter-spacing:-.015em;}

  /* ---- Shiffy §9: paper grain ----
     Its DESIGN.md calls this "most of why the UI doesn't read as generic
     SaaS", and it is the single cheapest thing that makes two sites feel
     related. Same filter, same opacities. Inline data URI, so it stays
     consistent with §6 here: nothing is fetched. */
  body::before{
    content:"";
    position:fixed; inset:0; z-index:0; pointer-events:none;
    background-image:url("data:image/svg+xml;utf8,<svg viewBox='0 0 240 240' xmlns='http://www.w3.org/2000/svg'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/><feColorMatrix values='0 0 0 0 0.05  0 0 0 0 0.05  0 0 0 0 0.05  0 0 0 0.06 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
    opacity:.6;
    mix-blend-mode:multiply;
  }
  :root[data-theme="dark"] body::before{mix-blend-mode:lighten; opacity:.15;}

  /* The recreations are the one surface the grain must not touch. PRODUCT.md
     §4: they stay fixed-light in both themes because real Lightning does not
     reskin, and a screenshot carrying a paper texture would read as fake.
     Raising them into their own stacking context lifts them clear of it. */
  .pui-frame{position:relative; z-index:1;}

  @media print{ body::before{display:none;} }
