/* BVL shared theme. Canonical file: products/_shared/theme.css.
   Copied verbatim to each site's public/style.css (fonts/ too) by products/_shared/sync.sh;
   products/_shared/theme.test.mjs fails on drift. Edit here, never in a site copy. Design record: products/DESIGN.md. */

@font-face{font-family:"Archivo";src:url("fonts/archivo.woff2") format("woff2");font-weight:100 900;font-stretch:62% 125%;font-display:swap}
@property --cut{syntax:"<length>";inherits:false;initial-value:0px}

:root{
  color-scheme:light dark;
  --paper:#f5f6f4;--ink:#0f1012;--ink-2:#45484d;--rule:#c9cbc8;--input:#fff;
  --field:var(--ink);--on-field:var(--paper);--facet:#45484d;
  --gutter:clamp(16px,3.4vw,48px);--gap:clamp(16px,2vw,28px);--page:88rem;
  --sans:"Archivo","Helvetica Neue",Arial,sans-serif;
  --mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  --key:3px;
  /* Code tokens, on the ink code ground (light scheme: #0f1012). */
  --tok-k:#a3b4ff;--tok-f:#7dd3c0;--tok-s:#b6db8c;--tok-n:#ffae7a;--tok-lit:#f2a2df;--tok-c:#9b9fa6;--tok-p:#8c9097;
}
@media (prefers-color-scheme:dark){
  :root{--paper:#111214;--ink:#eff0ec;--ink-2:#b4b7bb;--rule:#3a3c40;--facet:#b4b7bb;
    --tok-k:#2a32b5;--tok-f:#00685a;--tok-s:#386710;--tok-n:#a13e00;--tok-lit:#892676;--tok-c:#5c6067;--tok-p:#63676d}
}
/* Product colour, set on <body> (landings) or on a home card. */
.stalewatch{--field:#ffcf1a;--on-field:#0f1012;--facet:#d9a200}
.migration-guard{--field:#2a2ed6;--on-field:#fff;--facet:#171a96}
.writestop{--field:#0f6e6e;--on-field:#fff;--facet:#094848}

*,*::before,*::after{box-sizing:border-box}
html{background:var(--paper);-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{margin:0;background:var(--paper);color:var(--ink);font:400 clamp(1rem,.95rem + .25vw,1.0625rem)/1.55 var(--sans);font-stretch:100%;caret-color:var(--ink);overflow-wrap:break-word;overflow-x:clip}
::selection{background:var(--ink);color:var(--paper)}
h1,h2,h3{margin:0;font-weight:800;line-height:1.02;letter-spacing:-.02em;text-wrap:balance}
h1{font-size:clamp(2.25rem,1.4rem + 2.6vw,3.5rem);font-stretch:112%}
h2{font-size:clamp(1.25rem,1.05rem + .7vw,1.6rem);font-stretch:118%}
h3{font-size:1.5rem;font-stretch:125%}
p,ul,ol,table,pre,form{margin:0 0 1rem}
ul,ol{padding-left:1.25em}
li+li{margin-top:.4rem}
strong{font-weight:700}
/* 4px of block padding lifts a standalone link to a 24px target (WCAG 2.2 2.5.8) without moving any line of text. */
a{color:inherit;text-decoration-thickness:2px;text-underline-offset:.2em;padding-block:4px}
a:hover{background:var(--ink);color:var(--paper);text-decoration:none}
:focus-visible{outline:3px solid var(--ink);outline-offset:3px}
code{font:.9em var(--mono);padding:.08em .3em;background:color-mix(in srgb,var(--ink) 9%,transparent)}
pre{font:.875rem/1.55 var(--mono);color:var(--paper);background:linear-gradient(315deg,transparent 12px,var(--ink) 0);padding:1rem calc(1.25rem + 12px) 1rem 1.25rem;white-space:pre-wrap;overflow-wrap:anywhere}
pre code{font:inherit;background:none;padding:0}
pre::selection,pre ::selection{background:var(--paper);color:var(--ink)}
.muted{color:var(--ink-2)}
.muted,td,.card,footer{font-variant-numeric:tabular-nums}
.skip{position:absolute;left:-9999px;top:0;z-index:10;padding:.75rem 1rem;background:var(--ink);color:var(--paper)}
.skip:focus{left:var(--gutter)}

/* Bevel: the brand mark is a 45-degree cut on the bottom-right corner, drawn as a background so focus rings survive. */
.field{--cut:clamp(28px,3vw,44px);color:var(--on-field);background:linear-gradient(315deg,transparent var(--cut),var(--facet) var(--cut) calc(var(--cut) + 10px),var(--field) 0)}
.field{--ink:var(--on-field);--paper:var(--field);color-scheme:light}
.field input[type=checkbox]{accent-color:var(--on-field)}

/* Buttons: one vocabulary for .btn (home), form buttons and the injected .button (pre-order). */
.btn,.button,button{--cut:9px;--fill:var(--on-field);--ring:var(--on-field);--text:var(--field);display:inline-flex;align-items:center;min-height:48px;padding:.65rem 1.4rem .65rem 1.15rem;border:2px solid transparent;font:700 1rem/1.2 var(--sans);font-stretch:112%;letter-spacing:.01em;cursor:pointer;transition:--cut .16s cubic-bezier(.16,1,.3,1)}
.btn,.btn:hover,.button,.button:hover,button{color:var(--text);text-decoration:none;background:linear-gradient(315deg,transparent calc(var(--cut) - 1px),var(--fill) 0) padding-box,linear-gradient(315deg,transparent var(--cut),var(--ring) 0) border-box}
.button{--fill:var(--field);--ring:var(--ink);--text:var(--on-field)}
.btn:hover,.btn:focus-visible,button:hover,button:focus-visible{--cut:18px;--fill:var(--field);--text:var(--on-field)}
.button:hover,.button:focus-visible{--cut:18px;--fill:var(--ink);--text:var(--paper)}
/* Secondary .btn on a field card: field-coloured fill, on-field ring and text; hover inverts like the primary. */
.btn.alt{--fill:var(--field);--text:var(--on-field)}
.btn.alt:hover,.btn.alt:focus-visible{--fill:var(--on-field);--text:var(--field)}

/* Notes: status and limits at full weight inside a keyline frame. */
.note{border:2px solid var(--ink);padding:.9rem 1.1rem;margin:1.5rem 0;font-weight:500}
.note strong{font-weight:800}

/* Forms */
label{display:block;margin:0 0 1rem;font-weight:600}
input[type=email],input[type=text]{display:block;width:100%;max-width:28rem;min-height:48px;margin-top:.35rem;padding:.6rem .75rem;font:400 1.0625rem var(--sans);color:#0f1012;background:var(--input);border:2px solid #0f1012;border-radius:0}
input[type=number]{display:block;width:100%;max-width:10rem;min-height:48px;margin-top:.35rem;padding:.6rem .75rem;font:400 1.0625rem var(--sans);color:#0f1012;background:var(--input);border:2px solid #0f1012;border-radius:0}
textarea{display:block;width:100%;max-width:100%;min-height:12rem;margin:.35rem 0 1rem;padding:.75rem;font:400 .9375rem/1.5 var(--mono);color:#0f1012;background:var(--input);border:2px solid #0f1012;border-radius:0;resize:vertical}
input[type=checkbox]{width:1.25rem;height:1.25rem;margin:.15rem 0 0;accent-color:#0f1012}
label:has(input[type=checkbox]){display:grid;grid-template-columns:auto minmax(0,1fr);gap:.7rem;font-weight:400}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}

/* Code blocks (highlight.mjs codeBlock): one bevelled ink slab, exactly its column's width, holding a label bar (kind:
   SQL, JSON or Output, then an optional title) over the code, with the same inset on both sides. contain:inline-size keeps
   long lines from widening any ancestor, so a block never runs past its column. SQL and JSON wrap, continuation lines
   hanging by 2ch; query output (psql tables) keeps its columns and scrolls inside the slab, where text running past
   either edge fades out. The fade covers only the left inset and a wider right end that the scroll keeps empty, so text
   fades exactly when there is more to scroll to and never at rest.
   Token colours clear 4.5:1 on the slab in both schemes. */
.code{--cut:12px;--pad:clamp(.875rem,.55rem + 1.4vw,1.25rem);contain:inline-size;margin:0 0 1rem;color:var(--paper);background:linear-gradient(315deg,transparent var(--cut),var(--ink) 0)}
.code figcaption{display:flex;gap:.75rem;align-items:baseline;padding:.45rem var(--pad) .4rem;border-bottom:1px solid color-mix(in srgb,var(--paper) 28%,var(--ink));font-size:.8125rem;font-weight:700;font-stretch:118%;letter-spacing:.06em;line-height:1.4}
.code-lang{flex:none;text-transform:uppercase}
.code-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500;font-stretch:100%;letter-spacing:0}
.code pre{--fade:calc(var(--pad) + 1.75rem);margin:0;padding:.85rem var(--fade) 1.15rem var(--pad);background:none;font-size:clamp(.8125rem,.78rem + .15vw,.875rem);line-height:1.6;white-space:pre;overflow-wrap:normal;overflow-x:auto;tab-size:4;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--paper) 45%,var(--ink)) transparent;mask-image:linear-gradient(90deg,transparent,#000 var(--pad),#000 calc(100% - var(--fade)),transparent)}
.code pre:has(>.language-sql,>.language-json){padding-right:var(--pad);mask-image:none;white-space:pre-wrap;overflow-wrap:break-word;text-indent:2ch hanging each-line}
.code ::selection{background:var(--paper);color:var(--ink)}
.code:has(pre:focus-visible){outline:3px solid var(--ink);outline-offset:3px}
.code pre:focus-visible{outline:0}
.tok-k{color:var(--tok-k);font-weight:700}
.tok-key{color:var(--tok-k)}
.tok-f{color:var(--tok-f)}
.tok-s{color:var(--tok-s)}
.tok-n{color:var(--tok-n)}
.tok-lit{color:var(--tok-lit)}
.tok-c{color:var(--tok-c)}
.tok-p{color:var(--tok-p)}

/* Shell: header, footer, page width */
header,main,footer{width:min(100% - 2*var(--gutter),var(--page));margin-inline:auto}
header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.5rem 1rem;padding-top:clamp(16px,2.5vw,32px)}
.wordmark{--cut:12px;display:inline-flex;align-items:center;min-height:48px;padding:.2rem 1.1rem .2rem .8rem;font:900 1.75rem/1 var(--sans);font-stretch:125%;letter-spacing:.02em;text-decoration:none;color:var(--paper);background:linear-gradient(315deg,transparent var(--cut),var(--ink) 0)}
.wordmark:hover{color:var(--paper);background:linear-gradient(315deg,transparent 18px,var(--ink) 0)}
header nav{display:flex;gap:1rem;margin-right:-.5rem}
header nav a{display:inline-flex;align-items:center;min-height:48px;padding:0 .5rem;font-weight:700;font-stretch:112%}
footer{display:grid;grid-template-columns:repeat(auto-fit,minmax(13rem,1fr));gap:.5rem var(--gap);margin-top:clamp(48px,7vw,96px);padding:1rem 0 2.5rem;border-top:var(--key) solid var(--ink);font-size:.9375rem}
footer p{margin:0}
footer a{display:inline-block;min-width:24px;min-height:24px;text-align:center}

/* Registration: from 60rem every page on all three sites sits on one 12-column key grid.
   Read label 1-3 / text 4-9; home hero 1-8 / 9-12; cards 1-6 / 7-12; landing copy 1-7 / action 9-12. */
main{display:grid;grid-template-columns:minmax(0,1fr);column-gap:var(--gap);padding-top:clamp(32px,6vw,80px)}
main>*{min-width:0}
@media (min-width:60rem){main{grid-template-columns:repeat(12,minmax(0,1fr))}main>*{grid-column:1 / -1}}

/* Read pages: hanging section heads on the label columns, calm text column. */
.doc>h1{margin-bottom:1.5rem}
.doc>h1+.muted{margin-bottom:0}
.doc>h2{margin-top:2.75rem;margin-bottom:.75rem;padding-top:.7rem;border-top:var(--key) solid var(--ink)}
.doc>p,.doc>ul,.doc>ol{max-width:34rem}
.doc>.crumb{margin-bottom:1.25rem;font-weight:600;font-stretch:112%}
/* Product mark on Read pages: a bevelled colour block above the title. */
body.stalewatch>.doc::before,body.migration-guard>.doc::before{content:"";display:block;width:clamp(96px,14vw,168px);height:clamp(40px,5vw,64px);margin-bottom:1.5rem;--cut:clamp(14px,1.6vw,22px);background:linear-gradient(315deg,transparent var(--cut),var(--facet) var(--cut) calc(var(--cut) + 6px),var(--field) 0)}
@media (min-width:60rem){
  .doc>*{grid-column:4 / 10}
  .doc>h1{grid-column:1 / 10;max-width:22ch}
  .doc>h1+.muted,.doc>h2,body.stalewatch>.doc::before,body.migration-guard>.doc::before{grid-column:1 / 4}
  .doc>h2{margin-bottom:0;padding-right:1rem}
  .doc>h2+*{margin-top:2.75rem;padding-top:.85rem}
  .doc>h2+.code{margin-top:3.6rem;padding-top:0}
  .doc>.crumb{grid-column:1 / -1}
  body.stalewatch>.doc::before,body.migration-guard>.doc::before{width:auto}
}

table{width:100%;table-layout:fixed;border-collapse:collapse;border-top:var(--key) solid var(--ink)}
th,td{text-align:left;vertical-align:top;padding:.75rem .75rem .75rem 0;border-bottom:1px solid var(--rule)}
th{width:7.5rem;font-weight:700;font-stretch:112%}
@media (min-width:40rem){th{width:11rem}}
thead th{width:auto}
td .code{margin:0}

/* Home (bvl.dev) */
.poster>.hero{padding-bottom:clamp(32px,5vw,64px)}
.poster h1{font-size:clamp(2.6rem,1.2rem + 4.8vw,6rem);font-stretch:125%;font-weight:850;line-height:.95;letter-spacing:-.03em;max-width:14ch;margin-bottom:clamp(20px,3vw,36px)}
.hero p{max-width:34rem;font-size:clamp(1.0625rem,1rem + .35vw,1.3125rem)}
.hero p:last-child{font-weight:700;font-stretch:112%}
@media (min-width:60rem){
  .hero,.poster section,.poster .grid{display:grid;grid-template-columns:subgrid;grid-column:1 / -1}
  .hero{grid-template-rows:1fr auto;align-items:end}
  .hero h1{grid-column:1 / 9;grid-row:1 / span 2;margin-bottom:0}
  .hero p{grid-column:9 / 13}
  .hero p:last-child{margin-bottom:.4rem}
  #tools>h2{grid-column:1 / -1}
  .grid>:first-child,#tools>.note{grid-column:1 / 7}
  .grid>:last-child{grid-column:7 / 13}
}
#tools>h2{margin:0 0 var(--gap);padding-top:.7rem;border-top:var(--key) solid var(--ink)}
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,22rem),1fr));gap:var(--gap)}
.card{display:flex;flex-direction:column;padding:clamp(20px,2.6vw,36px) clamp(20px,2.6vw,36px) clamp(36px,4vw,56px)}
.card h3{font-size:clamp(1.9rem,1.3rem + 2vw,3rem);margin-bottom:.9rem}
.card p{max-width:30rem}
.card p:last-child{margin:auto 0 0;padding-top:.75rem}
.card .hook{font-size:clamp(1.3rem,1.1rem + .7vw,1.65rem);font-weight:800;font-stretch:112%;line-height:1.18;margin-bottom:.6rem}
.card .price{font-size:1.25rem;font-weight:700;font-stretch:112%}
.card .actions{display:flex;flex-wrap:wrap;gap:1rem}
.badge{display:inline-block;padding:.15rem .55rem;font-size:.8125rem;font-weight:700;font-stretch:118%;letter-spacing:.06em;text-transform:uppercase;color:var(--field);background:var(--on-field)}
#tools>.note{max-width:44rem}
.split{display:grid;grid-template-columns:minmax(0,1fr);margin-top:clamp(40px,6vw,72px)}
.split>h2{padding-top:.7rem;border-top:var(--key) solid var(--ink);margin-bottom:1rem}
.split ul{list-style:none;padding:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,15rem),1fr));gap:var(--gap)}
.split li{margin:0;padding-top:.7rem;border-top:1px solid var(--ink)}
.split li strong{display:block;font-size:1.25rem;font-weight:800;font-stretch:118%;line-height:1.15;margin-bottom:.35rem}
.split>p{font-size:clamp(1.125rem,1rem + .5vw,1.5rem);font-weight:700;font-stretch:112%}
@media (min-width:60rem){
  .split>h2{grid-column:1 / 4}
  .split>:not(h2){grid-column:4 / 13;padding-top:.85rem;border-top:1px solid var(--ink)}
  .split>ul{display:grid;grid-template-columns:subgrid;border-top:0;padding-top:0}
  .split li{grid-column:span 3}
}

/* Product landings: copy on the left, the colour action block on the right; the injected pre-order block stacks under it. */
.landing{padding-top:0}
.landing>.lede{padding-top:clamp(32px,6vw,72px)}
.landing h1{font-size:clamp(2rem,1.2rem + 3.2vw,4.25rem);font-stretch:125%;line-height:.98;letter-spacing:-.03em;max-width:15ch;margin-bottom:clamp(20px,3vw,36px)}
.lede>h1+p,.lede>h1+p+p{max-width:36rem;font-size:clamp(1.0625rem,1rem + .35vw,1.25rem)}
.lede>h2{margin:clamp(2rem,1.4rem + 2vw,2.75rem) 0 .85rem;padding-top:.7rem;border-top:var(--key) solid var(--ink)}
.lede>p,.lede>ul{max-width:34rem}
.lede ol{--step:clamp(2.75rem,2.2rem + 2vw,3.75rem);list-style:none;padding:0;counter-reset:step;max-width:34rem}
.lede ol li{counter-increment:step;position:relative;margin:0;padding:.65rem 0 .7rem var(--step);border-bottom:1px solid var(--rule)}
.lede ol li::before{content:counter(step);position:absolute;left:0;top:.6rem;font-size:clamp(1.75rem,1.45rem + 1.2vw,2.25rem);font-weight:850;font-stretch:125%;line-height:.9}
.lede .note{max-width:34rem}
.join{margin:0 calc(-1*var(--gutter));padding:clamp(28px,3vw,44px) var(--gutter) clamp(40px,6vw,80px)}
.join h2{font-size:clamp(1.75rem,1.2rem + 1.6vw,2.5rem);font-stretch:125%;margin-bottom:1.5rem}
.join form{margin-bottom:1.5rem}
.join>p{font-size:.9375rem}
.landing>p{margin:0}
.landing>.note{margin:1rem 0 0}
.landing>p:has(.button){margin-top:1rem}
@media (min-width:60rem){
  .landing{grid-template-rows:repeat(4,auto) 1fr}
  .landing>.lede{grid-column:1 / 8;grid-row:1 / -1}
  .landing>.join{grid-column:9 / 13;grid-row:1;margin:0 calc(-1*max(var(--gutter),(100vw - var(--page))/2)) 0 0;padding-left:clamp(28px,3vw,44px);padding-top:clamp(32px,6vw,72px)}
  .landing>p,.landing>.note{grid-column:9 / 13}
}
/* Without an injected pre-order block, the action column stays in view while the copy scrolls. */
@media (min-width:60rem) and (min-height:760px){
  .landing:not(:has(#preorder))>.join{grid-row:1 / -1;align-self:start;position:sticky;top:0}
}

@media (prefers-reduced-motion:no-preference){
  .field{animation:cut .7s cubic-bezier(.16,1,.3,1) .15s backwards}
  @keyframes cut{from{--cut:0px}}
}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}
/* Phones: the signup sits at the end of the page, so offer a jump to it near the top. */
@media (min-width:60rem){.jump{display:none}}

/* === stalewatch demo === */
/* Stalewatch landing (positioning v2 section 3) and demo result (section 4.2). Everything here is scoped to sw-* classes. */
.sw-actions{display:flex;flex-wrap:wrap;gap:1rem}
.button.sw-secondary{--fill:var(--paper);--text:var(--ink)}
.button.sw-secondary:hover,.button.sw-secondary:focus-visible{--fill:var(--ink);--text:var(--paper)}
/* Demo form buttons sit on paper, not in a field: the same yellow slab as the result page's closing button, in both schemes. */
.stalewatch .doc button{--fill:var(--field);--ring:var(--ink);--text:var(--on-field)}
.stalewatch .doc button:hover,.stalewatch .doc button:focus-visible{--fill:var(--ink);--text:var(--paper)}
.sw-why{max-width:34rem;margin:0 0 1rem;border-top:1px solid var(--rule)}
.sw-why dt{padding-top:.7rem;font-weight:800;font-stretch:118%;line-height:1.25}
.sw-why dd{margin:.3rem 0 0;padding-bottom:.7rem;border-bottom:1px solid var(--rule)}
.sw-summary{font-size:clamp(1.0625rem,1rem + .35vw,1.25rem);font-weight:700;font-stretch:112%}
.sw-alerts{font-weight:600}
.sw-table{margin-top:1.75rem}
.sw-table h3{margin-bottom:.5rem}
.sw-table p{margin-bottom:.75rem}
/* Rhythm strip: one column per hour; busy slots in the product colour, rows in ink, alert hours outlined. */
.sw-strip{table-layout:fixed;border-collapse:separate;border-spacing:2px;border-top:0;margin:0 0 .75rem -2px;width:calc(100% + 4px)}
.sw-strip th,.sw-strip td{padding:0;border:0;vertical-align:middle}
.sw-strip thead td{width:4.75rem;background:none}
.sw-strip thead th{width:auto;font-size:.75rem;font-weight:600;font-stretch:100%;font-variant-numeric:tabular-nums;color:var(--ink-2);white-space:nowrap}
.sw-strip thead th:not(:nth-child(6n+2)){font-size:0}
.sw-strip tbody th{width:auto;padding-right:.4rem;font-size:.75rem;font-weight:700;font-stretch:112%;white-space:nowrap}
.sw-strip td{height:1.25rem;font-size:0;background:color-mix(in srgb,var(--ink) 9%,transparent)}
.sw-day>*{border-top:.6rem solid transparent;background-clip:padding-box}
.sw-strip .on,.sw-key .on{background:var(--field)}
.sw-strip .r,.sw-key .r{background:var(--ink)}
.sw-strip .q,.sw-key .q{background:var(--field);outline:2px solid #0f1012;outline-offset:-2px}
.sw-key{font-size:.9375rem}
.sw-key span{display:inline-block;width:.9rem;height:.9rem;margin:0 .35rem 0 0;vertical-align:-.1rem}
.sw-key span+span{margin-left:.9rem}
@media (min-width:40rem){
  .sw-strip thead td{width:5.5rem}
  .sw-strip thead th:nth-child(3n+2){font-size:.75rem}
  .sw-strip tbody th{font-size:.8125rem}
  .sw-strip td{height:1.5rem}
}
/* === migration-guard demo === */
/* Positioning v2 (docs/strategy/2026-11-03-positioning.md 4.1): the result summary, statement blocks that wrap instead of
   clipping, spacing between findings, and the landing's action row and comparison list. Scoped to Migration Guard. */
.migration-guard .mg-summary{max-width:40rem;font-size:clamp(1.125rem,1rem + .5vw,1.375rem);font-weight:700;font-stretch:112%;line-height:1.35}
body.migration-guard .doc>h3{margin-bottom:.75rem;font-size:1.1875rem;font-stretch:112%}
body.migration-guard .doc form button{--fill:var(--field);--ring:var(--ink);--text:var(--on-field)}
body.migration-guard .doc form button:hover,body.migration-guard .doc form button:focus-visible{--fill:var(--ink);--text:var(--paper)}
body.migration-guard .doc>table+h3{margin-top:2.25rem}
.migration-guard .mg-actions{display:flex;flex-wrap:wrap;gap:1rem}
.migration-guard .button.mg-alt{--fill:var(--paper);--text:var(--ink)}
.migration-guard .button.mg-alt:hover,.migration-guard .button.mg-alt:focus-visible{--fill:var(--ink);--text:var(--paper)}
.migration-guard .mg-compare{max-width:34rem;margin:0 0 1rem;border-top:1px solid var(--rule)}
.migration-guard .mg-compare dt{padding-top:.7rem;font-weight:800;font-stretch:112%}
.migration-guard .mg-compare dd{margin:.3rem 0 0;padding-bottom:.7rem;border-bottom:1px solid var(--rule)}
/* === conversion === */
/* Positioning v2.1 B (docs/strategy/2026-11-03-positioning.md): one three-part frame (Input -> Output -> What {Tool} did) on
   landings, demo pages and result pages; the conversion strip; the founding-spots line; join blocks on Read pages; the
   landing's demo-first order; room for a third bvl.dev card. Shared by every product; ink and paper only. */
figure{margin:0 0 1rem}
details{margin:0 0 1rem}
summary{padding:.7rem 0;font-weight:700;font-stretch:112%;cursor:pointer}
summary::marker{color:var(--ink)}
summary:hover{text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:.2em}
details[open]>summary{margin-bottom:.35rem}

/* The frame has three levels (products/DESIGN.md "Frame hierarchy").
   1 Part: a 3px ink keyline across the whole part, a numbered small-caps label (the h2, "1 · Input"), then the part's
     answer in large type (.lead: the input in one line; .verdict: the result). Parts sit 2.5-4rem apart.
   2 Item, inside a part (a finding, a table, a limit, the what-it-did rows): a tinted panel with a 10px bevel and no
     keyline, in smaller steps, so it reads as contained, never as a new section.
   3 Detail: a native <details> row in lighter type inside an item.
   Page sections outside the frame (join, Try it on your own) keep the bold sentence-case h2 on a short keyline. */
.frame{display:grid;row-gap:clamp(2.5rem,1.6rem + 3vw,4rem);counter-reset:part}
.frame>section{counter-increment:part;padding-top:.65rem;border-top:var(--key) solid var(--ink)}
.frame>section,.frame>section>*,.sample>*{min-width:0}
.frame>section>h2{margin:0 0 .45rem;font-size:.8125rem;font-weight:700;font-stretch:118%;letter-spacing:.08em;line-height:1.4;text-transform:uppercase}
.frame>section>h2::before{content:counter(part) " \b7  "}
.frame>section>:last-child{margin-bottom:0}
.lead{margin:0 0 .35rem;font-size:clamp(1.25rem,1.05rem + .7vw,1.6rem);font-weight:800;font-stretch:118%;line-height:1.15;letter-spacing:-.01em;text-wrap:balance}
.verdict,.ws-verdict{margin:0 0 .6rem;font-size:clamp(1.75rem,1.2rem + 1.6vw,2.5rem);font-weight:800;font-stretch:125%;line-height:1.02;letter-spacing:-.02em;text-wrap:balance}
.frame .mg-summary,.frame .sw-summary{max-width:40rem;font-size:inherit;font-weight:600;font-stretch:100%;line-height:1.5}
.frame summary{padding:.4rem 0;font-size:.9375rem;font-weight:600;font-stretch:100%}
.frame>section>details{margin:0}
.frame details>.code:last-child{margin-bottom:0}
/* Level 2: a ranked list of item panels (the tier tag inverts for the rows that need action), and the what-it-did rows
   as one panel. */
.ranked,.ws-limits{display:grid;gap:.5rem;list-style:none;padding:0;margin:.9rem 0 1rem}
.ranked>li,.ws-limits>li,.did{--cut:10px;background:linear-gradient(315deg,transparent var(--cut),color-mix(in srgb,var(--ink) 7%,var(--paper)) 0)}
.ranked>li,.ws-limits>li{margin:0;padding:.6rem .8rem .7rem}
.ranked>li,.ws-limits>li,.did,.frame details>p{font-size:1rem}
.ranked>li>p{margin:0 0 .3rem}
.ranked>li>:last-child{margin-bottom:0}
.ranked details,.ws-limits details{margin:.35rem 0 0}
.ranked details>:not(summary),.ws-limits details>:not(summary){font-size:.9375rem}
.migration-guard .ranked table{border-top:1px solid var(--rule)}
/* Phones: a finding's fact table stacks, label over value, so its statement gets the panel's full width. */
@media (max-width:39.99rem){.migration-guard .ranked :is(table,tbody,tr,th,td){display:block;width:auto}.migration-guard .ranked th{padding:.55rem 0 0;border:0}.migration-guard .ranked td{padding:.15rem 0 .55rem}}
.tier{display:inline-block;margin-right:.4rem;padding:0 .45rem;border:2px solid var(--ink);font-size:.75rem;font-weight:700;font-stretch:118%;letter-spacing:.06em;line-height:1.6;text-transform:uppercase;vertical-align:.12em}
.tier-fix{color:var(--paper);background:var(--ink)}
.tier-low{color:var(--ink-2);border-color:var(--rule)}
.ranked .size{white-space:nowrap}
.migration-guard .ranked .tier{display:table;margin-bottom:.35rem}
.ranked p,.ws-limits p,.did p{text-wrap:pretty}
.did{list-style:none;margin:.9rem 0 0;padding:.05rem .8rem .15rem}
.did>li{margin:0;padding:.55rem 0;border-bottom:1px solid var(--rule)}
.did>li:last-child{border-bottom:0}
.did p{margin:0}
.did p+p{margin-top:.15rem;font-size:.9375rem;color:var(--ink-2)}

/* Conversion strip under a result's verdict (and above the demo's join form), and the founding copy in a join block. */
.convert,.ws-cta{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.75rem 1rem;margin:1.25rem 0;padding:.9rem 1.1rem;border:2px solid var(--ink)}
.convert>span,.ws-cta>p:first-child{flex:1 1 15rem}
.ws-cta p{margin:0}
.join>h2+p{font-size:1.0625rem;font-weight:600}
.join>.spots{font-size:1.0625rem;font-weight:800;font-stretch:112%}

/* Landing, demo first: lede, then the compact sample across the page, then the join block beside the rest. */
.sample{display:grid;row-gap:1.25rem;margin:clamp(40px,6vw,72px) 0}
.sample-more{margin:0;font-weight:700;font-stretch:112%}
@media (min-width:60rem){
  .landing{grid-template-rows:auto auto auto repeat(3,auto) 1fr}
  .landing>.lede{grid-row:1}
  .landing>.sample{grid-column:1 / -1;grid-row:2;grid-template-columns:subgrid}
  .landing>.join{grid-row:3}
  .landing>.more{grid-row:3 / -1;padding-top:0}
  .sample>*{grid-column:1 / -1}
  .frame.compact{grid-template-columns:subgrid}
  .frame.compact>section{grid-column:span 4}
}
@media (min-width:60rem) and (min-height:760px){.landing:not(:has(#preorder))>.join{grid-row:3 / -1}}
/* Wide screens: the home hero's split (h1 1-8, copy 9-12), so the sample starts inside the first viewport. */
@media (min-width:75rem){
  .landing>.lede:not(.more){display:grid;grid-template-columns:subgrid;grid-template-rows:repeat(4,auto) 1fr;grid-column:1 / -1}
  .landing>.lede:not(.more)>h1{grid-column:1 / 9;grid-row:1 / -1;margin-bottom:0}
  .landing>.lede:not(.more)>:not(h1){grid-column:9 / 13}
  .landing>.lede:not(.more)>.note{margin-top:.5rem}
}

/* Read pages (demo, result): the frame's parts hang their label in 1-3 with content in 4-9, under a keyline across the
   page; the frame ends with a wide gap before the next page section; the join block bleeds off the right edge. */
.doc>.frame{margin-top:clamp(2rem,1rem + 3vw,3.5rem)}
.doc>.frame+*{margin-top:clamp(3.5rem,2rem + 5vw,6rem)}
.doc>.join{margin-top:clamp(40px,6vw,72px)}
.doc>.join>*{max-width:40rem}
.doc .join.field form button{--fill:var(--on-field);--ring:var(--on-field);--text:var(--field)}
.doc .join.field form button:hover,.doc .join.field form button:focus-visible{--fill:var(--field);--text:var(--on-field)}
@media (min-width:60rem){
  .doc>.frame,.doc>.frame>section{display:grid;grid-template-columns:subgrid;grid-column:1 / -1}
  .doc>.frame>section>*{grid-column:4 / 10}
  .doc>.frame>section>h2{grid-column:1 / 4;margin:.2rem 0 0;padding-right:1rem}
  .doc>.join{grid-column:4 / -1;margin-right:calc(-1*max(var(--gutter),(100vw - var(--page))/2));padding-left:clamp(28px,3vw,44px)}
}

/* bvl.dev cards: the sample line, and three cards in a row once the third product's card lands. */
.card .sample-line{font-weight:600;font-stretch:112%}
@media (min-width:60rem){.grid:has(>:nth-child(3))>*{grid-column:span 4}}
/* === writestop === */
/* Writestop (positioning v2.1 section C): deep teal field with white text (6.04:1) and a dark teal facet (board: red read as
   an error signal). Its sample uses the shared frame; limit verdicts are inversion, never a hue. */
body.writestop>.doc::before{content:"";display:block;width:clamp(96px,14vw,168px);height:clamp(40px,5vw,64px);margin-bottom:1.5rem;--cut:clamp(14px,1.6vw,22px);background:linear-gradient(315deg,transparent var(--cut),var(--facet) var(--cut) calc(var(--cut) + 6px),var(--field) 0)}
.ws-actions{display:flex;flex-wrap:wrap;gap:1rem;margin:1.25rem 0 0}
.writestop .button.ws-alt{--fill:var(--paper);--text:var(--ink)}
.writestop .button.ws-alt:hover,.writestop .button.ws-alt:focus-visible{--fill:var(--ink);--text:var(--paper)}
.writestop .lede>.note{margin:1.5rem 0 0}
.writestop .lede li .code{margin:.75rem 0 .75rem calc(-1*var(--step))}
.ws-why{max-width:34rem;margin:0 0 1rem;border-top:1px solid var(--rule)}
.ws-why dt{padding-top:.7rem;font-weight:800;font-stretch:118%;line-height:1.25}
.ws-why dd{margin:.3rem 0 0;padding-bottom:.7rem;border-bottom:1px solid var(--rule)}
.ws-spots{font-weight:800;font-stretch:112%}
.ws-verdict span{display:inline-block}
.ws-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:.25rem .6rem;margin:0}
.ws-head strong{font-weight:800;font-stretch:112%;overflow-wrap:anywhere}
.ws-days{margin-left:auto;font-weight:800;font-stretch:118%;font-variant-numeric:tabular-nums;white-space:nowrap}
.ws-tag{flex:none;padding:.1rem .5rem;border:2px solid var(--ink);font-size:.75rem;font-weight:800;font-stretch:118%;letter-spacing:.06em;text-transform:uppercase;line-height:1.35}
.ws-act .ws-tag{color:var(--paper);background:var(--ink)}
.ws-fine .ws-tag{border-color:var(--rule);color:var(--ink-2)}
.ws-meta{margin:.35rem 0 0;font-size:.9375rem;color:var(--ink-2);font-variant-numeric:tabular-nums}
.ws-limits details p{margin:.5rem 0 0}
.ws-since{font-size:.9375rem;color:var(--ink-2)}
.ws-unread{padding:0;list-style:none;font-size:.9375rem}
.writestop .doc>h3{margin:1.75rem 0 .5rem;font-size:1.1875rem;font-stretch:112%}
.ws-try textarea{white-space:pre;overflow-wrap:normal}
.writestop .ws-try button{--fill:var(--field);--ring:var(--ink);--text:var(--on-field)}
.writestop .ws-try button:hover,.writestop .ws-try button:focus-visible{--fill:var(--ink);--text:var(--paper)}
.ws-position{font-size:clamp(1.125rem,1rem + .5vw,1.375rem);font-weight:700;font-stretch:112%;line-height:1.35}
@media (min-width:60rem){
  body.writestop>.doc::before{grid-column:1 / 4;width:auto}
}
