/* COPY — do not edit. The canonical file is design/site/_knowl/base.css.
 * It lives in both roots because docs is served from its own origin, so a shared absolute path
 * cannot reach it and web fonts would need CORS headers to be pulled cross-origin.
 * Refresh with:  node design/sync-base-css.mjs
 */
/* Knowl site — shared foundation.
 *
 * Everything every page needs: tokens, the segment system, the type scale, and the components
 * the motion contract in _knowl/motion.js expects to find. A page adds its own <style> for
 * what is genuinely local to it and links this for the rest.
 *
 * Lifted verbatim out of index.html when the second page arrived, because the alternative was
 * a second copy of seven hundred lines that would drift from the first within a week.
 */

@font-face{font-family:Geist;src:url("/fonts/geist-variable.woff2") format("woff2");font-weight:100 900;font-display:swap}
@font-face{font-family:"JetBrains Mono";src:url("/fonts/jetbrains-mono.woff2") format("woff2");font-weight:100 900;font-display:swap}

:root{
  /* Panels that carry sentences are effectively opaque. At 47% the constellation read straight
   * through the hero cards and sat behind the copy; anything holding a sentence has to own its
   * ground. */
  --canvas:#04121A; --panel:#081F28F5; --panel-solid:#0A1F29; --raised:#0D2733F7;
  /* ink-4 is the quietest text on the page — step numbers, unit labels, caption chips. It was
   * measured at 4.25:1 on the darkest ground, just under the 4.5 body-text floor, so it is
   * lifted until it clears. "Quiet" has a bottom. */
  --ink:#FAF8F5; --tusk:#E6FAFF; --ink-2:#A9C2CB; --ink-3:#7FA3B0; --ink-4:#85ADBC;

  /* THE PALETTE IS THE PRODUCT'S OWN. Knowl stores seven kinds of knowledge and the app already
   * gives each one a hue, at matched lightness and chroma so none shouts over the others
   * (web/app/globals.css). Using them here means colour on this page means something: a chip
   * tinted 295 is an architecture fact, not decoration. It also gets us off one aqua without
   * inventing a second brand. */
  --cat-constraint:oklch(.76 .125 25);    /* red    — what may not happen */
  --cat-decision:  oklch(.76 .125 95);    /* amber  — what was settled */
  --cat-goal:      oklch(.76 .125 140);   /* green  — what is intended */
  --cat-fact:      oklch(.76 .125 195);   /* cyan   — what is true */
  --cat-state:     oklch(.76 .125 250);   /* blue   — what is so right now */
  --cat-arch:      oklch(.76 .125 295);   /* violet — how it is put together */
  --cat-skill:     oklch(.76 .125 340);   /* magenta— what was learned to do */

  --accent:#4FD8E8; --accent-deep:#0A6B7A; --mint:#7FE3C0; --gold:#F2E2C4;
  /* Two gradients, both walking the same wheel the categories sit on, so they read as the
   * palette rather than as an effect laid over it. */
  --sweep:linear-gradient(96deg,var(--cat-fact),var(--cat-goal) 38%,var(--cat-decision) 72%,var(--cat-skill));
  --sweep-cool:linear-gradient(96deg,var(--cat-arch),var(--cat-state) 42%,var(--cat-fact));
  --hair:#78BECD29; --hair-soft:#78BECD17;
  --mono:"JetBrains Mono",ui-monospace,monospace;
  --shell:1280px; --pad:96px;
  --d1:clamp(3rem,7.4vw,7rem); --d2:clamp(2rem,3.9vw,3.5rem); --d3:1.45rem;
  --ease:cubic-bezier(.2,.6,.2,1);
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{margin:0;background:transparent;color:var(--ink);
  font-family:Geist,ui-sans-serif,system-ui,sans-serif;font-size:16px;line-height:1.5;
  -webkit-font-smoothing:antialiased;overflow-x:hidden}
a{color:inherit;text-decoration:none}
h1,h2,h3,h4,p,figure,ul,ol{margin:0}
ul,ol{padding:0;list-style:none}
img{max-width:100%;display:block}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}

.shell{max-width:var(--shell);margin:0 auto;padding:0 var(--pad);position:relative;z-index:1}
@media (max-width:900px){:root{--pad:24px}}

/* ── fixed sky ─────────────────────────────────────────────────────────── */
/* The fixed ambient layers fade out as the page commits to a flat colour. --ambient is driven
 * by motion.js on the same curve as the stage, so they leave exactly as the colour arrives
 * rather than popping at a section edge. */
.sky{position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:calc(var(--ambient,1) * .5);
  background:radial-gradient(1200px 760px at 76% 8%,#4FD8E81A,transparent 62%),
             radial-gradient(940px 640px at 12% 62%,#7FE3C012,transparent 60%)}
/* Scroll-driven ambient wash, painted by motion.js. It sits above the sections so the drift
 * reaches the whole page, and blends rather than covers so copy keeps its contrast. */
.drift{position:fixed;inset:0;z-index:3;pointer-events:none;mix-blend-mode:soft-light;
  transition:opacity .5s linear}
@media (prefers-reduced-motion:reduce){.drift{display:none}}
.stars{position:fixed;inset:0;z-index:0;pointer-events:none;opacity:var(--ambient,1)}
.stars i{position:absolute;border-radius:50%;background:#CFE6EC;animation:tw 4.5s var(--ease) infinite}
@keyframes tw{0%,100%{opacity:.12}50%{opacity:.8}}

/* ── nav ───────────────────────────────────────────────────────────────── */
/* Transparent, and it gets out of the way. Hidden while you scroll down, back the instant you
 * scroll up — the bar is only wanted when you are looking for it.
 *
 * A scrim rather than a panel: once off the top it fades the current ground colour down from the
 * top edge, which keeps the bar feeling transparent while guaranteeing the labels have something
 * to sit on. --nav-ground is the live stage colour, so the scrim is the page's own colour rather
 * than a fixed dark that would be a slab across the white segment. */
.nav{position:sticky;top:0;z-index:40;background:transparent;
  transition:transform .34s var(--ease),opacity .24s linear}
.nav::before{content:"";position:absolute;inset:0;z-index:-1;opacity:0;transition:opacity .3s;
  background:linear-gradient(180deg,var(--nav-ground,#04121A) 18%,transparent);
  -webkit-mask-image:linear-gradient(180deg,#000 55%,transparent);
  mask-image:linear-gradient(180deg,#000 55%,transparent)}
.nav[data-stuck="true"]::before{opacity:.92}
.nav[data-hidden="true"]{transform:translateY(-100%);opacity:0}
/* Never hide the bar while something inside it has keyboard focus, or tabbing into the page
 * moves focus to a control that has just slid off screen. */
.nav:focus-within{transform:none!important;opacity:1!important}

/* On the light segments the bar inverts, because transparent means the ground decides. */
:root[data-ground="light"] .nav-links button,
:root[data-ground="light"] .nav-links a,
:root[data-ground="light"] .nav-right .lnk{color:#3B525E}
:root[data-ground="light"] .nav-links button:hover,
:root[data-ground="light"] .nav-links a:hover,
:root[data-ground="light"] .nav-right .lnk:hover{color:#05121A}
/* The lockup is white type with an aqua mark; on paper the white half disappears. No filter can
 * recolour one half selectively, so the whole thing is darkened — the mark reads as deep teal
 * and the type as near-black, which keeps the shape and loses only the brightness. */
:root[data-ground="light"] .mark img{filter:brightness(.28) saturate(1.5)}
.nav-in{display:flex;align-items:center;height:83px;gap:38px}
.mark img{width:126px}
.nav-links{display:flex;gap:34px;font-size:16px;color:var(--ink-2)}
.nav-links button,.nav-links a{display:flex;align-items:center;gap:7px;transition:color .2s}
.nav-links button:hover,.nav-links a:hover{color:var(--ink)}
.nav-right{margin-left:auto;display:flex;align-items:center;gap:22px}
.mob{display:none}

.btn{display:inline-flex;align-items:center;gap:9px;padding:12px 24px;border-radius:999px;
  font-size:16px;font-weight:500;transition:filter .2s,transform .2s,background .2s;white-space:nowrap}
.btn-p{color:#04121A;background:linear-gradient(96deg,#4FD8E8,#7FE3C0)}
.btn-p:hover{filter:brightness(1.08);transform:translateY(-1px)}
.btn-l{color:#04121A;background:var(--tusk)}
.btn-l:hover{filter:brightness(1.05);transform:translateY(-1px)}
/* The ghost button takes the segment's ink, not the dark-theme ink. Pinned to --ink it was white
 * on white in the light segments — a button you can only find by hovering. */
.btn-g{border:1px solid var(--hair);color:var(--seg-head,var(--ink))}
.btn-g:hover{background:color-mix(in srgb,currentColor 8%,transparent)}
.lnk{display:inline-flex;align-items:center;gap:8px;color:var(--ink-2);transition:color .2s}
.lnk:hover{color:var(--accent)}

/* glow button — motion.js spins .border-glow and opens the spread on hover */
.glow-button{position:relative;isolation:isolate;--glow-half-spread:10}
.glow-button .border-glow{position:absolute;inset:-2px;border-radius:inherit;z-index:-1;
  background:conic-gradient(from 0deg,transparent,var(--accent) calc(var(--glow-half-spread)*1deg),
    transparent calc(var(--glow-half-spread)*2deg));filter:blur(3px);opacity:.85}

/* ── type ──────────────────────────────────────────────────────────────── */
h1{font-size:var(--d1);line-height:.92;font-weight:500;letter-spacing:-.028em}
h2{font-size:var(--d2);line-height:1.04;font-weight:500;letter-spacing:-.022em;color:var(--tusk)}
h3{font-size:var(--d3);line-height:1.25;font-weight:500;letter-spacing:-.01em}
.lede{font-size:21px;line-height:1.4;font-weight:350;color:var(--ink-2)}
/* Eyebrows take their section's hue, so the label tells you which register you are in before
 * you read it. Defaults to the fact cyan when a section does not set one. */
.eyebrow{display:inline-flex;align-items:center;gap:9px;
  font-family:var(--mono);font-size:12px;font-weight:500;letter-spacing:.16em;
  text-transform:uppercase;color:var(--hue,var(--cat-fact))}
.eyebrow::before{content:"";width:20px;height:1px;background:currentColor;opacity:.7}
.grad{background:var(--sweep);
  -webkit-background-clip:text;background-clip:text;color:transparent}

/* ── segments ──────────────────────────────────────────────────────────────
 * The page moves through light instead of sitting at one level, so you can tell you have
 * crossed into a new argument before reading a word. The arc is deliberate and follows the
 * mascot: slate body, aqua beak, and goggles that run violet to blue to cyan to gold.
 *
 *   night  void   rise   steel   dawn   DAY   jade   ash   dusk   night
 *   hero → problem → promise → adapters → before/after → lifecycle → proof → plans → faq → close
 *
 * void is the darkest point and sits under the problem, day is full light and sits under the
 * governance story -- the two ends of the argument get the two ends of the range.
 *
 * Each segment paints itself and fades to transparent at both edges, so neighbours cross-fade
 * through the body rather than butting against a hard line. Every one carries corner glows in
 * its own hue. Tokens are re-declared per segment, which is what lets the light segment flip
 * text to dark without a single overriding rule anywhere else.
 */
.band{position:relative;padding:150px 0;isolation:isolate;
  color:var(--seg-ink,var(--ink));
  --hair:var(--seg-hair,#78BECD29); --hair-soft:var(--seg-hair-soft,#78BECD17);
  --panel:var(--seg-panel,#081F28F5); --raised:var(--seg-raised,#0D2733F7)}
.band .lede,.band .ev-meta,.band .card p{color:var(--seg-ink-2,var(--ink-2))}
.band h2,.band h3,.band .client-name,.band .ev-claim{color:var(--seg-head,var(--tusk))}

/* THE STAGE OWNS THE BACKGROUND, not the sections.
 * Sections used to paint their own strip and cross-fade at the edges, which is what made some
 * joins look like joins: two gradients meeting, each with its own idea of where the seam was.
 * One fixed layer now holds the whole screen and motion.js drives its colour, so entering a
 * segment turns the entire viewport that colour -- black is black edge to edge, white is white
 * edge to edge -- and the only place any blending happens is the seam itself. */
.stage{position:fixed;inset:0;z-index:-2;pointer-events:none;background:#04121A}
/* Sections no longer paint a ground; only the slab does, because a hard cut is a thing you
 * draw, not a colour you arrive at. */
/* and its corner light — two opposed pools, never centred, so the eye keeps moving down */
.band::after,.hero-wrap::after{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:var(--seg-glow,none);
  mask-image:linear-gradient(180deg,transparent,#000 16%,#000 84%,transparent);
  -webkit-mask-image:linear-gradient(180deg,transparent,#000 16%,#000 84%,transparent)}
/* The hero's ground starts hard at the nav rather than fading in — there is nothing above it
 * to cross-fade with, and a fade there just looks like a rendering fault. */
.hero-wrap{isolation:isolate;padding-bottom:40px}
.hero-wrap::before{mask-image:linear-gradient(180deg,#000 80%,transparent);
  -webkit-mask-image:linear-gradient(180deg,#000 80%,transparent)}

.seg-night{--seg-bg:linear-gradient(180deg,#04121A,#061A24 60%,#04121A);
  --seg-glow:radial-gradient(760px 420px at 82% 6%,#4FD8E82E,transparent 66%),
             radial-gradient(680px 400px at 10% 88%,#A78BFA1F,transparent 64%)}
/* Full black. Not near-black -- the problem section is the bottom of the argument and the page
 * should go all the way there, so the only light in the viewport is the copy and two embers. */
.seg-void{--seg-bg:#000000;
  --seg-glow:radial-gradient(700px 380px at 14% 12%,#E8794C22,transparent 64%),
             radial-gradient(620px 360px at 88% 82%,#4FD8E818,transparent 62%)}
.seg-rise{--seg-bg:linear-gradient(180deg,#01060B,#0B1830 55%,#101A33);
  --seg-glow:radial-gradient(820px 440px at 88% 10%,#A78BFA33,transparent 66%),
             radial-gradient(700px 400px at 6% 86%,#60A5FA26,transparent 64%)}
.seg-steel{--seg-bg:linear-gradient(180deg,#101A33,#16283C 50%,#1A3042);
  --seg-glow:radial-gradient(780px 420px at 12% 14%,#60A5FA2E,transparent 64%),
             radial-gradient(700px 400px at 90% 84%,#4FD8E826,transparent 62%)}
/* Dawn was a mid-grey at #4A4B42, which is the worst place to put light text — too dark for
 * dark type, too light for light. Dropped until the copy on it clears 4.5:1 with room to spare.
 * It still reads as the warm step between steel and daylight, just from below rather than
 * halfway. */
.seg-dawn{--seg-bg:#33362F;
  --seg-glow:radial-gradient(860px 460px at 84% 12%,#F2C46A38,transparent 66%),
             radial-gradient(720px 420px at 8% 88%,#E8794C26,transparent 62%)}

/* The full-light segment. Tokens are redeclared rather than patched, so every component inside
 * inherits a legible palette instead of needing a light-mode variant of its own. */
/* And full white at the other end. Paper, not off-white: the governance story is the part that
 * has to feel like a document. */
.seg-day{--seg-bg:#FBFAF7;
  --seg-glow:radial-gradient(820px 440px at 88% 14%,#4FD8E82E,transparent 62%),
             radial-gradient(740px 420px at 6% 86%,#A78BFA26,transparent 60%);
  --seg-ink:#0C1A22; --seg-ink-2:#39505C; --seg-head:#05121A;
  --seg-hair:#0C1A2226; --seg-hair-soft:#0C1A2214;
  --seg-panel:#FFFFFFD9; --seg-raised:#FFFFFFF2;
  /* The category hues are tuned to sit on a dark ground at L .76. On paper they are washes.
   * Same hue, same meaning, dropped to a lightness that carries — so an amber label is still
   * the amber label, and still readable. */
  --cat-constraint:oklch(.52 .16 25);  --cat-decision:oklch(.50 .13 95);
  --cat-goal:oklch(.46 .13 140);       --cat-fact:oklch(.49 .12 195);
  --cat-state:oklch(.50 .14 250);      --cat-arch:oklch(.50 .16 295);
  --cat-skill:oklch(.52 .16 340)}
.seg-day .ev-when,.seg-day .client-name+code,.seg-day .adapter code{color:#4C6472}
.seg-day .adapter img{filter:none;opacity:.9}

/* MIST — the light segment for things you read rather than admire.
 * Paper white is right for a single dramatic beat and wrong for a pricing table: at #FBFAF7 a
 * grid of cards is a wall of glare. This sits a long way down from white while staying firmly a
 * light segment, so the same dark tokens apply and white cards lift off it instead of vanishing
 * into it. Everything below the background is shared with seg-day. */
.seg-mist{--seg-bg:#C7CDD0;
  --seg-glow:radial-gradient(880px 460px at 86% 14%,#4FD8E82A,transparent 62%),
             radial-gradient(760px 430px at 8% 86%,#A78BFA22,transparent 60%)}
.seg-mist,.seg-day{
  --seg-ink:#0C1A22; --seg-ink-2:#39505C; --seg-head:#05121A;
  --seg-hair:#0C1A2226; --seg-hair-soft:#0C1A2214;
  --seg-panel:#FFFFFFD9; --seg-raised:#FFFFFFF2;
  /* The category hues are tuned to sit on a dark ground at L .76. On paper they are washes.
   * Same hue, same meaning, dropped to a lightness that carries. */
  --cat-constraint:oklch(.52 .16 25);  --cat-decision:oklch(.50 .13 95);
  --cat-goal:oklch(.46 .13 140);       --cat-fact:oklch(.49 .12 195);
  --cat-state:oklch(.50 .14 250);      --cat-arch:oklch(.50 .16 295);
  --cat-skill:oklch(.52 .16 340)}
.seg-mist .plate{display:none}

/* A slab cuts, so its ground starts at full dark on the first pixel. Ramping in from the
 * segment above would turn the hard edge back into the fade it exists to avoid. */
.seg-jade{--seg-bg:linear-gradient(180deg,#0A2019,#07171A 55%,#051218);
  --seg-glow:radial-gradient(800px 440px at 10% 12%,#7FE3C033,transparent 64%),
             radial-gradient(700px 400px at 90% 86%,#4FD8E822,transparent 62%)}
.seg-ash{--seg-bg:linear-gradient(180deg,#051218,#1C1F24 48%,#212429);
  --seg-glow:radial-gradient(820px 440px at 86% 12%,#F09BC833,transparent 64%),
             radial-gradient(700px 400px at 10% 86%,#A78BFA1F,transparent 62%)}
.seg-dusk{--seg-bg:linear-gradient(180deg,#212429,#0A141C 55%,#06111A);
  --seg-glow:radial-gradient(720px 400px at 16% 14%,#60A5FA1F,transparent 62%),
             radial-gradient(660px 380px at 86% 84%,#4FD8E81A,transparent 60%)}

/* Not every boundary should dissolve. Where the argument turns, the next segment arrives as a
 * slab: hard top edge, rounded shoulders, inset so the segment above shows past it. You have
 * entered somewhere rather than drifted there. Used once — after the light segment, where the
 * page goes from the governance story to the evidence — so it reads as a decision, not a motif.
 * The slab needs the segment above it to stay solid all the way down to the cut, or the hard
 * edge lands on a gap where that segment had already faded out. */
.seg-slab::before{content:"";position:absolute;inset:0 clamp(0px,2.2vw,30px);z-index:-1;
  border-radius:38px 38px 0 0;background:var(--seg-bg);
  mask-image:linear-gradient(180deg,#000 86%,transparent);
  -webkit-mask-image:linear-gradient(180deg,#000 86%,transparent)}
.seg-slab::after{inset:0 clamp(0px,2.2vw,30px);border-radius:38px 38px 0 0}
.seg-slab{padding-top:170px}

/* COMMITTED SEGMENTS ARE EXACTLY ONE COLOUR.
 * Fully black with a nebula in the corner is not fully black, it is a dark section with a
 * nebula in it. Inside these two, every ambient layer is switched off at source -- the section
 * plate, the corner glow, and (via --ambient, driven by motion.js) the starfield and the drift
 * wash, which are fixed and so cannot be reached from here. */
.seg-void .plate,.seg-day .plate{display:none}
.seg-void::after,.seg-day::after{display:none}

.band-hair{border-top:1px solid var(--hair)}
.plate{position:absolute;inset:0;z-index:0;background-size:cover;background-position:50% 45%;
  opacity:.42;mask-image:linear-gradient(180deg,transparent,#000 24%,#000 72%,transparent);
  -webkit-mask-image:linear-gradient(180deg,transparent,#000 24%,#000 72%,transparent)}
.center{text-align:center}
.center h2,.center .lede{margin-inline:auto}
.mw-h2{max-width:19ch}
.mw-p{max-width:60ch}

/* ── hero ──────────────────────────────────────────────────────────────── */
/* clip, not hidden: the plate is deliberately wider than the viewport so its wings leave the
 * frame, and without this that overhang becomes a horizontal scrollbar on narrow screens.
 * overflow-x:clip cuts the overhang without making this a scroll container, which `hidden`
 * would, and which would break position:sticky on the nav above it. */
.hero-wrap{position:relative;overflow-x:clip}
/* The constellation owl sits behind the headline, full-bleed and wider than the shell so its
 * wingtips run off both edges rather than sitting in a box. The plate is painted on black, so
 * screen blending is what makes it work: black contributes nothing and the lit nodes add over
 * the canvas, which means no rectangle edge and no cutout to maintain. The radial mask fades
 * the far corners so the wings dissolve instead of stopping. */
.hero-sky{position:absolute;left:50%;top:150px;transform:translateX(-50%);
  width:min(1420px,128vw);aspect-ratio:1200/886;z-index:0;pointer-events:none;
  background:url("/_atmos-art/node-owl-sparse-01.webp") 50% 50%/contain no-repeat;
  /* Screen blending drops the plate's black ground, which also drops its contrast -- so the
   * nodes get it back explicitly rather than by turning opacity up, which would lift the murk
   * along with them. */
  mix-blend-mode:screen;opacity:.92;filter:brightness(1.5) saturate(1.25) contrast(1.1);
  /* Two masks, doing different jobs. The radial dissolves the wingtips so they run out of the
   * frame instead of ending. The linear cuts the top, keeping the lit nodes out from behind the
   * headline and sub -- copy over texture is the one thing this palette cannot afford. */
  mask-image:radial-gradient(ellipse 60% 58% at 50% 50%,#000 42%,transparent 78%),
             linear-gradient(180deg,transparent 18%,#000 38%,#000 58%,transparent 72%);
  -webkit-mask-image:radial-gradient(ellipse 60% 58% at 50% 50%,#000 42%,transparent 78%),
             linear-gradient(180deg,transparent 18%,#000 38%,#000 58%,transparent 72%);
  mask-composite:intersect;-webkit-mask-composite:source-in}
@media (max-width:900px){.hero-sky{opacity:.8;width:180vw;top:120px}}
.hero{padding:110px 0 0;text-align:center}
.hero h1{max-width:14ch;margin:0 auto}
.hero .lede{margin:28px auto 0;max-width:58ch}
.hero .lede b{color:var(--ink);font-weight:500}
.cta-row{display:flex;gap:14px;justify-content:center;margin-top:40px;flex-wrap:wrap}

/* A TERMINAL, NOT A CODE STRIP.
 * The steps are the window's tabs, which is the one place a tab metaphor is literally true
 * rather than decorative: you really do run these in order, in a shell, in this repo. The
 * window keeps its own ground — darker than any segment — so it reads as an application sitting
 * on the page rather than a panel cut out of it.
 *
 * The margin is the gap the constellation lives in. It is large on purpose: the plate needs
 * open canvas between the call to action and the window, or its wings read as clutter. */
.tabs{margin-top:250px;text-align:left}
/* Narrower than the shell. A terminal that runs the full page width reads as a band; at this
 * measure it reads as a window someone opened, and the commands stop looking lost in it. */
.term{max-width:860px;margin-inline:auto;
  border:1px solid var(--hair);border-radius:14px;background:#030C12;overflow:hidden;
  box-shadow:0 34px 90px -34px #000000cc}
.term-bar{display:flex;align-items:stretch;background:#071720;border-bottom:1px solid var(--hair-soft)}
.lights{display:flex;align-items:center;gap:8px;padding:0 18px;flex:none}
.lights i{width:11px;height:11px;border-radius:50%;background:#22343D}
.term-tabs{display:flex;flex:1;min-width:0;overflow-x:auto;scrollbar-width:none}
.term-tabs::-webkit-scrollbar{display:none}
.tab{display:flex;align-items:center;gap:10px;white-space:nowrap;position:relative;
  padding:15px 22px;font-size:14.5px;color:var(--ink-3);
  border-right:1px solid var(--hair-soft);transition:color .2s,background .2s}
.tab:hover{color:var(--ink-2);background:#0B1F2A}
/* The step number is the structure: an ordered sequence, and you cannot do 03 first. */
.tab .step{font-family:var(--mono);font-size:11.5px;letter-spacing:.08em;color:var(--ink-4);
  transition:color .2s}
/* The selected tab joins the body below it. Cutting the divider away underneath is what makes a
 * tab read as attached to its pane rather than as a button sitting above one. */
.tab[aria-selected="true"]{color:var(--tusk);background:#030C12;margin-bottom:-1px;padding-bottom:16px}
.tab[aria-selected="true"] .step{color:var(--cat-fact)}
.tab[aria-selected="true"]::before{content:"";position:absolute;left:0;right:0;top:0;height:2px;
  background:var(--sweep)}
.tab:focus-visible{outline:2px solid var(--cat-fact);outline-offset:-3px}
.term-body{padding:20px 24px 22px;font-family:var(--mono);font-size:14px;line-height:1.75;
  overflow-x:auto}
.cwd{font-size:12px;letter-spacing:.04em;color:var(--ink-4);margin-bottom:10px}
/* The rows stay inline and the newlines inside <pre> do the breaking. Making them block as well
 * gives every row two breaks and double-spaces the session — and in a terminal, line spacing is
 * most of what makes it read as one. */
.term-body pre{margin:0;white-space:pre;color:var(--ink-2)}
.term-body .ln{color:var(--tusk)}
.term-body .pr{color:var(--cat-goal);user-select:none;margin-right:7px}
.term-body .out{color:var(--ink-4)}
.term-body b{color:var(--cat-fact);font-weight:500}
.cursor{display:inline-block;width:8px;height:15px;margin-top:3px;background:var(--cat-fact);
  animation:blink 1.15s steps(1) infinite}
@keyframes blink{0%,49%{opacity:1}50%,100%{opacity:0}}
@media (prefers-reduced-motion:reduce){.cursor{animation:none;opacity:.65}}
.tag{font-family:var(--mono);font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;
  padding:5px 9px;border-radius:6px;background:#78BECD1A;color:var(--ink-3)}
.copy{flex:none;align-self:center;width:34px;height:34px;margin:0 12px;
  border:1px solid var(--hair-soft);border-radius:9px;
  display:grid;place-items:center;color:var(--ink-4);transition:color .2s,border-color .2s}
.copy:hover{color:var(--cat-fact);border-color:#4FD8E84D}
.hidden{display:none!important}
.install{margin-top:26px;font-size:16px;color:var(--ink-3);text-align:center}
.install b{color:var(--ink-2);font-weight:500}

/* ── problem beats ─────────────────────────────────────────────────────── */
.beats{display:grid;gap:26px;max-width:74ch;margin:56px auto 0}
.beat{display:flex;gap:18px;align-items:baseline;font-size:19px;line-height:1.5;color:var(--ink-2)}
.beat i{flex:none;width:7px;height:7px;border-radius:50%;background:var(--accent);
  transform:translateY(-3px);opacity:.85}
.beat b{color:var(--ink);font-weight:500}
.rest{margin:70px auto 0;width:min(420px,60vw)}
/* The standing owl holds a K up. It belongs beside the invitation, not floating in a band of
 * its own — sized so it reads as a character in the scene rather than an illustration of it. */
.perch{margin:58px auto 0;width:min(260px,34vw)}

/* ── cards ─────────────────────────────────────────────────────────────── */
.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:64px}
.card{border:1px solid var(--hair-soft);border-radius:20px;background:var(--panel);padding:32px 28px;
  display:flex;flex-direction:column}
.card p{margin-top:12px;font-size:16.5px;line-height:1.55;color:var(--ink-3)}
/* Each card is a different promise, so each takes the hue of the category it is about:
 * checkable is a fact, staying local is a constraint, going out of date is the goal. */
.quote{margin-top:auto;padding:14px 16px;border-left:2px solid var(--hue,var(--accent));
  border-radius:0 10px 10px 0;background:#061A2399;
  font-family:var(--mono);font-size:12.5px;line-height:1.5;color:var(--ink-2)}
.card .quote{margin-top:22px}
.card h3{color:var(--tusk)}
.card::before{content:"";display:block;width:34px;height:3px;border-radius:2px;margin-bottom:18px;
  background:var(--hue,var(--accent))}

/* ── adapters ──────────────────────────────────────────────────────────── */
.adapters{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:56px}
.adapter{display:grid;grid-template-columns:26px 1fr;grid-template-areas:"logo name" "logo cmd" ". cap";
  gap:4px 14px;align-items:center;padding:22px 24px;
  border:1px solid var(--hair-soft);border-radius:16px;background:var(--panel);
  transition:border-color .2s,transform .2s}
.adapter:hover{border-color:color-mix(in oklch,var(--cat-fact) 45%,transparent);transform:translateY(-2px)}
/* Vendor marks are flattened to one weight of white. A logo wall that keeps every brand's own
 * colour reads as a sponsor list; monochrome makes it read as a compatibility list, which is
 * what it is. */
.adapter img{grid-area:logo;width:26px;height:26px;object-fit:contain;
  filter:brightness(0) invert(1);opacity:.82}
.client-glyph{grid-area:logo;width:26px;height:26px;display:grid;place-items:center;
  border:1px dashed var(--hair);border-radius:7px;color:var(--ink-4);font-size:15px}
.client-name{grid-area:name;font-size:17px;font-weight:500;color:var(--tusk)}
/* min-width:0 because a grid item's default min-width:auto refuses to shrink below its content,
 * and `knowl init claude-desktop` is wider than a narrow column -- which is how this grid pushed
 * the whole page sideways rather than wrapping. */
.adapter code{grid-area:cmd;min-width:0;overflow-wrap:anywhere;
  font-family:var(--mono);font-size:12.5px;color:var(--ink-3)}
.cap{grid-area:cap;justify-self:start;margin-top:8px;font-family:var(--mono);font-size:10px;
  letter-spacing:.1em;text-transform:uppercase;padding:4px 8px;border-radius:5px;
  background:#78BECD14;color:var(--ink-4)}
/* Hooks are the meaningful difference between these rows, so they get the colour. */
.cap-hooks{background:color-mix(in oklch,var(--cat-goal) 18%,transparent);
  color:color-mix(in oklch,var(--cat-goal) 82%,white)}
.adapter-any{border-style:dashed;background:transparent}

/* ── split ─────────────────────────────────────────────────────────────── */
.split{display:grid;grid-template-columns:1fr 1fr;gap:80px;align-items:start}
.checks{display:flex;flex-direction:column;gap:28px}
.check{display:flex;gap:18px;align-items:flex-start;font-size:21px;line-height:1.35}
.check svg{flex:none;margin-top:5px;color:var(--ink-4)}

/* ── before / after ────────────────────────────────────────────────────── */
/* Paired rows, not a two-column table: the pairing is the argument, so each row is one unit and
 * the "after" is visually the answer to the line directly above it rather than a parallel column
 * you have to scan across. */
/* Two states, so two colours — not a spectrum. The rainbow edge that was here made every row
 * look equally weighted; the point is that one side is being left behind. The old artifact is
 * muted and the new one carries the accent, and the arrow is the only bright thing between them. */
.swaps{display:grid;gap:14px;margin-top:60px;max-width:1000px}
.swap{display:grid;grid-template-columns:1fr 44px 1fr;align-items:center;gap:8px;
  padding:24px 30px;border-radius:16px;
  border:1px solid var(--hair-soft);background:var(--panel);
  transition:border-color .2s,transform .2s}
.swap:hover{border-color:color-mix(in oklch,var(--cat-goal) 38%,transparent);transform:translateY(-1px)}
.was,.now{display:grid;gap:5px;min-width:0}
.was b,.now b{font-size:19px;font-weight:500;letter-spacing:-.012em;line-height:1.25}
.was span,.now span{font-size:15px;line-height:1.45}
.was b{color:var(--seg-ink-2,var(--ink-3))}
.was span{color:var(--seg-ink-2,var(--ink-4));opacity:.8}
.now b{color:var(--seg-head,var(--tusk))}
.now span{color:var(--seg-ink-2,var(--ink-3))}
.arr{justify-self:center;font-size:19px;line-height:1;color:var(--cat-goal);opacity:.9}
@media (max-width:760px){
  .swap{grid-template-columns:1fr;gap:12px;padding:22px 24px}
  /* the arrow turns down when the columns stack, or it points at nothing */
  .arr{justify-self:start;transform:rotate(90deg)}
}

/* ── fact lifecycle ────────────────────────────────────────────────────── */
/* An ordered list on a spine. The order is the argument -- these are four states of the same
 * claim, and each row's hue is the knowledge category it belongs to, so the colour is carrying
 * meaning rather than variety. */
.life{counter-reset:ev;margin:64px auto 0;max-width:900px;text-align:left;position:relative}
.life::before{content:"";position:absolute;left:15px;top:14px;bottom:14px;width:2px;border-radius:2px;
  /* the spine runs through the same four hues the events carry, in the same order */
  background:linear-gradient(180deg,var(--cat-fact),var(--cat-decision) 34%,var(--cat-goal) 66%,var(--cat-arch))}
.ev{position:relative;padding:0 0 42px 56px}
.ev:last-child{padding-bottom:0}
.ev::before{content:"";position:absolute;left:8px;top:7px;width:16px;height:16px;border-radius:50%;
  background:var(--hue);box-shadow:0 0 0 4px var(--canvas),0 0 18px color-mix(in oklch,var(--hue) 70%,transparent)}
.ev-when{font-family:var(--mono);font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--ink-4)}
.ev-what{margin-left:12px;font-family:var(--mono);font-size:11.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--hue)}
.ev-claim{margin-top:12px;font-size:22px;line-height:1.3;font-weight:500;letter-spacing:-.012em;
  color:var(--tusk)}
/* The answer is the payload, so it is set apart from the prose around it: indented behind a
 * rule, in the product's own vocabulary, with the metadata as chips rather than a sentence. */
.ev-answer{display:flex;flex-wrap:wrap;align-items:baseline;gap:10px 14px;margin-top:12px;
  padding:12px 0 12px 16px;border-left:2px solid var(--hue)}
.ev-answer .a{font-size:19px;font-weight:500;color:var(--seg-head,var(--tusk))}
.chips{display:flex;flex-wrap:wrap;gap:7px}
.chip{font-family:var(--mono);font-style:normal;font-size:10.5px;letter-spacing:.08em;
  text-transform:uppercase;padding:4px 9px;border-radius:5px;
  background:color-mix(in oklch,var(--hue) 16%,transparent);
  color:color-mix(in oklch,var(--hue) 78%,var(--seg-head,white))}
.ev-meta{margin-top:12px;font-size:16px;line-height:1.55;color:var(--seg-ink-2,var(--ink-3));max-width:62ch}
/* Emphasis has to be stronger than the text around it in BOTH directions. Pinning it to a
 * dark-segment token made it lighter than its own body copy on the light segment, which is
 * where the emphasised terms were disappearing into the paper. */
.ev-meta b,.lede b,.beat b,.install b{color:var(--seg-head,var(--ink));font-weight:500}


/* ── proof bars ────────────────────────────────────────────────────────── */
.bars{display:flex;flex-direction:column;gap:22px;margin-top:56px}
.bar-row{display:grid;grid-template-columns:1fr;gap:10px}
.src{border-bottom:1px solid color-mix(in oklch,var(--cat-goal) 50%,transparent);
  color:var(--seg-ink-2,var(--ink-2));transition:color .2s,border-color .2s}
.src:hover{color:var(--cat-goal);border-bottom-color:var(--cat-goal)}
.bar-label{display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  font-size:16px;color:var(--ink-2)}
.bar-label b{font-family:var(--mono);font-size:19px;color:var(--ink);font-weight:500}
.bar{height:12px;border-radius:999px;background:#78BECD1A;overflow:hidden}
.bar span{display:block;height:100%;border-radius:999px;background:var(--sweep);
  transform-origin:left;transform:scaleX(0);transition:transform 1.1s var(--ease)}
.bar.on span{transform:scaleX(1)}
/* The comparisons are deliberately colourless. Only our own result earns the palette; giving
 * the baselines a hue would make them look like alternatives rather than the thing being beaten. */
.bar.dim span{background:#78BECD3D}
.note{margin-top:34px;font-size:14.5px;line-height:1.6;color:var(--ink-4);max-width:78ch}
.caveat{margin-top:22px;padding:20px 24px;border:1px solid var(--hair-soft);border-radius:14px;
  background:var(--panel);font-size:16px;line-height:1.6;color:var(--ink-2);max-width:78ch}

/* ── plans ─────────────────────────────────────────────────────────────── */
.plans{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:60px}
.plan{border:1px solid var(--hair-soft);border-radius:20px;background:var(--panel);padding:34px 30px;
  display:flex;flex-direction:column}
.plan.on{border-color:#4FD8E86B;background:var(--raised)}
.plan .name{font-size:18px;font-weight:500;color:var(--tusk)}
.plan .fig{margin-top:16px;font-size:44px;font-weight:500;line-height:1;letter-spacing:-.03em}
.plan .per{margin-top:8px;font-size:14.5px;color:var(--ink-4)}
.plan .who{margin-top:18px;font-size:16px;line-height:1.5;color:var(--ink-3);min-height:3em}
.plan ul{margin:24px 0 30px;display:flex;flex-direction:column;gap:11px;font-size:15.5px;color:var(--ink-2)}
.plan li{display:flex;gap:10px}
.plan li::before{content:"—";color:var(--ink-4)}
.plan .btn{margin-top:auto;justify-content:center}
.plans-note{margin-top:26px;font-size:16px;color:var(--ink-3);max-width:72ch}

/* ── faq ───────────────────────────────────────────────────────────────── */
.faq{max-width:900px;margin:56px auto 0;border-top:1px solid var(--hair-soft)}
.faq-item{border-bottom:1px solid var(--hair-soft)}
.faq-trigger{width:100%;display:flex;align-items:center;justify-content:space-between;gap:24px;
  padding:26px 0;text-align:left;font-size:19px;font-weight:500;transition:color .2s}
.faq-trigger:hover{color:var(--accent)}
.faq-icon{flex:none;position:relative;width:18px;height:18px;color:var(--ink-3)}
.faq-icon svg{position:absolute;inset:0}
.faq-panel{display:grid;grid-template-rows:0fr;transition:grid-template-rows .34s var(--ease)}
.faq-panel.is-open{grid-template-rows:1fr}
.faq-panel>div{overflow:hidden}
.faq-panel p{padding-bottom:26px;font-size:17px;line-height:1.6;color:var(--ink-3);max-width:74ch}

/* ── final + footer ────────────────────────────────────────────────────── */
.wordmark{position:relative;margin-top:120px;text-align:center}
.wordmark img{width:min(260px,30vw);margin:0 auto}
footer{position:relative;z-index:1;border-top:1px solid var(--hair);padding:80px 0 44px}
/* Two link columns, not four. The brand column takes the space the removed ones freed rather
 * than the grid stretching two columns across the page. */
.fgrid{display:grid;grid-template-columns:2fr 1fr 1fr;gap:56px;max-width:940px}
.flegal{display:flex;gap:18px;margin-right:auto;margin-left:28px}
.flegal a{transition:color .2s}
.flegal a:hover{color:var(--ink-2)}
.fcol h4{font-family:var(--mono);font-size:11px;font-weight:400;letter-spacing:.15em;
  text-transform:uppercase;color:var(--ink-4);margin-bottom:18px}
.fcol li a{display:block;padding:6px 0;font-size:15.5px;color:var(--ink-2);transition:color .2s}
.fcol li a:hover{color:var(--ink)}
.fbot{display:flex;justify-content:space-between;align-items:center;gap:20px;flex-wrap:wrap;
  margin-top:64px;padding-top:28px;border-top:1px solid var(--hair-soft);
  font-size:14px;color:var(--ink-4)}

/* ── motion contract (driven by /_knowl/motion.js) ─────────────────────── */
[data-animate],[data-animate-standalone]{will-change:opacity,transform}
.animated-dots-container{display:flex;gap:7px;align-items:center;justify-content:center}
.animated-dots-container .dot{width:5px;height:5px;border-radius:50%;background:var(--accent);
  opacity:0;transform:scale(.4)}

@media (max-width:980px){
  .tab-row,.cards,.plans,.uses{grid-template-columns:1fr}
  .adapters{grid-template-columns:repeat(2,1fr)}
  .split,.rr{grid-template-columns:1fr;gap:44px}
  .fgrid{grid-template-columns:1fr 1fr;gap:32px}
  .nav-links{display:none}
  .mob{display:block}
  .band{padding:96px 0}
}
@media (max-width:640px){
  .adapters{grid-template-columns:1fr}
  .ev{padding-left:44px}
  .ev-claim{font-size:19px}
}
