/* ============================================================================
   craft/design/base.css — the starting stylesheet for a new project.
   Extracted 30.8.26 from /c/ (Contract Powers Registry), which is the first
   thing I built that Ofir called finished rather than working.

   HOW TO USE
     cp ~/workspace/craft/design/base.css   ~/projects/<name>/public/base.css
     cp -r ~/workspace/craft/design/fonts   ~/projects/<name>/public/f
     <link rel="stylesheet" href="/base.css">
     PRELOAD THE PAIR THAT CARRIES *THIS PAGE'S* SCRIPT -- exactly two, never four:
       English page:  fraunces.woff2  + jakarta.woff2
       Hebrew  page:  frankruhl-he.woff2 + heebo-he.woff2

   HEBREW IS ALREADY HANDLED. fonts/ carries frankruhl-he.woff2 (serif) and
   heebo-he.woff2 (sans) and base.css wires them by unicode-range, so a page in
   Hebrew gets the intended pairing with no extra markup.

   ⚠️ PRELOAD IS PER-LANGUAGE, AND GETTING IT BACKWARDS IS SILENT. The rule used
   to read "never preload the Hebrew faces". That was right for the reason behind
   it -- preload fetches unconditionally, so an ENGLISH page that preloads them
   pays 29KB for glyphs it has none of, and destroys the unicode-range gating that
   is the whole point. It was wrong as a blanket rule: a HEBREW page downloads them
   regardless, so not preloading them only delays them.
   Measured 31.8.26 on a scaffolded he/rtl page, 300ms simulated latency per font:
     preloading the Latin two   -> Latin 332ms, heebo-he 646ms, frankruhl-he never
     preloading the Hebrew two  -> frankruhl-he 344ms, heebo-he 345ms, Latin 367/370ms
   The face carrying the body text arrived 301ms EARLIER. The page looked identical
   in a screenshot both times, which is why it survived two shipped pages.
   The invariant that still holds: an English page must preload ZERO Hebrew faces.

   Added 31.8.26. Before it, Fraunces and Jakarta had ZERO Hebrew glyphs between
   them (checked, not guessed), so every Hebrew page silently rendered in
   whatever font the visitor happened to own -- and looked fine to me, because
   my own machine had one. This is the same failure mode as the warning above.

   ⚠️ THE FONTS ARE PER-ORIGIN. A new subdomain does NOT inherit /f/ from
   agent.zbang.net, and cross-origin webfonts need CORS. Copy the files into the
   new project. If you skip this the page silently falls back to system fonts and
   still looks fine — which is exactly why you will not notice you skipped it.
   Check a screenshot, not the CSS.

   ⚠️ ONE ACCENT. --acc must mean exactly one thing in a given project, and that
   meaning gets written down at the top of the project's own stylesheet. In /c/
   it means "a human still holds power here". Green/red were REMOVED on purpose:
   a green badge next to "source verified" invited the reader to stop reading,
   which is the exact failure the page existed to prevent. Colour that decorates
   is colour that lies.
   ========================================================================== */

@font-face{font-family:Fraunces;src:url(/f/fraunces.woff2) format("woff2");
font-weight:600;font-style:normal;font-display:swap}
@font-face{font-family:"Plus Jakarta Sans";src:url(/f/jakarta.woff2) format("woff2");
font-weight:200 800;font-style:normal;font-display:swap}

/* Hebrew. Same two roles, two faces that actually have the letters: Frank Ruhl
   Libre is the serif, Heebo is the sans. Both SIL OFL, subset to the Hebrew
   block only (10-18KB), licences beside them in fonts/.

   ⚠️ OFL section 2: "each copy contains the above copyright notice and this
   license". Serving a woff2 over the web IS distribution, so OFL-*.txt must be
   copied into the project's /f/ alongside the fonts -- "licences beside them in
   fonts/" was true of craft/ and false of everything I had deployed. Fixed
   31.8.26 in new-landing and retrofitted to control and watch.

   unicode-range is the whole trick: the browser downloads these ONLY when a
   Hebrew codepoint is on the page. An English page pays zero bytes, and its
   Latin still renders in Fraunces/Jakarta exactly as before -- the picking is
   per character, not per page.  */
@font-face{font-family:"Frank Ruhl Libre";src:url(/f/frankruhl-he.woff2) format("woff2");
font-weight:300 900;font-style:normal;font-display:swap;
unicode-range:U+0590-05FF,U+FB1D-FB4F,U+200E-200F,U+20AA}
@font-face{font-family:Heebo;src:url(/f/heebo-he.woff2) format("woff2");
font-weight:100 900;font-style:normal;font-display:swap;
unicode-range:U+0590-05FF,U+FB1D-FB4F,U+200E-200F,U+20AA}

/* ⚠️ color-scheme IS NOT COSMETIC AND ITS ABSENCE IS SILENT. Without it a dark
   page still gets Chromium's LIGHT native controls: an UNCHECKED radio renders
   as a solid white disc on the dark panel, which reads as the selected one — so
   a four-option question looks like all four are already picked. Measured on
   sign 31.8.26, on a 390px screenshot; every automated check passed. It also
   fixes the scrollbar, the textarea grip, the date picker and autofill. */
:root{
color-scheme:dark;
--bg:#0a0c14;--panel:#11141e;--panel2:#151926;--line:#212636;--edge:rgba(255,255,255,.055);
--ink:#e7eaf2;--dim:#878ea4;--acc:#e0a75e;--link:#9fb7ea;--max:940px;
--serif:Fraunces,"Frank Ruhl Libre",ui-serif,Georgia,"Times New Roman",serif;
--sans:"Plus Jakarta Sans",Heebo,ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
--mono:ui-monospace,SFMono-Regular,Menlo,"Cascadia Mono",monospace}

/* --- reset + base ------------------------------------------------------- */
*{box-sizing:border-box}html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--ink);font:400 16px/1.62 var(--sans);
overflow-wrap:break-word;-webkit-font-smoothing:antialiased;font-optical-sizing:auto}
a{color:var(--link);text-decoration:none}
a:hover{text-decoration:underline;text-underline-offset:2px}
:focus-visible{outline:2px solid var(--acc);outline-offset:2px;border-radius:3px}
code{font-family:var(--mono);font-size:.85em;font-variant-numeric:tabular-nums}
/* <bdi> is how a Hebrew page isolates a numeral from the RTL run around it, so in
   practice every inline number on these pages is inside one. The spec says numbers
   are always tabular; until now that only held inside tables and stat tiles, and
   `finish` counted 3 untreated numeric fields on control.agent.zbang.net 26.9.26. */
bdi{font-variant-numeric:tabular-nums}
.wrap{max-width:var(--max);margin:0 auto;padding:0 22px}
/* ⚠️ NOT left:-9999px. Measured 30.8.26 on the first RTL landing page: in a
   dir="rtl" document the inline axis is reversed, so an element parked 9999px to
   the LEFT is 9999px of real scrollable overflow. The page rendered 11,279px wide
   (9999 + viewport), the body collapsed into a narrow column, and NOTHING errored.
   rtl.md previously listed left:-9999px as safe-to-stay-physical. It was wrong.
   The clip technique has no direction at all, which is why it is the right one. */
.skip{position:absolute;width:1px;height:1px;overflow:hidden;
clip-path:inset(50%);white-space:nowrap}
.skip:focus{width:auto;height:auto;overflow:visible;clip-path:none;
inset-inline-start:8px;top:8px;background:var(--panel);border:1px solid var(--line);
border-radius:7px;padding:8px 12px;z-index:9}

/* --- surfaces: flat + one hairline + a lit top edge.
   The inset highlight is the whole trick. It is what makes a dark panel read as
   BUILT rather than as DIMMED. Without it the page looks like a light design
   with the brightness turned down. -------------------------------------- */
.panel,.tile,.verdict,.ok-box,.card,.cta>div{
background:var(--panel);border:1px solid var(--line);border-radius:11px;
box-shadow:inset 0 1px 0 var(--edge)}

/* --- nav ---------------------------------------------------------------- */
.topnav{border-bottom:1px solid var(--line);background:color-mix(in srgb,var(--bg) 88%,transparent);
position:sticky;top:0;z-index:5;backdrop-filter:blur(10px)}
.topnav .wrap{display:flex;align-items:center;gap:14px;height:54px;font-size:.88rem;flex-wrap:wrap}
.topnav .brand{font-family:var(--serif);font-weight:600;font-size:1.04rem;color:var(--ink);letter-spacing:.01em}
.topnav .sep{color:var(--dim)}.topnav .grow{flex:1}
.topnav a:not(.brand){color:var(--dim)}.topnav a:not(.brand):hover{color:var(--ink)}
main{padding-bottom:56px}
.crumb{font-size:.82rem;margin:24px 0 0;color:var(--dim)}

/* --- type: serif for headings ONLY, sans for everything you actually read.
   Mixing them inside body copy is what makes a page look like a template. -- */
h1{font:600 2.35rem/1.14 var(--serif);margin:.22em 0 .12em;letter-spacing:-.015em}
h2{font:600 1.32rem/1.3 var(--serif);margin:2.5em 0 .55em;letter-spacing:-.005em;scroll-margin-top:66px}
h3{font:600 1rem/1.35 var(--sans);margin:0;letter-spacing:-.005em}
.lede{font-size:1.06rem;color:var(--ink);max-width:70ch}
.note{color:var(--dim);max-width:70ch}.note b{color:var(--ink);font-weight:600}

/* --- stat tiles --------------------------------------------------------- */
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(158px,1fr));gap:12px;margin:22px 0 0}
.tile{padding:13px 15px}
.tile .k{display:block;font-size:.68rem;text-transform:uppercase;letter-spacing:.09em;
color:var(--dim);margin-bottom:3px}
.tile b{display:block;font:600 1.5rem/1.25 var(--serif);letter-spacing:-.02em;
font-variant-numeric:tabular-nums}
/* .w = the one accented state. Everything else stays neutral. */
.tile.w{border-color:color-mix(in srgb,var(--acc) 26%,var(--line))}
.tile.w b{color:var(--acc)}

/* --- callouts ----------------------------------------------------------- */
.verdict,.ok-box{padding:15px 17px;margin:0 0 8px;border-inline-start:2px solid var(--line)}
.verdict.w{border-inline-start-color:var(--acc)}

/* --- key/value table ---------------------------------------------------- */
table.kv{width:100%;border-collapse:collapse;margin:10px 0;font-size:.93rem;
font-variant-numeric:tabular-nums}
table.kv th{text-align:start;color:var(--dim);font-weight:400;width:34%;vertical-align:top;
padding-block:9px;padding-inline:0 10px;border-bottom:1px solid var(--line)}
table.kv td{padding-block:9px;padding-inline:0;border-bottom:1px solid var(--line);vertical-align:top}
table.kv.wide th{width:auto}
table.kv code,ul.ev code,.addr code{word-break:break-all}

/* --- cards -------------------------------------------------------------- */
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(258px,1fr));gap:12px;margin:14px 0}
.card{padding:15px 17px;transition:transform .16s ease,border-color .16s ease}
.card:hover{transform:translateY(-1px);border-color:color-mix(in srgb,var(--ink) 14%,var(--line))}
.card p{margin:.45em 0 .6em;color:var(--dim);font-size:.9rem}
.chead{display:flex;align-items:flex-start;gap:10px;justify-content:space-between}
.badge{font-size:.63rem;text-transform:uppercase;letter-spacing:.08em;padding:3px 8px;
border-radius:20px;white-space:nowrap;font-weight:500}
.b-dec{background:color-mix(in srgb,var(--acc) 12%,transparent);color:var(--acc);
border:1px solid color-mix(in srgb,var(--acc) 28%,transparent)}
.b-heu{background:transparent;color:var(--dim);border:1px solid var(--line)}
details{margin-top:6px}
summary{cursor:pointer;color:var(--dim);font-size:.84rem}
summary:hover{color:var(--ink)}
ul.ev{margin:.5em 0;padding-inline-start:18px;font-size:.83rem;color:var(--dim)}ul.ev li{margin:.25em 0}
.src{color:var(--dim);font-size:.8em;opacity:.8}

/* --- filter input ------------------------------------------------------- */
.filter{display:block;margin:20px 0 6px}
.filter span{display:block;font-size:.68rem;text-transform:uppercase;letter-spacing:.09em;
color:var(--dim);margin-bottom:6px}
.filter input{width:100%;max-width:340px;background:var(--panel);border:1px solid var(--line);
border-radius:9px;color:var(--ink);padding:10px 13px;font:inherit;font-size:.94rem;
box-shadow:inset 0 1px 0 var(--edge)}
.filter input::placeholder{color:var(--dim)}

/* --- data table, grouped.
   Grouping is not decoration: it writes the repeated value ONCE as a heading
   instead of N times as a cell. See craft/patterns/tables.md ---------------*/
table.reg{width:100%;border-collapse:collapse;font-size:.9rem;margin-top:8px;
font-variant-numeric:tabular-nums}
table.reg th{text-align:start;color:var(--dim);font-weight:400;font-size:.72rem;
text-transform:uppercase;letter-spacing:.08em;padding-block:10px 9px;padding-inline:0 14px;
border-bottom:1px solid var(--line);white-space:nowrap}
table.reg td{padding-block:11px;padding-inline:0 14px;border-bottom:1px solid var(--line);vertical-align:top}
table.reg tbody tr{transition:background .14s ease}
table.reg tbody tr:hover{background:var(--panel)}
table.reg td:first-child a{color:var(--ink);font-weight:500}
table.reg td:first-child a:hover{color:var(--link)}
tr.grp th{font:600 .95rem/1.3 var(--serif);color:var(--ink);text-transform:none;
letter-spacing:0;padding-block:26px 8px;padding-inline:0;border-bottom:1px solid var(--line)}
tr.grp .n{color:var(--dim);font-family:var(--sans);font-size:.72rem;font-weight:400;
text-transform:uppercase;letter-spacing:.09em;margin-inline-start:8px}
code.tiny{font-size:.72rem;color:var(--dim)}
.dim{color:var(--dim)}

/* --- empty state: says what is true, not the word "none".
   See craft/patterns/empty-and-loading.md -------------------------------- */
.empty{display:none;padding:26px 0 6px;color:var(--dim);font-size:.94rem}
.empty b{color:var(--ink);font-weight:600;font-family:var(--serif)}

/* --- skeleton: reserve the SHAPE of the answer, never the word "Loading".
   Width varies per line so it reads as text, not as three grey bars. ------ */
.sk{background:linear-gradient(90deg,var(--panel) 25%,var(--panel2) 37%,var(--panel) 63%);
background-size:400% 100%;animation:shimmer 1.4s ease infinite;border-radius:6px;
height:1em;margin:.5em 0}
.sk:nth-child(2){width:82%}.sk:nth-child(3){width:64%}.sk:nth-child(4){width:73%}
@keyframes shimmer{from{background-position:100% 0}to{background-position:0 0}}

/* --- CTA ---------------------------------------------------------------- */
.cta{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:12px;margin:32px 0 0}
.cta>div{background:var(--panel2);padding:17px 19px;
transition:transform .16s ease,border-color .16s ease}
.cta>div:hover{transform:translateY(-1px);border-color:color-mix(in srgb,var(--ink) 14%,var(--line))}
.cta p{color:var(--dim);font-size:.9rem;margin:.5em 0 0}

/* --- footer. The AI-agent disclosure lives here and is MANDATORY. -------- */
.foot{border-top:1px solid var(--line);margin-top:46px;padding-top:22px;padding-bottom:46px;font-size:.86rem}
.foot p{max-width:74ch;color:var(--dim)}.foot strong{color:var(--ink);font-weight:600}

/* --- motion you feel rather than watch: 40ms stagger, 1px lift, nothing else */
@keyframes rise{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.tiles>*,.cards>*{animation:rise .38s cubic-bezier(.2,.6,.2,1) both}
.tiles>:nth-child(2),.cards>:nth-child(2){animation-delay:40ms}
.tiles>:nth-child(3),.cards>:nth-child(3){animation-delay:80ms}
.tiles>:nth-child(4),.cards>:nth-child(4){animation-delay:120ms}
.cards>:nth-child(5){animation-delay:160ms}.cards>:nth-child(6){animation-delay:200ms}
.cards>:nth-child(7){animation-delay:240ms}.cards>:nth-child(8){animation-delay:280ms}

/* --- responsive. Both rules below came from a real phone screenshot, not
   from guessing a breakpoint. See craft/patterns/responsive.md ----------- */
@media(max-width:560px){
h1{font-size:1.72rem}.lede{font-size:1.06rem}.tile b{font-size:1.24rem}
.topnav .wrap{height:54px;gap:16px}
/* a 42-char hex has no break point, so a two-column table cannot shrink below
   it. On a phone the label/value pair STACKS instead of fighting for width. */
table.kv:not(.wide),table.kv:not(.wide) tbody,table.kv:not(.wide) tr,
table.kv:not(.wide) th,table.kv:not(.wide) td{display:block;width:100%}
table.kv:not(.wide) th{border-bottom:none;padding-block:10px 2px;padding-inline:0;font-size:.76rem;
text-transform:uppercase;letter-spacing:.07em}
table.kv:not(.wide) td{padding-block:0 12px;padding-inline:0}
/* a table with meaningful column headers must NOT stack — stacking orphans the
   values from their labels. It scrolls sideways instead. */
table.kv.wide{display:block;overflow-x:auto;white-space:nowrap}
table.reg{display:block;overflow-x:auto}}

@media(prefers-reduced-motion:reduce){
*{transition:none!important;animation:none!important}
.tiles>*,.cards>*{opacity:1;transform:none}}
