/* ==========================================================================
   RustCFML project site
   Hand-written, no framework. Dark by default, light on request, one file.
   ========================================================================== */

/* --- Tokens -------------------------------------------------------------- */
:root[data-theme="dark"] {
  --bg:          #0a0e14;
  --bg-soft:     #0e141c;
  --panel:       #111925;
  --panel-2:     #16202e;
  --line:        #1f2c3c;
  --line-soft:   #18232f;
  --ink:         #e8eef6;
  --ink-2:       #a4b3c6;
  --ink-3:       #6f8299;
  --brand:       #ff7a45;
  --brand-2:     #ffb27a;
  --brand-ink:   #1a0c04;
  --brand-glow:  rgba(255, 122, 69, .18);
  --cool:        #7cc7ff;
  --code-bg:     #0b111a;
  --code-line:   #17222f;
  --shadow:      0 18px 50px -18px rgba(0, 0, 0, .75);
  --header-bg:   rgba(10, 14, 20, .78);
  --card-shadow: none;   /* the panel already separates by being lighter */
  --tk-kw:   #ff9d6b;
  --tk-str:  #9ae6a1;
  --tk-fn:   #7cc7ff;
  --tk-com:  #5b6f86;
  --tk-num:  #d8b4fe;
  --tk-tag:  #ff7a45;
  --tk-out:  #cfe3ff;
}

:root[data-theme="light"] {
  --bg:          #fbfcfe;
  --bg-soft:     #f3f6fa;
  --panel:       #ffffff;
  --panel-2:     #f7f9fc;
  --line:        #dbe3ee;
  --line-soft:   #e8edf4;
  --ink:         #0f1a26;
  --ink-2:       #46586e;
  --ink-3:       #7b8ca1;
  --brand:       #e2551f;
  --brand-2:     #f0864f;
  --brand-ink:   #fff6f1;
  --brand-glow:  rgba(226, 85, 31, .12);
  --cool:        #1f6feb;
  --code-bg:     #0b111a;
  --code-line:   #17222f;
  --shadow:      0 14px 40px -22px rgba(15, 26, 38, .35);
  --header-bg:   rgba(251, 252, 254, .82);
  /* A white panel on a near-white ground needs more than a hairline to read as
     raised, which is free in the dark theme and has to be drawn in this one. */
  --card-shadow: 0 1px 2px rgba(15, 26, 38, .04), 0 10px 26px -20px rgba(15, 26, 38, .22);
  --tk-kw:   #ffb68f;
  --tk-str:  #a6f0ae;
  --tk-fn:   #93d3ff;
  --tk-com:  #6f8499;
  --tk-num:  #e6c6ff;
  --tk-tag:  #ff9264;
  --tk-out:  #dbe9ff;
}

/* --- Base ---------------------------------------------------------------- */
* { box-sizing: border-box; }

html { scroll-behavior: smooth; scroll-padding-top: 92px; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 400 16px/1.65 "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-feature-settings: "cv02", "cv03", "cv04", "ss01";
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4 { line-height: 1.15; margin: 0 0 .5em; font-weight: 700; letter-spacing: -.02em; }
h1 { font-size: clamp(2.4rem, 5.2vw, 3.9rem); font-weight: 800; letter-spacing: -.035em; }
h2 { font-size: clamp(1.7rem, 3vw, 2.35rem); }
/* The hero h1 sits in a half-width grid track, so its size has to suit the
   headline it actually carries. At the global 3.9rem a 44-character line broke
   into four, which reads as a paragraph rather than a headline; this keeps it
   to two or three. Interior page heroes are short enough to stay at full size. */
.hero h1 { font-size: clamp(2.15rem, 4.4vw, 3.15rem); }

h3 { font-size: 1.18rem; letter-spacing: -.015em; }
h4 { font-size: .82rem; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3); font-weight: 700; margin-bottom: 1.1em; }
p { margin: 0 0 1.1em; color: var(--ink-2); }
p:last-child { margin-bottom: 0; }
a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--brand-2); }
strong { color: var(--ink); font-weight: 600; }
em { color: var(--ink-2); }
hr { border: 0; border-top: 1px solid var(--line); margin: 48px 0; }
img { max-width: 100%; }
code, kbd, pre { font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; }
::selection { background: var(--brand); color: var(--brand-ink); }

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

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--brand); color: var(--brand-ink); padding: 10px 18px; border-radius: 0 0 10px 0; font-weight: 600;
}
.skip:focus { left: 0; }

.wrap { width: 100%; max-width: 1160px; margin-inline: auto; padding-inline: clamp(18px, 4vw, 32px); }
main { display: block; }
/* Adjacent sections each contribute their own padding, so the gap between two
   bands is double whatever is set here. At 84px that made 168px between the
   last line of one section and the first of the next, which is a gap you
   scroll through rather than a separation you read. */
section { padding-block: clamp(30px, 3.5vw, 46px); }
section.tight { padding-block: clamp(18px, 1.9vw, 24px); }
.page-hero + section.tight { padding-top: 0; }
section.tint { background: var(--bg-soft); border-block: 1px solid var(--line-soft); }

.lead { font-size: 1.12rem; color: var(--ink-2); max-width: 68ch; }
/* The 74ch measure is for the prose. Capping the whole block put it on the
   heading too, which wrapped "5 ways to deploy including Cloudflare edge" onto
   a second line with 400px of empty row beside it. */
.section-head { margin-bottom: 28px; }
.section-head > p { max-width: 74ch; }
.section-head.center { margin-inline: auto; text-align: center; }
.section-head.center > p { margin-inline: auto; }
.section-head h2 { margin-bottom: 14px; }
.muted { color: var(--ink-3); }
.small { font-size: .875rem; }
.nowrap { white-space: nowrap; }

/* --- Header -------------------------------------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: var(--header-bg);
  backdrop-filter: saturate(160%) blur(14px);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  border-bottom: 1px solid var(--line-soft);
  transition: border-color .2s, box-shadow .2s;
}
.site-header.is-scrolled { border-bottom-color: var(--line); box-shadow: 0 10px 30px -24px rgba(0, 0, 0, .9); }
.header-inner { display: flex; align-items: center; gap: 22px; height: 66px; }

.brand { display: inline-flex; align-items: center; gap: 10px; color: var(--ink); flex: none; }
.brand:hover { color: var(--ink); }
.brand img { display: block; }
.brand-name { font-weight: 800; letter-spacing: -.03em; font-size: 1.08rem; }
.brand-hi { color: var(--brand); }

.nav { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.nav-link {
  padding: 8px 13px; border-radius: 9px; font-size: .925rem; font-weight: 500;
  color: var(--ink-2); transition: color .15s, background .15s;
}
.nav-link:hover { color: var(--ink); background: var(--panel); }
.nav-link.is-active { color: var(--ink); background: var(--panel-2); box-shadow: inset 0 0 0 1px var(--line); }
.nav-mobile-only { display: none; }

.header-actions { display: flex; align-items: center; gap: 8px; flex: none; }

.theme-btn, .menu-btn {
  display: grid; place-items: center; width: 36px; height: 36px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  color: var(--ink-2); cursor: pointer; transition: color .15s, border-color .15s, transform .15s;
}
.theme-btn:hover, .menu-btn:hover { color: var(--ink); border-color: var(--ink-3); transform: translateY(-1px); }
:root[data-theme="dark"] .ico-sun  { display: none; }
:root[data-theme="light"] .ico-moon { display: none; }

.menu-btn { display: none; place-items: center; flex-direction: column; gap: 4px; }
.menu-btn span { display: block; width: 15px; height: 1.5px; background: var(--ink-2); border-radius: 2px; transition: transform .2s, opacity .2s; }
.menu-btn[aria-expanded="true"] span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.menu-btn[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.menu-btn[aria-expanded="true"] span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

/* --- Buttons ------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 11px 18px; border-radius: 11px; border: 1px solid transparent;
  font: 600 .925rem/1.2 "Inter", sans-serif; cursor: pointer; white-space: nowrap;
  transition: transform .15s, box-shadow .15s, background .15s, border-color .15s, color .15s;
}
.btn:hover { transform: translateY(-1px); }
.btn-primary { background: linear-gradient(180deg, var(--brand-2), var(--brand)); color: var(--brand-ink); box-shadow: 0 12px 30px -14px var(--brand-glow), inset 0 1px 0 rgba(255, 255, 255, .28); }
.btn-primary:hover { color: var(--brand-ink); box-shadow: 0 16px 36px -14px var(--brand-glow); }
.btn-secondary { background: var(--panel); color: var(--ink); border-color: var(--line); }
.btn-secondary:hover { color: var(--ink); border-color: var(--ink-3); }
.btn-ghost { background: transparent; color: var(--ink-2); border-color: var(--line); }
.btn-ghost:hover { color: var(--ink); border-color: var(--ink-3); }
.btn-sm { padding: 7px 12px; font-size: .84rem; border-radius: 9px; }
.btn-lg { padding: 14px 24px; font-size: 1rem; border-radius: 12px; }
.btn svg { width: 17px; height: 17px; flex: none; }
.btn-lg svg { width: 19px; height: 19px; }
.btn-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-top: 28px; }

.pill {
  display: inline-flex; align-items: center; gap: 5px; padding: 2px 8px; margin-left: 2px;
  border-radius: 999px; background: rgba(124, 199, 255, .12); color: var(--cool);
  font-size: .76rem; font-weight: 700; letter-spacing: .01em;
}

.badge-link {
  display: inline-flex; align-items: center; padding: 4px 10px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--panel);
  font-size: .76rem; font-weight: 600; color: var(--ink-2); font-family: "JetBrains Mono", monospace;
}
.badge-link:hover { color: var(--ink); border-color: var(--ink-3); }

/* --- Hero ---------------------------------------------------------------- */
.hero { position: relative; padding-block: clamp(22px, 2.6vw, 34px) clamp(30px, 3.8vw, 54px); overflow: hidden; }
.hero::before {
  content: ""; position: absolute; inset: -40% -10% auto; height: 130%;
  background: radial-gradient(58% 60% at 22% 12%, var(--brand-glow), transparent 70%),
              radial-gradient(45% 50% at 82% 4%, rgba(124, 199, 255, .12), transparent 72%);
  pointer-events: none;
}
.hero::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: .5;
  background-image: linear-gradient(var(--line-soft) 1px, transparent 1px),
                    linear-gradient(90deg, var(--line-soft) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(70% 60% at 50% 0%, #000 20%, transparent 78%);
  -webkit-mask-image: radial-gradient(70% 60% at 50% 0%, #000 20%, transparent 78%);
}
.hero .wrap { position: relative; z-index: 1; }
/* minmax(0, …), like every other grid here, and top-aligned like every .split.
   Two things this grid got wrong in the past, both worth not repeating: on a
   bare fr its automatic minimum is min-content, so one unbreakable token in the
   text column starved the code panel down to 159px; and centred, the shorter
   column is pushed down by half the height difference, which had the h1 start
   74px below the header while every sub-page h1 started at 34px. */
.hero-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(28px, 5vw, 60px); align-items: start; }
.hero h1 { margin-bottom: 14px; }
.hero h1 .hi { color: var(--brand); white-space: nowrap; }
.hero .lead .hi { color: var(--brand); }
.hero .lead { font-size: clamp(1.02rem, 1.6vw, 1.18rem); }
.hero-badges { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 20px; }
.hero-crab { position: absolute; right: -30px; bottom: -40px; width: 220px; opacity: .07; pointer-events: none; }


/* --- Code windows -------------------------------------------------------- */
.term { background: var(--code-bg); border: 1px solid var(--code-line); border-radius: 14px; overflow: hidden; box-shadow: var(--shadow); }
.term + .term, .term + p { margin-top: 18px; }
.term-bar {
  display: flex; align-items: center; gap: 8px; padding: 10px 14px;
  border-bottom: 1px solid var(--code-line); background: rgba(255, 255, 255, .02);
}
.term-bar .dot { width: 9px; height: 9px; border-radius: 50%; background: #ff5f57; }
.term-bar .dot + .dot { background: #febc2e; }
.term-bar .dot + .dot + .dot { background: #28c840; }
.term-name { margin-left: 6px; font: 500 .775rem "JetBrains Mono", monospace; color: var(--ink-3); }
.term-copy {
  margin-left: auto; padding: 4px 9px; border-radius: 7px; border: 1px solid var(--code-line);
  background: transparent; color: var(--ink-3); font: 600 .72rem "Inter", sans-serif; cursor: pointer;
}
.term-copy:hover { color: var(--ink); border-color: var(--ink-3); }
.term-body {
  margin: 0; padding: 16px 18px; overflow-x: auto;
  font-size: .845rem; line-height: 1.72; color: var(--tk-out);
  /* Wrap instead of scroll. overflow-x:auto alone hid the end of every long
     line: a release URL in a grid track showed 316 of the 782px it needed,
     with no scrollbar to say so, which reads as broken rather than scrollable.
     Soft wrapping cannot hide anything, and leaves the copy button intact:
     innerText reports required line breaks only, never soft ones. */
  white-space: pre-wrap;
  overflow-wrap: break-word;   /* a release URL is one unbreakable token */
}
.term-body code { font: inherit; }
.term-out { border-top: 1px dashed var(--code-line); color: var(--ink-3); }
.term-out .ok { color: #6fdc8c; }

.tk-kw  { color: var(--tk-kw); }
.tk-str { color: var(--tk-str); }
.tk-fn  { color: var(--tk-fn); }
.tk-com { color: var(--tk-com); font-style: italic; }
.tk-num { color: var(--tk-num); }
.tk-tag { color: var(--tk-tag); }
.tk-att { color: #ffd9a8; }

code.inline {
  padding: .12em .4em; border-radius: 6px; background: var(--panel-2);
  border: 1px solid var(--line); font-size: .875em; color: var(--ink);
}
kbd {
  padding: 2px 7px; border-radius: 6px; background: var(--panel-2);
  border: 1px solid var(--line); border-bottom-width: 2px; font-size: .82em; color: var(--ink);
}

/* --- Stats --------------------------------------------------------------- */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: 16px; overflow: hidden; }
.stats:has(.stat:nth-child(3):last-child) { grid-template-columns: repeat(3, 1fr); }
.stat { background: var(--panel); padding: 26px 22px; }
.stat b { display: block; font-size: clamp(1.7rem, 3.2vw, 2.3rem); font-weight: 800; letter-spacing: -.035em; color: var(--ink); line-height: 1.1; }
.stat span { display: block; margin-top: 6px; font-size: .9rem; font-weight: 600; color: var(--ink-2); }
.stat i { display: block; margin-top: 3px; font-size: .78rem; font-style: normal; color: var(--ink-3); }

/* --- Grids & cards ------------------------------------------------------- */
.grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 18px; }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* A grid of terminals reflows on the width a shell line needs, not the width
   that suits cards: three-up inside a padded CTA left each one 316px, which is
   about 34 characters. min() keeps the track from ever exceeding the track it
   is given, so this cannot reintroduce page-level overflow on a phone. */
.grid-2:has(> .term), .grid-3:has(> .term), .grid-4:has(> .term) {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
}

.card {
  position: relative; padding: 24px; border-radius: 15px;
  background: var(--panel); border: 1px solid var(--line);
  box-shadow: var(--card-shadow, none);
  transition: transform .18s, border-color .18s, background .18s, box-shadow .18s;
}
.card:hover { transform: translateY(-3px); border-color: color-mix(in srgb, var(--brand) 45%, var(--line)); }
.card h3 { margin-bottom: 8px; }
.card p { font-size: .935rem; }
.card-ico {
  display: grid; place-items: center; width: 38px; height: 38px; margin-bottom: 15px;
  border-radius: 10px; background: linear-gradient(160deg, var(--brand-glow), transparent), var(--panel-2);
  border: 1px solid var(--line); color: var(--brand);
}
.card-ico svg { width: 19px; height: 19px; }
.card-link { display: block; color: inherit; }
.card-link h3 a::after { content: ""; position: absolute; inset: 0; }
.card-more { display: inline-flex; align-items: center; gap: 6px; margin-top: 14px; font-size: .86rem; font-weight: 600; color: var(--brand); }
.card-more::after { content: "→"; transition: transform .18s; }
.card:hover .card-more::after { transform: translateX(3px); }
.card .tag { display: inline-block; margin-bottom: 12px; font: 700 .7rem/1 "Inter", sans-serif; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }

/* Five deploy shapes, named and linked to their section of the deployment
   doc. A card each, with body copy and a terminal panel, cost most of a
   viewport to say five short things. */
/* Chips size to their own labels and share what is left over, rather than
   sitting in equal tracks: an equal track is set by the shortest name, which
   left "Edge / Cloudflare" wrapping onto a second line on its own. */
.deploy-ways { display: flex; flex-wrap: wrap; gap: 10px; }
.deploy-way {
  flex: 1 1 auto; white-space: nowrap;
  display: flex; align-items: center; gap: 11px; padding: 12px 14px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  color: var(--ink); font-weight: 600; font-size: .93rem;
  transition: transform .18s, border-color .18s, color .18s;
}
.deploy-way:hover { transform: translateY(-2px); border-color: color-mix(in srgb, var(--brand) 45%, var(--line)); color: var(--ink); }
.deploy-name::after { content: " →"; color: var(--brand); white-space: pre; }
.deploy-ico {
  display: grid; place-items: center; flex: none; width: 30px; height: 30px; border-radius: 9px;
  background: linear-gradient(160deg, var(--brand-glow), transparent), var(--panel-2);
  border: 1px solid var(--line); color: var(--brand);
}
.deploy-ico svg { width: 16px; height: 16px; }

@media (max-width: 520px) { .deploy-way { flex-basis: 100%; white-space: normal; } }

ul.tick { list-style: none; padding: 0; margin: 0 0 18px; }
ul.tick li { position: relative; padding-left: 26px; margin-bottom: 9px; color: var(--ink-2); font-size: .95rem; }
ul.tick li::before {
  content: ""; position: absolute; left: 2px; top: .55em; width: 14px; height: 8px;
  border-left: 2px solid var(--brand); border-bottom: 2px solid var(--brand);
  transform: rotate(-45deg); opacity: .9;
}
/* A capability list, not a card grid. Two columns on a desktop so eight short
   items read as one block rather than a long scroll, collapsing to one column
   where a line would otherwise wrap mid-phrase. */
ul.tick.cols { columns: 2; column-gap: clamp(24px, 4vw, 48px); margin-bottom: 0; }
ul.tick.cols li { break-inside: avoid; margin-bottom: 11px; }
@media (max-width: 760px) { ul.tick.cols { columns: 1; } }

/* --- /try playground ----------------------------------------------------- */
/* The editor and the output are the same panel chrome as every other code
   sample on the site, so the page reads as part of it rather than as an
   embedded tool. Equal tracks, both minmax(0,…) like every other grid here. */
.try-bar { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 16px; }
.try-samples { display: flex; gap: 8px; flex-wrap: wrap; margin-right: auto; }
.chip {
  padding: 7px 13px; border-radius: 999px; cursor: pointer;
  background: var(--panel); border: 1px solid var(--line); color: var(--ink-2);
  font: 600 .82rem/1 "Inter", sans-serif;
  transition: color .15s, border-color .15s, background .15s;
}
.chip:hover { color: var(--ink); border-color: var(--ink-3); }
.chip.is-active { color: var(--brand-ink); background: var(--brand); border-color: var(--brand); }

.try-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; align-items: start; }
.try-grid .term + .term { margin-top: 0; }
.term-hint { margin-left: auto; font-size: .74rem; color: var(--ink-3); letter-spacing: .04em; }

/* A textarea, not a contenteditable: it keeps native undo, native selection and
   a caret that behaves, which no hand-rolled editor gets right for free. */
.try-editor {
  display: block; width: 100%; min-height: 420px; resize: vertical;
  margin: 0; padding: 16px 18px; border: 0; outline: 0;
  background: transparent; color: var(--tk-out);
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .845rem; line-height: 1.72; tab-size: 4;
  /* Display panels can have ligatures; an input cannot. JetBrains Mono renders
     => as one glyph and != as ≠, which is decoration in a sample and a lie in a
     field you type into. */
  font-variant-ligatures: none;
}
.try-editor:focus-visible { outline: 0; box-shadow: inset 0 0 0 2px var(--brand-glow); }

.try-out { min-height: 420px; margin: 0; white-space: pre-wrap; overflow-wrap: break-word; }
.term.is-error .try-out { color: #ff9d8b; }

@media (max-width: 900px) {
  .try-grid { grid-template-columns: minmax(0, 1fr); }
  .try-editor, .try-out { min-height: 300px; }
}

ul.plain { list-style: none; padding: 0; margin: 0; }
ul.plain li { margin-bottom: 8px; color: var(--ink-2); }

/* --- Split feature rows -------------------------------------------------- */
/* Top-aligned, not centred. A code panel is whatever height its sample is, and
   centring it against a much taller column of prose left a void above and below
   it; aligned to the top it reads as belonging to the heading it follows. */
.split { display: grid; grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr); gap: clamp(24px, 4vw, 48px); align-items: start; }
.split.middle { align-items: center; }
.split.flip > .split-text { order: 2; }
.split + .split { margin-top: clamp(48px, 7vw, 84px); }
.split h3 { font-size: clamp(1.3rem, 2.3vw, 1.75rem); letter-spacing: -.025em; margin-bottom: 12px; }
.split p { font-size: 1rem; }

/* --- Steps --------------------------------------------------------------- */
.steps { counter-reset: step; display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }
.step { position: relative; padding: 20px 22px 20px 62px; background: var(--panel); border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--card-shadow, none); }
.step::before {
  counter-increment: step; content: counter(step);
  position: absolute; left: 20px; top: 19px; width: 26px; height: 26px;
  display: grid; place-items: center; border-radius: 8px;
  background: linear-gradient(180deg, var(--brand-2), var(--brand)); color: var(--brand-ink);
  font: 800 .82rem/1 "JetBrains Mono", monospace;
}
.step h3 { font-size: 1.02rem; margin-bottom: 6px; }
.step p { font-size: .93rem; margin-bottom: 12px; }
.step .term { margin-top: 12px; }

/* --- Callouts ------------------------------------------------------------ */
.callout { display: flex; gap: 14px; padding: 18px 20px; border-radius: 13px; border: 1px solid var(--line); background: var(--panel); margin: 22px 0; }
.callout p { margin: 0; font-size: .93rem; }
.callout .ico { flex: none; width: 22px; height: 22px; color: var(--cool); }
.callout .ico svg { width: 22px; height: 22px; display: block; }
.callout.warn { border-color: color-mix(in srgb, #f0b429 40%, var(--line)); }
.callout.warn .ico { color: #f0b429; }
.callout.brandline .ico { color: var(--brand); }
.callout b { display: block; margin-bottom: 3px; color: var(--ink); }

/* --- Tables -------------------------------------------------------------- */
.table-wrap {
  border: 1px solid var(--line); border-radius: 15px; overflow: hidden;
  background: var(--panel); overflow-x: auto;
  /* A wide table still scrolls, so give it a scrollbar you can see. */
  scrollbar-width: thin; scrollbar-color: var(--ink-3) transparent;
}
.table-wrap::-webkit-scrollbar { height: 9px; }
.table-wrap::-webkit-scrollbar-track { background: var(--panel-2); }
.table-wrap::-webkit-scrollbar-thumb { background: var(--line); border-radius: 999px; }
.table-wrap:hover::-webkit-scrollbar-thumb { background: var(--ink-3); }
table { width: 100%; border-collapse: collapse; font-size: .92rem; }
/* The 560px floor is opt-in, not global. A three-column table sitting in a
   half-width grid track fits its content comfortably; forcing the floor on it
   made the wrap scroll and cut the last column mid-word ("JVM + runtim"). Only
   the six-column benchmark tables need a minimum, and they run full width. */
.table-wrap.wide table { min-width: 560px; }
caption { text-align: left; padding: 16px 20px; border-bottom: 1px solid var(--line); font-weight: 600; color: var(--ink); background: var(--panel-2); }
th, td { padding: 12px 18px; text-align: left; border-bottom: 1px solid var(--line-soft); }
thead th { font-size: .74rem; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3); font-weight: 700; background: var(--panel-2); }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover td { background: rgba(255, 255, 255, .015); }
td.num, th.num { text-align: right; font-family: "JetBrains Mono", monospace; font-variant-numeric: tabular-nums; }
tr.ours td { background: color-mix(in srgb, var(--brand) 8%, transparent); font-weight: 600; }
tr.ours td:first-child { box-shadow: inset 3px 0 0 var(--brand); }
.bar { display: block; height: 6px; border-radius: 4px; background: var(--line); overflow: hidden; min-width: 70px; }
.bar i { display: block; height: 100%; border-radius: 4px; background: linear-gradient(90deg, var(--brand-2), var(--brand)); }
.bar.cool i { background: linear-gradient(90deg, #86d3ff, #3b9dff); }

/* --- FAQ ----------------------------------------------------------------- */
.faq-item { border-bottom: 1px solid var(--line); }
.faq-item summary {
  padding: 18px 40px 18px 0; cursor: pointer; font-weight: 600; font-size: 1.02rem;
  list-style: none; position: relative; color: var(--ink);
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: "+"; position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  color: var(--brand); font-size: 1.25rem; font-weight: 400; transition: transform .2s;
}
.faq-item[open] summary::after { content: "–"; }
.faq-item .faq-body { padding: 0 0 20px; max-width: 78ch; }
.faq-item .faq-body p { font-size: .96rem; }

/* --- Docs index ---------------------------------------------------------- */
.doc-group + .doc-group { margin-top: 40px; }
.doc-group-head { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; padding-bottom: 12px; border-bottom: 1px solid var(--line); margin-bottom: 20px; }
.doc-group-head h3 { margin: 0; }
.doc-group-head span { font-size: .9rem; color: var(--ink-3); }
.doc-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.doc-item { display: block; padding: 16px 18px; border-radius: 12px; border: 1px solid var(--line); background: var(--panel); box-shadow: var(--card-shadow, none); transition: border-color .18s, transform .18s, box-shadow .18s; color: inherit; }
.doc-item:hover { border-color: color-mix(in srgb, var(--brand) 45%, var(--line)); transform: translateY(-2px); color: inherit; }
.doc-item b { display: block; font-size: .98rem; margin-bottom: 4px; color: var(--ink); }
.doc-item span { display: block; font-size: .875rem; color: var(--ink-2); }
.doc-item code { display: block; margin-top: 8px; font-size: .76rem; color: var(--ink-3); }

/* --- Platform cards ------------------------------------------------------ */
.plat { padding: 22px; }
.plat h3 { font-size: 1.05rem; margin-bottom: 2px; }
.plat .arch { font-size: .82rem; color: var(--ink-3); font-family: "JetBrains Mono", monospace; margin-bottom: 14px; }
.plat .term-body { font-size: .78rem; padding: 12px 14px; }

/* --- CTA band ------------------------------------------------------------ */
.cta {
  position: relative; overflow: hidden; padding: clamp(24px, 3.4vw, 38px);
  border-radius: 20px; border: 1px solid var(--line);
  background: radial-gradient(90% 130% at 8% 0%, var(--brand-glow), transparent 62%), var(--panel);
}
.cta h2 { margin-bottom: 12px; }
.cta p { max-width: 62ch; }
.cta .btn-row { margin-top: 18px; }

/* --- Footer -------------------------------------------------------------- */
.site-footer { border-top: 1px solid var(--line); background: var(--bg-soft); padding-block: 36px 26px; }
.footer-grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: 32px; }
.footer-brand p { font-size: .92rem; margin: 14px 0 16px; max-width: 38ch; }
.footer-badges { display: flex; flex-wrap: wrap; gap: 8px; }
.site-footer h4 { margin-bottom: 14px; }
.site-footer ul { list-style: none; padding: 0; margin: 0; }
.site-footer ul li { margin-bottom: 9px; }
.site-footer ul a { font-size: .92rem; color: var(--ink-2); }
.site-footer ul a:hover { color: var(--brand); }
.footer-bar { margin-top: 44px; padding-top: 22px; border-top: 1px solid var(--line); display: flex; flex-wrap: wrap; gap: 14px; justify-content: space-between; }
.footer-bar p { font-size: .8rem; color: var(--ink-3); max-width: 60ch; margin: 0; }
.footer-meta { font-family: "JetBrains Mono", monospace; }

/* --- Page hero (inner pages) --------------------------------------------- */
.page-hero { position: relative; padding-block: clamp(22px, 2.6vw, 34px) clamp(16px, 2vw, 24px); overflow: hidden; }
.page-hero::before {
  content: ""; position: absolute; inset: -60% -10% auto; height: 150%; pointer-events: none;
  background: radial-gradient(50% 55% at 18% 20%, var(--brand-glow), transparent 68%);
}
.page-hero .wrap { position: relative; z-index: 1; }
.page-hero h1 { font-size: clamp(2.1rem, 4vw, 3.1rem); margin-bottom: 11px; }
.page-hero .lead { font-size: 1.1rem; }

/* --- Span waterfall ------------------------------------------------------ */
/* A diagram, not a screenshot of one: the shape a request takes once it is
   spanned, drawn from the span types the exporter always emits (request root,
   template render, DB queries, and user functions under the depth cap). */
.trace {
  margin: 0; padding: 16px 18px 18px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--card-shadow);
}
.trace figcaption {
  margin-bottom: 14px; padding-bottom: 12px; border-bottom: 1px solid var(--line-soft);
  font: 700 .72rem "JetBrains Mono", ui-monospace, monospace;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3);
}
.trace-row {
  display: grid; align-items: center; gap: 12px;
  grid-template-columns: minmax(0, 13.5em) minmax(0, 1fr) 4.2em;
  padding: 5px 0;
}
.trace-name {
  font: 500 .78rem "JetBrains Mono", ui-monospace, monospace;
  color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.trace-track { position: relative; height: 12px; background: var(--line-soft); border-radius: 4px; }
.trace-track i {
  position: absolute; top: 0; bottom: 0;
  left: var(--o); width: var(--w);
  border-radius: 4px;
  background: linear-gradient(90deg, var(--brand-2), var(--brand));
}
.trace-track i.db { background: linear-gradient(90deg, #86d3ff, #3b9dff); }
.trace-ms {
  font: 500 .72rem "JetBrains Mono", ui-monospace, monospace;
  color: var(--ink-3); text-align: right;
}
@media (max-width: 520px) {
  .trace-row { grid-template-columns: minmax(0, 1fr) 4em; }
  .trace-track { grid-column: 1 / -1; }
}

/* A number and its bar in one cell, so the two engines can be compared at a
   glance instead of one being a figure and the other a wordless bar. */
td.num .bar { margin-top: 6px; }

/* --- Home hero: the monolith --------------------------------------------- */
/* One object standing in for the binary: six capability bands on a single
   prism. It is CSS 3D rather than a WebGL library on purpose, because a page that
   argues for a 60 MB dependency-free runtime should not open by downloading
   half a megabyte of scene graph. Every label stays real, selectable text and
   the whole thing degrades to a static prism with script switched off.
   Geometry is driven from --mw / --md / --mh, so one rule rescales it. */
.mono {
  --mw: 222px;                       /* width  of the prism */
  --md: 156px;                       /* depth  of the prism */
  --mh: 52px;                        /* height of one band  */
  --mhalf: 2.5;                      /* (bands - 1) / 2, for centring the stack */

  /* Surfaces are tokens rather than literals because the two themes want
     genuinely different shading: dark can lift a face out of the background,
     light has to push it back with a border and a shadow instead. */
  --mono-edge:   color-mix(in srgb, var(--ink) 13%, var(--line));
  --mono-face:   linear-gradient(168deg, color-mix(in srgb, var(--ink) 7%, var(--panel-2)), var(--panel) 72%);
  --mono-side:   linear-gradient(168deg, var(--panel), color-mix(in srgb, var(--bg) 55%, var(--panel)) 80%);
  --mono-top:    linear-gradient(140deg, color-mix(in srgb, var(--brand) 20%, var(--panel-2)), var(--panel) 76%);
  --mono-bot:    linear-gradient(140deg, color-mix(in srgb, var(--ink) 12%, var(--panel-2)), var(--panel) 78%);
  --mono-bevel:  inset 0 1px 0 color-mix(in srgb, var(--ink) 11%, transparent);
  --mono-shadow: rgba(0, 0, 0, .5);
}
:root[data-theme="light"] .mono {
  --mono-edge:   color-mix(in srgb, var(--ink) 24%, var(--line));
  --mono-face:   linear-gradient(168deg, #fff, color-mix(in srgb, var(--ink) 7%, var(--bg-soft)) 100%);
  --mono-side:   linear-gradient(168deg, color-mix(in srgb, var(--ink) 9%, var(--bg-soft)), color-mix(in srgb, var(--ink) 20%, var(--bg-soft)));
  --mono-top:    linear-gradient(140deg, color-mix(in srgb, var(--brand) 18%, #fff), var(--bg-soft) 82%);
  --mono-bot:    linear-gradient(140deg, #fff, var(--bg-soft));
  --mono-bevel:  inset 0 1px 0 #fff;
  --mono-shadow: rgba(15, 26, 38, .30);
}

.mono-stage {
  position: relative;
  display: grid;
  place-items: center;
  height: 400px;
  margin-top: -44px;
  perspective: 2400px;
  perspective-origin: 50% 50%;
  cursor: grab;
  touch-action: pan-y;               /* vertical scroll still belongs to the page */
}
.mono-stage.is-drag { cursor: grabbing; }

/* Glow behind, contact shadow beneath: the two cheap cues that stop a flat
   stack of rectangles from reading as a flat stack of rectangles. */
.mono-stage::before {
  content: ""; position: absolute; inset: 10% 4%;
  background: radial-gradient(ellipse at 50% 44%, var(--brand-glow), transparent 68%);
  filter: blur(14px); pointer-events: none;
}
.mono-stage::after {
  content: ""; position: absolute; left: 50%; bottom: 34px;
  width: 268px; height: 34px; transform: translateX(-50%);
  background: radial-gradient(ellipse, var(--mono-shadow), transparent 72%);
  filter: blur(11px); pointer-events: none;
}

.mono-obj {
  position: relative;
  width: var(--mw);
  height: calc(var(--mh) * 6);
  transform-style: preserve-3d;
  transform: rotateX(-20deg) rotateY(var(--ry, -26deg));
  will-change: transform;
}

/* A band is a <button>, which is what makes the object keyboard-reachable
   without a parallel list of links underneath it. */
.mono-band {
  --ty: calc((var(--i) - var(--mhalf)) * var(--mh));
  position: absolute; left: 50%; top: 50%;
  width: var(--mw); height: var(--mh);
  margin: calc(var(--mh) / -2) 0 0 calc(var(--mw) / -2);
  padding: 0; border: 0; background: none; color: inherit; font: inherit;
  appearance: none; -webkit-appearance: none;
  transform-style: preserve-3d;
  transform: translateY(var(--ty));
  transition: transform .28s cubic-bezier(.2, .7, .3, 1);
  cursor: pointer;
}
.mono-band.is-on { transform: translateY(var(--ty)) scale3d(1.07, 1, 1.07); }
.mono-band:focus { outline: none; }

.mf {
  position: absolute; left: 50%; top: 50%;
  display: grid; place-items: center;
  height: var(--mh);
  border: 1px solid var(--mono-edge);
  background: var(--mono-face);
  box-shadow: var(--mono-bevel);
  color: var(--ink-2);
  font: 700 12px/1 "JetBrains Mono", ui-monospace, monospace;
  letter-spacing: .2em; text-transform: uppercase;
  user-select: none;
  transition: color .22s, border-color .22s, background .22s, box-shadow .22s;
}
.mf-fr, .mf-bk { width: var(--mw); margin: calc(var(--mh) / -2) 0 0 calc(var(--mw) / -2); }
.mf-lf, .mf-rt {
  width: var(--md); margin: calc(var(--mh) / -2) 0 0 calc(var(--md) / -2);
  padding: 0 7px;
  font-size: 10px; letter-spacing: .04em; text-transform: none;
  background: var(--mono-side);
  color: var(--ink-2);
}
.mf-fr { transform: translateZ(calc(var(--md) / 2)); }
.mf-bk { transform: rotateY(180deg) translateZ(calc(var(--md) / 2)); }
.mf-rt { transform: rotateY(90deg)  translateZ(calc(var(--mw) / 2)); }
.mf-lf { transform: rotateY(-90deg) translateZ(calc(var(--mw) / 2)); }

.mono-band.is-on .mf {
  color: var(--brand);
  border-color: color-mix(in srgb, var(--brand) 62%, var(--line));
  background: linear-gradient(180deg,
                color-mix(in srgb, var(--brand) 17%, var(--panel-2)),
                color-mix(in srgb, var(--brand)  7%, var(--panel)));
  box-shadow: 0 0 26px -6px var(--brand-glow), inset 0 0 20px -10px var(--brand);
}
.mono-band:focus-visible .mf { border-color: var(--brand); color: var(--brand); }

/* The two ends of the prism. The top is the only place the product is named,
   which is the reward for turning it over. */
.mono-cap {
  position: absolute; left: 50%; top: 50%;
  display: grid; place-items: center;
  width: var(--mw); height: var(--md);
  margin: calc(var(--md) / -2) 0 0 calc(var(--mw) / -2);
  border: 1px solid var(--mono-edge);
  background: var(--mono-bot);
  overflow: hidden;                  /* the mark must not spill off the lid */
}
.mono-cap-top {
  border-color: color-mix(in srgb, var(--brand) 45%, var(--line));
  background: var(--mono-top);
  align-content: center;
  gap: 6px;
}
/* Seen at a glancing angle for most of a turn, so it is drawn big and lit
   rather than sized as a logo would be on a flat page. */
.mono-crab {
  width: calc(var(--mw) * .68); height: auto;
  opacity: .96;
}
.mono-cap span {
  font: 700 10px/1 "JetBrains Mono", ui-monospace, monospace;
  letter-spacing: .3em; color: var(--brand); opacity: .75;
}
.mono-cap-top { transform: translateY(calc(var(--mh) * -3)) rotateX(90deg); }
.mono-cap-bot { transform: translateY(calc(var(--mh) *  3)) rotateX(-90deg); }

/* The readout. Fixed minimum height, because copy of four different lengths
   swapping on hover must not shunt the buttons below it around. */
.mono-read { min-height: 76px; margin-top: 4px; }
.mono-read b {
  display: block; margin-bottom: 6px;
  font: 700 .74rem/1 "JetBrains Mono", ui-monospace, monospace;
  letter-spacing: .16em; text-transform: uppercase; color: var(--brand);
}
.mono-read p { margin: 0; color: var(--ink-2); font-size: .94rem; }

.mono-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 14px 0 0; padding-top: 14px; border-top: 1px solid var(--line-soft);
  font: 500 .72rem "JetBrains Mono", ui-monospace, monospace; color: var(--ink-3);
}
.mono-foot span { padding: 5px 9px; border: 1px solid var(--line); border-radius: 8px; }
.mono-foot .mono-hint { margin-left: auto; border: 0; padding: 5px 0; opacity: .8; }

@media (max-width: 1180px) {
  .mono { --mw: 190px; --md: 134px; --mh: 46px; }
  .mono-stage { height: 360px; }
}
@media (max-width: 1000px) {
  /* Single column below here, so there is room to go back to full size. */
  .mono { --mw: 222px; --md: 156px; --mh: 52px; }
  .mono-stage { height: 400px; }
}
@media (max-width: 420px) {
  .mono { --mw: 174px; --md: 124px; --mh: 44px; }
  .mono-stage { height: 340px; }
  .mono-foot .mono-hint { display: none; }
}

/* --- Reveal animation ---------------------------------------------------- */
/* Hidden only when script is running: the inline boot script in _head.cfm tags
   <html> with .js, so a browser with JavaScript switched off, or a crawler, or
   a print, sees every element at full opacity instead of an empty page. */
.js .reveal { opacity: 0; transform: translateY(14px); }
.reveal.in { opacity: 1; transform: none; transition: opacity .55s ease, transform .55s cubic-bezier(.2, .7, .3, 1); }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; }
  .btn:hover, .card:hover { transform: none; }
  .mono-band, .mf { transition: none; }
}

/* --- Misc ---------------------------------------------------------------- */
.anchor { scroll-margin-top: 92px; }
.h2-row { display: flex; align-items: end; justify-content: space-between; gap: 20px; flex-wrap: wrap; margin-bottom: 24px; }
.h2-row .section-head { margin-bottom: 0; }
.kv { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 28px; }
.kv > div { padding: 14px 0; border-top: 1px solid var(--line); }
.kv dt { font-size: .74rem; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3); font-weight: 700; }
.kv dd { margin: 6px 0 0; color: var(--ink-2); font-size: .95rem; }
.pipeline { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font: 500 .78rem "JetBrains Mono", monospace; }
.pipeline span { padding: 7px 11px; border-radius: 9px; background: var(--panel); border: 1px solid var(--line); color: var(--ink-2); }
.pipeline span.hi { border-color: color-mix(in srgb, var(--brand) 55%, var(--line)); color: var(--brand); }
.pipeline em { color: var(--ink-3); font-style: normal; }
.avatars { display: flex; flex-wrap: wrap; gap: 8px; }

/* --- Responsive ---------------------------------------------------------- */
@media (max-width: 1000px) {
  .hero-grid, .split { grid-template-columns: minmax(0, 1fr); }
  .split.flip > .split-text { order: 0; }
  .split .term { order: 2; }
  .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .footer-brand { grid-column: 1 / -1; }
}

/* The full nav needs about a thousand pixels; below that it becomes the
   hamburger menu rather than a squeezed row of links. */
@media (max-width: 1060px) {
  .menu-btn { display: grid; }
  .header-actions { margin-left: auto; }
  .nav {
    position: fixed; inset: 66px 0 auto; flex-direction: column; align-items: stretch; gap: 2px;
    padding: 14px clamp(18px, 4vw, 32px) 22px; margin: 0;
    background: var(--bg-soft); border-bottom: 1px solid var(--line);
    box-shadow: 0 24px 40px -30px rgba(0, 0, 0, .9);
    display: none;
  }
  .nav.is-open { display: flex; }
  .nav-link { padding: 12px 14px; font-size: 1rem; }
  .nav-mobile-only { display: block; }
}

@media (max-width: 760px) {
  /* The header runs out of room before the nav does: Download moves into the
     menu, where .nav-mobile-only puts it. */
  .header-dl { display: none; }
  .kv { grid-template-columns: minmax(0, 1fr); }
  .doc-list { grid-template-columns: minmax(0, 1fr); }
  .pipeline { font-size: .72rem; }
}

@media (max-width: 520px) {
  /* minmax(0,1fr), not 1fr: an auto minimum lets a wide code sample push the
     whole track, and the page, wider than the screen. */
  .grid-2, .grid-3, .grid-4 { grid-template-columns: minmax(0, 1fr); }
  .stats { grid-template-columns: minmax(0, 1fr); }
  .js-gh { padding: 7px 10px; }
  .hero .btn { width: 100%; }
  .cta { text-align: left; }
}
