/* MyBI — customer-facing site
   Pure static CSS, dark-first, responsive. No build step. */

:root {
  --bg: #0a0e17;
  --bg-soft: #0d1320;
  --panel: #111827;
  --panel-2: #141c2b;
  --border: #1e2838;
  --border-soft: #18212f;
  --text: #e7eef7;
  --muted: #97a6bb;
  --faint: #6b7a90;
  /* Brand accents taken straight from the logomark's own gradients (src-tauri/icons/
     logo-foreground.svg): blue #1570ef→#3aa0ff, violet #6938ef→#9b8afb, purple #a93aea→#cf7bff,
     pink #ec4899→#ff8fd6. The site used to be deliberately monochrome, which made it read like a
     generic template rather than like MyBI — the product's own colours now carry it. Surfaces stay
     the same near-black so the palette is an accent, not a wash. */
  --brand: #9b8afb;
  --brand-2: #cf7bff;
  --brand-3: #3aa0ff;
  --good: #3ddc84;
  --warn: #e0a23a;
  --idle: #5b6b82;
  /* Flat by design: no gradients anywhere in the site. Kept as a token so the few rules that
     still reference it stay one-line edits. */
  --grad: #7c4ddb;
  /* Flat tint, not a ramp — this backs the small icon chips. */
  --grad-soft: rgba(169,58,234,.16);
  --shadow: 0 24px 60px -20px rgba(0,0,0,.7);
  --radius: 16px;
  --radius-sm: 10px;
  --maxw: 1320px;
  --font: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  /* Primary buttons are a SOLID brand violet — no gradient. A flat fill keeps the label contrast
     constant across the whole button instead of shifting with the ramp. */
  --btn-bg: #7c4ddb;
  --btn-bg-hover: #6a3bc9;
  --btn-fg: #ffffff;
  --ghost-hover: rgba(255,255,255,.06);
  color-scheme: dark;
}

/* ---------- Light theme (html[data-theme="light"]; default is dark) ---------- */
html[data-theme="light"] {
  /* Inverted from the usual light-theme arrangement: the page is plain white and every surface
     laid on it — cards, the footer band, the drawer, the note boxes — is the grey. A white card on
     a grey page reads as a sheet of paper; a grey card on a white page reads as a control, which is
     what these are. */
  --bg: #ffffff;
  --bg-soft: #eef1f6;
  --panel: #f4f6fa;
  --panel-2: #e9edf4;
  --border: #dbe2ed;
  --border-soft: #e6ebf3;
  --text: #101b2d;
  --muted: #4a5a72;
  --faint: #75849a;
  --idle: #9aa9bf;
  /* Light theme takes the SAME brand hues, darkened so they hold contrast on white. */
  --brand: #6938ef;
  --brand-2: #a93aea;
  --brand-3: #1570ef;
  --good: #047857;
  --warn: #b45309;
  --grad: #6938ef;
  --grad-soft: rgba(169,58,234,.10);
  --shadow: 0 24px 60px -28px rgba(23,34,61,.22);
  --btn-bg: #6938ef;
  --btn-bg-hover: #5629d4;
  --btn-fg: #ffffff;
  --ghost-hover: rgba(16,27,45,.06);
  color-scheme: light;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; scroll-padding-top: 90px; }
/* Nothing is allowed to make the page wider than the phone: one overflowing element and the whole
   layout pans sideways, every section broken off at the left edge. The overflow stays on the BODY,
   not the root — the root's own overflow is what took the sticky bar off the screen once before
   (see the drawer note further down) — and body's value propagates to the viewport just the same.
   clip over hidden because hidden still permits a pan once something has overflowed; overscroll
   stops the sideways rubber-band that shows the same emptiness. Anything too old for either keeps
   the plain hidden above it. */
html { overscroll-behavior-x: none; }

body {
  margin: 0;
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  overflow-x: clip;
  overscroll-behavior-x: none;
}

/* ambient background glow — monochrome (subtle light pools, no hue) */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(900px 500px at 78% -8%, rgba(255,255,255,.05), transparent 60%),
    radial-gradient(800px 520px at 8% 8%, rgba(255,255,255,.035), transparent 55%),
    radial-gradient(700px 700px at 50% 120%, rgba(255,255,255,.03), transparent 60%);
}
html[data-theme="light"] body::before {
  background:
    radial-gradient(900px 500px at 78% -8%, rgba(16,27,45,.05), transparent 60%),
    radial-gradient(800px 520px at 8% 8%, rgba(16,27,45,.035), transparent 55%),
    radial-gradient(700px 700px at 50% 120%, rgba(16,27,45,.03), transparent 60%);
}
/* Footer (assembled in main.js): a big brand mark on the left, the note box on the right, then the
   link columns spread across the full width beneath them. */
.foot-note {
  max-width: none;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-soft);
  padding: 12px 14px; display: grid; gap: 8px;
}
.foot-note-head {
  font-size: 11px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--brand-2); margin-bottom: 2px;
}
.foot-note-row { display: flex; align-items: flex-start; gap: 10px; }
.foot-note-txt b { color: var(--text); font-weight: 600; margin-right: 6px; }
.foot-note-ic {
  flex: 0 0 auto; width: 25px; height: 25px; border-radius: 8px; background: var(--grad-soft);
  border: 1px solid var(--border); display: grid; place-items: center; color: var(--brand-2);
}
.foot-note-ic svg { width: 15px; height: 15px; }
.foot-note-txt { color: var(--faint); font-size: 12.5px; line-height: 1.5; padding-top: 3px; }

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }

.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }

/* Read by a screen reader, invisible on screen. Not display:none, which would take it out of the
   accessibility tree along with the layout. Used where the visible thing is artwork carrying its own
   words — the store badges — so the accessible name is real text rather than an attribute. */
.vh {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---------- Nav ---------- */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: 1px solid var(--border-soft);
}
/* The blur and the tint sit on a PSEUDO-ELEMENT, not on .nav itself. backdrop-filter makes the
   element carrying it the containing block for its fixed descendants, so with the filter on .nav
   the drawer's top/left/bottom resolved against the 64px bar: it painted a strip inside the bar and
   nothing below it. The pseudo has no descendants, so the drawer measures against the viewport. */
.nav::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  backdrop-filter: saturate(140%) blur(14px);
  -webkit-backdrop-filter: saturate(140%) blur(14px);
  background: rgba(17,24,39,.82);
}
/* Three zones: tabs left, mark centre, actions right. The mark is positioned against the BAR
   rather than laid out between the two side zones, so it stays optically centred even though the
   left and right zones are different widths (and differ page to page). */
.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  height: 64px;
  position: relative;
}
.brand {
  display: flex; align-items: center; gap: 11px; font-weight: 700; letter-spacing: -.02em; font-size: 18px;
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); white-space: nowrap;
}
.brand .logo { width: 30px; height: 30px; border-radius: 9px; flex: 0 0 auto; }
/* One word, one colour: no gradient and no accent on the BI. */
.brand b { color: inherit; }

/* Page tabs, mirroring MyBI's own Settings sub-tab bar: a bordered pill row, icon + label per tab,
   the active one in the accent rather than merely brighter. */
.nav-tabs {
  display: flex; gap: 3px; padding: 4px; align-items: center;
  border: 1px solid var(--border); border-radius: 12px; background: var(--bg-soft);
}
.nav-tab {
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
  border-radius: 9px; padding: 7px 12px; color: var(--muted);
  font-size: 13.5px; font-weight: 600;
  transition: background .12s ease, color .12s ease, transform .16s ease;
}
/* Same hover language as the feature cards: the tile lifts and its icon springs. */
.nav-tab-ic { width: 16px; height: 16px; flex: 0 0 auto; transition: transform .32s cubic-bezier(.34,1.56,.64,1); }
.nav-tab:hover { color: var(--text); background: var(--ghost-hover); transform: translateY(-2px); }
.nav-tab:hover .nav-tab-ic { transform: scale(1.14) rotate(-4deg); }
/* In the drawer the tabs are full-width rows; lifting them looks like a wobble, so only the icon
   moves there. */
.nav-compact .nav-tab:hover { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .nav-tab, .nav-tab-ic, .nav-tab:hover, .nav-tab:hover .nav-tab-ic { transition: none; transform: none; }
}
.nav-tab.on { color: var(--brand-2); background: color-mix(in srgb, var(--brand-2) 14%, transparent); }

.nav-actions { display: flex; align-items: center; gap: 10px; }

/* Burger: hidden until the bar can no longer hold both side zones. */
.nav-burger {
  display: none; width: 38px; height: 38px; padding: 0; cursor: pointer;
  align-items: center; justify-content: center;
  background: transparent; border: 1px solid var(--border); border-radius: 10px; color: var(--text);
}
.nav-burger svg { width: 20px; height: 20px; }
.nav-burger:hover { background: var(--ghost-hover); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 9px;
  user-select: none; -webkit-user-select: none;
  padding: 11px 18px; border-radius: 11px; font-weight: 600; font-size: 14.5px;
  border: 1px solid transparent; cursor: pointer; transition: transform .12s, box-shadow .18s, background .18s, border-color .18s;
  white-space: nowrap;
}
.btn svg { width: 17px; height: 17px; flex: 0 0 auto; }
/* HOVER MUST STAY DARKER THAN THE TEXT. The hover violet was lighter than the resting one, so the
   button got paler exactly when the pointer was on it and the white label lost contrast. Hover now
   DEEPENS, which is also the direction a pressed control is expected to move. */
.btn-primary { background: var(--btn-bg); color: var(--btn-fg); box-shadow: 0 8px 22px -14px rgba(105,56,239,.55); }
.btn-primary:hover { transform: translateY(-1px); background: var(--btn-bg-hover); box-shadow: 0 12px 28px -14px rgba(105,56,239,.6); }
.btn-primary:active { transform: translateY(0); }
.btn-sm svg { width: 15px; height: 15px; }
.btn-ghost { background: transparent; border-color: var(--border); color: var(--text); }
.btn-ghost:hover { background: var(--ghost-hover); border-color: var(--faint); }
.btn-sm { padding: 8px 14px; font-size: 13.5px; border-radius: 9px; }

/* ---------- Hero ---------- */
/* Tight at the bottom: the CTA row already carries 22px of its own for the tabs that hang below
   it, and the features section adds its own lead-in, so the hero contributes almost nothing. */
.hero { padding: 22px 0 6px; position: relative; }
/* Two columns only when there is something to put in the second one. The hero used to pair the copy
   with the screenshot slider; with the slider gone it is a single centred column rather than a
   half-empty grid. Kept as :has() so re-adding a slider restores the two-up layout by itself. */
.hero-grid { display: grid; grid-template-columns: 1.05fr .95fr; gap: 56px; align-items: center; }
/* Wider than the copy needs, because the five store buttons do: at 760px they could only sit two to
   a row. The headline keeps the narrower measure so widening the column did not turn a two-line
   headline into a one-and-a-bit one. */
.hero-grid:not(:has(.shot-slider)) { grid-template-columns: 1fr; max-width: 940px; text-align: center; }
.hero-grid:not(:has(.shot-slider)) h1.hero-title { max-width: 760px; margin-inline: auto; }
.hero-grid:not(:has(.shot-slider)) .hero-cta,
.hero-grid:not(:has(.shot-slider)) .hero-meta { justify-content: center; }
.eyebrow {
  display: inline-flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600;
  color: var(--brand-2); background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.2);
  padding: 5px 12px; border-radius: 999px; margin-bottom: 16px; letter-spacing: .01em;
}
.eyebrow .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--brand-2); box-shadow: 0 0 10px var(--brand-2); }
/* One step down from the old 38–60px: at laptop widths the headline filled two full lines and read
   as a poster rather than a page. */
h1.hero-title {
  font-size: clamp(30px, 4.4vw, 47px); line-height: 1.06; letter-spacing: -.03em;
  margin: 0 0 34px; font-weight: 800;
}
/* Purple running into the logo's pink rather than flat violet — the mark itself carries both hues,
   so the highlighted words read as brand instead of as a tinted word. */
h1.hero-title .g {
  background-image: linear-gradient(100deg, var(--brand-2) 8%, #ff8fd6 92%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
html[data-theme="light"] h1.hero-title .g { background-image: linear-gradient(100deg, var(--brand-2) 8%, #ec4899 92%); }
/* Two headlines sharing one grid cell: the cell is as tall as the taller line, so the cross-fade
   moves nothing below it. Without JS the first line keeps .on and the hero is simply static. */
.rot { display: grid; }
.rot-line {
  grid-area: 1 / 1; opacity: 0; transform: translateY(.22em);
  transition: opacity .55s ease, transform .55s ease;
}
.rot-line.on { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .rot-line { transition: none; } }
.hero-cta { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.hero-meta { display: flex; gap: 20px; flex-wrap: wrap; margin-top: 30px; color: var(--faint); font-size: 13.5px; }
.hero-meta span { display: inline-flex; align-items: center; gap: 7px; }
.hero-meta svg { width: 15px; height: 15px; color: var(--brand-2); }

/* ---------- App mockup ---------- */
.mock {
  height: 400px; display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: 16px; overflow: hidden;
  background: linear-gradient(180deg, #0e1623, #0b111c);
  box-shadow: var(--shadow); position: relative;
}
.mock::after { content:""; position:absolute; inset:0; pointer-events:none; box-shadow: inset 0 1px 0 rgba(255,255,255,.04); border-radius:16px; }
.mock-bar { flex: 0 0 auto; display: flex; align-items: center; gap: 7px; padding: 11px 14px; border-bottom: 1px solid var(--border-soft); background: rgba(255,255,255,.015); }
.mock-bar i { width: 11px; height: 11px; border-radius: 50%; display: inline-block; }
.mock-bar i:nth-child(1){ background:#ff5f57; } .mock-bar i:nth-child(2){ background:#febc2e; } .mock-bar i:nth-child(3){ background:#28c840; }
.mock-bar .tt { margin-left: 10px; font-size: 12px; color: var(--faint); font-family: var(--mono); }
.mock-body { display: grid; grid-template-columns: 46px 1fr; flex: 1; min-height: 0; }
.mock-rail { position: relative; border-right: 1px solid var(--border-soft); padding: 8px 0; display: flex; flex-direction: column; gap: 8px; align-items: center; }
.rail-pill { position: absolute; left: 8px; top: 8px; width: 30px; height: 30px; border-radius: 9px; background: var(--btn-bg); box-shadow: 0 6px 16px -8px rgba(255,255,255,.85); transition: transform .45s cubic-bezier(.4,0,.2,1); z-index: 0; }
.mr-ic { position: relative; z-index: 1; width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center; color: var(--muted); transition: color .3s; }
.mr-ic svg { width: 16px; height: 16px; }
.mr-ic.on { color: #fff; }
.mock-canvas { padding: 16px; display: grid; grid-template-columns: 1fr 1fr; grid-auto-rows: minmax(78px, auto); gap: 12px; }
.card-mini { border: 1px solid var(--border-soft); border-radius: 10px; background: rgba(255,255,255,.02); padding: 12px; display:flex; flex-direction:column; gap:9px; }
.card-mini .lbl { font-size: 10.5px; color: var(--faint); text-transform: uppercase; letter-spacing: .08em; }
.kpi .num { font-size: 24px; font-weight: 800; letter-spacing: -.02em; }
.kpi .num.g { color: var(--brand-2); }
.bars { display: flex; align-items: flex-end; gap: 7px; height: 62px; }
.bars span { flex: 1; border-radius: 4px 4px 0 0; background: linear-gradient(180deg, var(--brand), rgba(255,255,255,.25)); }
.bars span:nth-child(2){ background: linear-gradient(180deg, var(--brand-3), rgba(255,255,255,.25)); }
.bars span:nth-child(3){ background: linear-gradient(180deg, var(--brand-2), rgba(255,255,255,.25)); }
.spark { height: 62px; width: 100%; }
.donut { width: 60px; height: 60px; border-radius: 50%; margin: 2px auto; background:
  conic-gradient(var(--brand) 0 38%, var(--brand-3) 38% 67%, var(--brand-2) 67% 100%); position: relative; }
.donut::after { content:""; position:absolute; inset:14px; border-radius:50%; background:#0c1320; }
.span-2 { grid-column: span 2; }

/* hero auto-playing showcase (carousel of areas) */
.mock-progress { flex: 0 0 auto; height: 2px; background: rgba(255,255,255,.06); }
.mock-progress > i { display: block; height: 100%; width: 0; background: var(--btn-bg); }
.mock-stage { position: relative; flex: 1; min-height: 0; overflow: hidden; }
.mock-slide { position: absolute; inset: 0; opacity: 0; transform: translateY(10px); transition: opacity .5s ease, transform .5s ease; pointer-events: none; }
.mock-slide.on { opacity: 1; transform: none; }
.mock-pad { padding: 14px 16px; height: 100%; box-sizing: border-box; display: flex; flex-direction: column; }
.mock-pad.mid { justify-content: center; }
.mock-pad.mock-center { display: grid; place-items: center; }
.mock-pad .side-title { font-size: 10px; text-transform: uppercase; letter-spacing: .08em; color: var(--faint); margin: 0 0 10px; }
.mini-tbl { width: 100%; border-collapse: collapse; font-size: 11.5px; }
.mini-tbl th { text-align: left; color: var(--faint); font-weight: 600; text-transform: uppercase; font-size: 9px; letter-spacing: .04em; padding: 6px 10px; background: rgba(255,255,255,.03); border-bottom: 1px solid var(--border-soft); }
.mini-tbl td { color: var(--muted); padding: 7px 10px; border-bottom: 1px solid var(--border-soft); }
.mini-tbl td:nth-child(n+2) { text-align: right; font-variant-numeric: tabular-nums; color: var(--text); }
.mini-tbl tr:hover td { background: rgba(255,255,255,.02); }
.mini-model { width: 100%; height: auto; max-height: 100%; }
.mock-pad .plug { padding: 8px; border: 1px solid var(--border-soft); border-radius: 9px; margin-bottom: 8px; background: rgba(255,255,255,.02); }
.mock-pad .prow { padding: 8px; border: 1px solid var(--border-soft); border-radius: 9px; margin-bottom: 8px; background: rgba(255,255,255,.02); }
.mock-cap { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 9px 14px; border-top: 1px solid var(--border-soft); background: rgba(255,255,255,.015); }
.mock-cap .cap-txt { font-size: 11.5px; color: var(--muted); }
.mock-cap .cap-txt b { color: var(--text); }
.mock-cap .cap-dots { display: flex; gap: 5px; align-items: center; }
.mock-cap .cap-dots i { width: 6px; height: 6px; border-radius: 50%; background: rgba(255,255,255,.16); transition: background .3s, width .3s; }
.mock-cap .cap-dots i.on { width: 16px; border-radius: 3px; background: var(--btn-bg); }

/* Hero dashboard skeleton (the right-side mockup) — monochrome KPIs + line/bar/donut,
   mirroring a real MyBI canvas. */
.mock-app { flex: 1; min-height: 0; display: flex; }
.mock-side { flex: 0 0 38px; border-right: 1px solid var(--border-soft); display: flex; flex-direction: column; align-items: center; gap: 11px; padding: 13px 0; }
.ms-ic { width: 18px; height: 18px; border-radius: 6px; background: var(--border); }
.ms-ic.on { background: var(--text); opacity: .8; }
.mock-main { flex: 1; min-width: 0; min-height: 0; padding: 13px; display: flex; flex-direction: column; gap: 10px; }
.mock-foot { flex: 0 0 auto; display: flex; align-items: center; gap: 7px; padding: 7px 12px; border-top: 1px solid var(--border-soft); background: rgba(255,255,255,.015); }
.mf-tab { font-size: 10.5px; color: var(--faint); padding: 3px 9px; border-radius: 5px; }
.mf-tab.on { color: var(--text); background: var(--bg-soft); }
.mf-status { margin-left: auto; font-size: 10px; color: var(--faint); }
.dk-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 9px; }
.dk-kpi { background: var(--bg-soft); border: 1px solid var(--border-soft); border-radius: 9px; padding: 9px 10px; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.dk-k-t { font-size: 9.5px; color: var(--faint); text-transform: uppercase; letter-spacing: .05em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dk-k-v { font-size: 17px; font-weight: 700; color: var(--text); line-height: 1.1; }
.dk-k-v small { font-size: 9.5px; font-weight: 500; color: var(--muted); margin-left: 2px; }
.dk-k-d { font-size: 9.5px; color: var(--faint); }
.dk-charts { display: grid; grid-template-columns: 1.5fr 1fr 1fr; gap: 9px; flex: 1; min-height: 0; }
.dk-card { background: var(--bg-soft); border: 1px solid var(--border-soft); border-radius: 9px; padding: 10px 11px; display: flex; flex-direction: column; gap: 8px; min-height: 0; }
.dk-c-t { font-size: 10.5px; color: var(--muted); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dk-line { width: 100%; flex: 1; min-height: 0; color: var(--text); }
.dk-bars { display: flex; align-items: flex-end; gap: 5px; flex: 1; min-height: 0; }
.dk-bars i { flex: 1; background: var(--text); border-radius: 3px 3px 0 0; opacity: .8; }
.dk-pie { width: 74px; height: 74px; align-self: center; margin: auto; color: var(--text); transform: rotate(-90deg); }

/* ---------- Section scaffolding ---------- */
/* Tightened from 80px: with the slider and CTA band gone the page is short, and the old
   rhythm left large empty bands between the little content that remains. */
section { padding: 34px 0; }
/* Scoped, not a change to section: the features block follows the hero's buttons directly, and
   a full section's worth of lead-in there read as a gap rather than as a break. */
#features { padding-top: 14px; }
.sec-head { max-width: 720px; margin: 0 auto 20px; text-align: center; }
.sec-head.left { text-align: left; margin-left: 0; }
.kicker { display: inline-block; color: var(--brand-2); font-weight: 700; font-size: 13px; letter-spacing: .12em; text-transform: uppercase; margin-bottom: 6px; }
h2.sec-title { font-size: clamp(22px, 2.8vw, 31px); letter-spacing: -.025em; margin: 8px 0 14px; font-weight: 800; line-height: 1.12; }
.sec-sub { color: var(--muted); font-size: 15.5px; margin: 0; }

/* ---------- Principles strip ---------- */
.principles { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--border-soft); border: 1px solid var(--border-soft); border-radius: var(--radius); overflow: hidden; }
.principles .p { background: var(--bg-soft); padding: 24px 22px; }
.principles .p .ic { width: 36px; height: 36px; border-radius: 10px; background: var(--grad-soft); display: grid; place-items: center; margin-bottom: 14px; color: var(--brand-2); }
.principles .p .ic svg { width: 19px; height: 19px; }
.principles .p h3 { font-size: 16px; margin: 0 0 6px; letter-spacing: -.01em; }
.principles .p p { margin: 0; color: var(--muted); font-size: 14px; }


/* Linux's own mark, sized with the other button glyphs. The Apple and Microsoft ones that used to
   sit beside it are gone: both stores now show their vendor's badge artwork, which carries its own
   mark. */
.btn .lx-logo { width: 16px; height: 16px; }

/* Platform marks on the System requirements OS line. */
.os-item { display: inline-flex; align-items: center; gap: 5px; margin-right: 10px; white-space: nowrap; }
.os-mark { width: 12px; height: 12px; flex: 0 0 auto; color: var(--muted); }

/* ---------- "Data → Dashboard → Share" ---------- */
/* The section title says the whole product in seven words; this draws the same sentence. It runs
   ONCE, the first time it is scrolled into view — a loop would turn a full stop into a fidget. */
/* One font-size drives the diagram and every measurement under it is in em, so the chips, their
   icons and the arrows shrink together as the screen narrows rather than holding desktop sizes and
   pushing the row off the side. From 517px up the clamp sits on its ceiling, which is the 15.5px
   the diagram has always been — the em values below are that layout, converted. */
.flowline {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
  font-size: clamp(11px, 3vw, 15.5px);
  gap: .65em; margin-top: 16px;
}
/* Rounded rectangles, not pills, and sized up: these three are the hero's one diagram, so they read
   as the cards the rest of the page is built from rather than as tags. */
.fl-node {
  display: inline-flex; align-items: center; gap: .65em;
  padding: .84em 1.42em; border: 1px solid var(--border); border-radius: .84em;
  background: var(--panel); color: var(--muted); font-weight: 600;
  opacity: 0; transform: translateY(6px);
}
.fl-node svg { width: 1.23em; height: 1.23em; color: var(--brand-2); }
.fl-node b { color: var(--text); font-weight: 600; }
.fl-arrow { display: inline-flex; color: var(--faint); opacity: 0; }
.fl-arrow svg { width: 2.2em; height: .78em; }
.fl-arrow .fl-line, .fl-arrow .fl-head { stroke-dasharray: 30; stroke-dashoffset: 30; }
.flowline.go .fl-node { animation: fl-in .42s cubic-bezier(.34,1.4,.64,1) forwards; }
.flowline.go .fl-arrow { animation: fl-fade .3s ease forwards; }
.flowline.go .fl-arrow .fl-line,
.flowline.go .fl-arrow .fl-head { animation: fl-draw .45s ease forwards; }
/* Each step waits for the one before it, so it reads left to right like the sentence above it. */
.flowline.go > :nth-child(1) { animation-delay: .05s; }
.flowline.go > :nth-child(2), .flowline.go > :nth-child(2) path { animation-delay: .35s; }
.flowline.go > :nth-child(3) { animation-delay: .6s; }
.flowline.go > :nth-child(4), .flowline.go > :nth-child(4) path { animation-delay: .9s; }
.flowline.go > :nth-child(5) { animation-delay: 1.15s; }
/* The one flourish: a light sweeps across each chip as it lands. */
.flowline.go .fl-node::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(100deg, transparent 30%, color-mix(in srgb, var(--brand-2) 22%, transparent) 50%, transparent 70%);
  animation: fl-sheen .9s ease-out forwards; animation-delay: inherit;
}
.fl-node { position: relative; overflow: hidden; }
@keyframes fl-in { to { opacity: 1; transform: none; } }
@keyframes fl-fade { to { opacity: 1; } }
@keyframes fl-draw { to { stroke-dashoffset: 0; } }
@keyframes fl-sheen { from { transform: translateX(-120%); } to { transform: translateX(120%); } }
/* The curved connector is for the wrapped row only; the dash has to be the length of the longer
   path or it would finish drawing halfway along. */
.fl-curve { display: none; }
.fl-curve .fl-line { stroke-dasharray: 190; stroke-dashoffset: 190; }
@media (prefers-reduced-motion: reduce) {
  .fl-node, .fl-arrow { opacity: 1; transform: none; }
  .fl-arrow .fl-line, .fl-arrow .fl-head { stroke-dashoffset: 0; }
  .flowline.go .fl-node, .flowline.go .fl-arrow, .flowline.go .fl-node::after { animation: none; }
}
/* Phone. Scaling the type alone does not buy enough room: at 11px the desktop's 22px of side
   padding is wider than the word it surrounds, so the chips give up padding and the arrows shorten
   as well. Proportions, not just size — that is what fits Data → Dashboard → Share on one line all
   the way down to 360px, which is the whole point of not breaking the row. */
@media (max-width: 560px) {
  .flowline { gap: .4em; }
  .fl-node { padding: .8em .95em; gap: .5em; border-radius: .75em; }
  .fl-arrow svg { width: 1.6em; }
}
/* Narrower than that, one line would mean type too small to read, so the row breaks in two.
   A grid rather than a wrap, because the grid is what anchors the curve: the connector's cell is the
   column the Dashboard chip defines, so the cell's right edge IS Dashboard's right edge, and Share —
   sent to the end of the two columns beside it — finishes where that cell starts. The curve then only
   has to run corner to corner of its own box, with nothing measured at runtime.
   (Wrapping instead left the second arrow stranded on the row below, pointing at Share out of empty
   space with Dashboard nowhere near it.) */
@media (max-width: 359px) {
  .flowline {
    display: grid; width: max-content; margin-inline: auto;
    grid-template-columns: auto auto auto; align-items: center;
    column-gap: .4em; row-gap: 16px;
  }
  .flowline > :nth-child(1) { grid-area: 1 / 1; }
  .flowline > :nth-child(2) { grid-area: 1 / 2; }
  .flowline > :nth-child(3) { grid-area: 1 / 3; }
  .flowline > :nth-child(5) { grid-area: 2 / 1 / 3 / 3; justify-self: end; }
  /* The negative margin is the row gap, so the curve starts on Dashboard's bottom edge rather than
     below it — align-self: stretch turns that back into height. */
  .fl-arrow-2 {
    grid-area: 2 / 3; align-self: stretch; display: block; position: relative; margin-top: -16px;
  }
  .fl-arrow-2 .fl-straight { display: none; }
  /* Out of flow deliberately. The curve carries a viewBox and no width, so in flow it would hand the
     column it shares with the Dashboard chip a replaced element's default 300px — and the chip,
     stretching to the column it no longer sized, would run off the side of the screen. */
  .fl-arrow-2 .fl-curve { display: block; position: absolute; inset: 0; width: 100%; height: 100%; }
}

/* ---------- Feature grid ---------- */
.features { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
.feature {
  border: 1px solid var(--border); border-radius: var(--radius); background: linear-gradient(180deg, var(--panel), var(--bg-soft));
  padding: 26px 24px; transition: transform .16s, border-color .16s, box-shadow .16s; position: relative;
}
.feature:hover { transform: translateY(-3px); border-color: #2b3a54; box-shadow: 0 20px 40px -24px rgba(0,0,0,.8); }
.feature .ic { width: 44px; height: 44px; border-radius: 12px; background: var(--grad-soft); border: 1px solid var(--border); display: grid; place-items: center; color: var(--brand-2); margin-bottom: 18px; }
.feature .ic svg { width: 22px; height: 22px; transition: transform .32s cubic-bezier(.34,1.56,.64,1); }
.feature .ic { transition: transform .32s cubic-bezier(.34,1.56,.64,1), background .3s ease, border-color .3s ease; }
.feature:hover .ic { transform: translateY(-2px) rotate(-4deg); border-color: var(--brand-2); }
.feature:hover .ic svg { transform: scale(1.12); }
@media (prefers-reduced-motion: reduce) {
  .feature .ic, .feature .ic svg, .feature:hover .ic, .feature:hover .ic svg { transition: none; transform: none; }
}
/* Engine marks inside the AI card: local on the left because on-device is the default, cloud on
   the right because it is opt-in and needs a key. Local marks carry their name (two of them, and
   which one you get depends on your OS); the six cloud marks would not fit as labelled chips, so
   they are logo tiles with the names spelled out underneath. */
.engines {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px;
  margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border-soft);
}
.eng-col + .eng-col { border-left: 1px solid var(--border-soft); padding-left: 16px; }
.eng-h {
  display: block; font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .09em; color: var(--faint); margin-bottom: 10px;
}
/* Second heading inside the local column: the engines run the models, the models come from these. */
.eng-h-sub { margin-top: 16px; }
/* auto-fit rather than a fixed column count: the tiles work out how many fit the space they are
   given, so the same markup is a 3-wide block inside a third-width card and one clean row once the
   card goes full width. minmax's floor is the narrowest a tile may be, not its size — the 1fr
   stretches them to share the row evenly, which is what stops the ragged last line. */
.eng-marks { display: grid; gap: 7px; grid-template-columns: repeat(auto-fit, minmax(40px, 1fr)); }
/* Only the engine row carries labels, so only it needs tracks wide enough to hold one. */
.eng-marks-engine { grid-template-columns: repeat(auto-fit, minmax(104px, 1fr)); }
/* The chevron sits against the card's icon, at the far right of that first line. The strip below
   it is a <details> body, so while closed neither it NOR its top rule exists to leave a stray
   divider across the card. */
.eng-wrap > summary {
  position: absolute; top: 33px; right: 24px; list-style: none; cursor: pointer;
  width: 30px; height: 30px; border-radius: 9px; border: 1px solid var(--border);
  display: grid; place-items: center; color: var(--muted); background: var(--bg-soft);
  transition: color .14s ease, border-color .14s ease, background .14s ease;
}
.eng-wrap > summary::-webkit-details-marker { display: none; }
.eng-wrap > summary::marker { content: ""; }
.eng-wrap > summary svg { width: 16px; height: 16px; transition: transform .2s ease; }
.eng-wrap > summary:hover { color: var(--text); border-color: var(--faint); background: var(--ghost-hover); }
.eng-wrap[open] > summary { color: var(--brand-2); border-color: var(--brand-2); }
.eng-wrap[open] > summary svg { transform: rotate(180deg); }
.eng-mark {
  display: flex; align-items: center; justify-content: center; gap: 7px; padding: 6px 9px;
  border: 1px solid var(--border); border-radius: 9px; background: var(--bg-soft);
  font-size: 12px; font-weight: 600; color: var(--muted); min-width: 0; text-align: center;
  line-height: 1.3;
}
/* Marks whose owners publish them as monochrome (Apple, Ollama, OpenAI, Kimi) are drawn in
   currentColor, so they take the text colour the way each owner intends. Give them the full text
   colour rather than the chip's muted label colour, or they read as disabled. */
.eng-mark svg { width: 15px; height: 15px; flex: 0 0 auto; color: var(--text); }
.eng-mark.mark-only { padding: 7px; }
/* Hover popup: what a vendor actually gives you. A styled ::after rather than the browser's own
   title tip, which waits a second, cannot wrap a model list legibly and is invisible on touch.
   The card is lifted while one is open so the popup is not painted over by the card after it. */
.eng-mark[data-tip] { position: relative; }
.eng-mark[data-tip]::after {
  content: attr(data-tip);
  position: absolute; bottom: calc(100% + 9px); left: 50%;
  transform: translateX(-50%) translateY(4px);
  width: max-content; max-width: min(220px, 62vw); padding: 9px 11px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: var(--shadow); color: var(--muted);
  font-size: 11.5px; font-weight: 500; line-height: 1.5; text-align: left; white-space: normal;
  opacity: 0; pointer-events: none; transition: opacity .14s ease, transform .14s ease; z-index: 4;
}
.eng-mark[data-tip]:hover::after { opacity: 1; transform: translateX(-50%) translateY(0); }
.eng-marks > .eng-mark:first-child[data-tip]::after { left: 0; transform: translateX(0) translateY(4px); }
.eng-marks > .eng-mark:first-child[data-tip]:hover::after { transform: translateX(0) translateY(0); }
.eng-marks > .eng-mark:last-child[data-tip]::after { left: auto; right: 0; transform: translateX(0) translateY(4px); }
.eng-marks > .eng-mark:last-child[data-tip]:hover::after { transform: translateX(0) translateY(0); }
.feature:has(.eng-mark[data-tip]:hover) { z-index: 3; }
/* Scoped to .feature so they beat `.feature p`, which would otherwise set them back to body size. */
.feature .eng-names { margin: 10px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--faint); }
/* Below the width where the feature grid itself is a single column, the two groups stop being
   columns too: side by side they would each get half of a phone screen. Stacked, each group gets
   the full card width, which is what turns both sets of marks into one row apiece. */
@media (max-width: 620px) {
  .engines { grid-template-columns: 1fr; gap: 16px; }
  .eng-col + .eng-col { border-left: 0; padding-left: 0; border-top: 1px solid var(--border-soft); padding-top: 16px; }
}
/* A card that takes the whole row. Two columns of labelled engines do not fit a third of one, and
   a seventh card at normal width would leave a hole in a three-track grid. */
.feature-wide { grid-column: 1 / -1; }
/* Footnote keys on the group headings. The detail they point at lives under the grid: inside the
   box it competed with the marks for the same glance. */
.eng-star { color: var(--brand-2); font-weight: 700; margin-left: 3px; }
.feat-notes {
  display: grid; gap: 7px; margin: 20px 0 0;
  color: var(--faint); font-size: 12px; line-height: 1.55;
}
/* Keys are the printer's sequence — * † ‡ § ‖ — rather than a growing run of asterisks, which by
   the fifth note was five characters wide and had to be counted to be matched to its mark. They are
   single glyphs of differing widths, so the key gets a fixed column and every note's text starts on
   the same edge. */
.feat-notes b { color: var(--brand-2); font-weight: 700; margin-right: 7px; display: inline-block; min-width: 9px; }
.feature h3 { margin: 0 0 11px; font-size: 18.5px; letter-spacing: -.015em; }
.feature p { margin: 0; color: var(--muted); font-size: 14.5px; }
.feature .tag { position: absolute; top: 20px; right: 20px; font-size: 11px; font-weight: 700; color: var(--warn); background: rgba(251,191,36,.1); border: 1px solid rgba(251,191,36,.25); padding: 3px 9px; border-radius: 999px; }

/* ---------- Split highlight ---------- */
/* minmax(0, 1fr) rather than a bare 1fr, with min-width: 0 on the items to go with it. A 1fr track
   is minmax(auto, 1fr), and that auto floor is the content's min-content width — which for the code
   block in the media half is a whole line, since it is white-space: pre. So on a phone the track
   sized itself to the longest command and carried the entire page sideways with it. Floored at
   zero, the track is simply the column width and the block scrolls inside its own box, which is
   what its overflow-x was there for all along. */
.split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 48px; align-items: center; }
.split > * { min-width: 0; }
.split.rev .split-media { order: -1; }
.split-media {
  border: 1px solid var(--border); border-radius: var(--radius); padding: 26px; background: linear-gradient(180deg, var(--panel-2), var(--bg-soft));
  box-shadow: var(--shadow);
}
.bullet-list { list-style: none; padding: 0; margin: 22px 0 0; display: grid; gap: 14px; }
.bullet-list li { display: flex; gap: 12px; color: var(--muted); font-size: 15px; }
.bullet-list li svg { width: 20px; height: 20px; color: var(--good); flex: 0 0 auto; margin-top: 2px; }
.bullet-list li b { color: var(--text); font-weight: 600; }

/* flow diagram (one source of truth) */
.flow { display: grid; gap: 12px; }
.flow .node { border: 1px solid var(--border-soft); border-radius: 12px; padding: 13px 16px; background: rgba(255,255,255,.02); display: flex; align-items: center; gap: 12px; font-size: 14px; }
.flow .node .b { width: 30px; height: 30px; border-radius: 8px; background: var(--grad-soft); display:grid; place-items:center; color: var(--brand-2); flex:0 0 auto; }
.flow .node .b svg { width: 16px; height: 16px; }
.flow .core { background: var(--btn-bg); color: #0a0e17; border-color: transparent; font-weight: 700; }
.flow .core .b { background: rgba(10,14,23,.18); color: #0a0e17; }
.flow .arrow { text-align: center; color: var(--faint); font-size: 18px; line-height: 1; }
.flow .row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

/* ai chips */
.ai-chips { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 6px; }
.ai-chip { border: 1px solid var(--border); background: rgba(255,255,255,.03); border-radius: 999px; padding: 8px 15px; font-size: 13.5px; color: var(--muted); display:inline-flex; align-items:center; gap:8px; }
.ai-chip .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--brand-2); }

/* ---------- Open source / trust ---------- */
.trust-lead {
  border: 1px solid var(--border); border-radius: var(--radius); padding: 30px 32px;
  background: var(--grad-soft); display: grid; grid-template-columns: 1fr auto; gap: 26px;
  align-items: center; margin-bottom: 18px; position: relative; overflow: hidden;
}
.trust-lead::before { content:""; position:absolute; inset:0; background: radial-gradient(520px 180px at 12% -30%, rgba(255,255,255,.22), transparent 70%); pointer-events:none; }
.trust-lead .tl-txt { position: relative; }
.trust-lead h3 { margin: 0 0 8px; font-size: 21px; letter-spacing: -.02em; }
.trust-lead p { margin: 0; color: var(--muted); font-size: 15px; max-width: 620px; }
.trust-lead .tl-cta { position: relative; display: flex; gap: 10px; flex-wrap: wrap; }
.feature--open .ic { color: var(--good); background: rgba(54,211,153,.1); border-color: rgba(54,211,153,.22); }
.trust-note {
  display: flex; gap: 12px; align-items: flex-start; margin-top: 18px; padding: 16px 18px;
  border: 1px solid var(--border-soft); border-radius: 12px; background: rgba(255,255,255,.02);
  color: var(--muted); font-size: 14px;
}
.trust-note svg { width: 19px; height: 19px; color: var(--brand-2); flex: 0 0 auto; margin-top: 1px; }
.trust-note b { color: var(--text); }

/* ---------- Tech strip ---------- */
.tech { display: grid; grid-template-columns: repeat(4,1fr); gap: 16px; }
.tech .t { border: 1px solid var(--border); border-radius: 12px; padding: 20px; background: var(--bg-soft); }
.tech .t .k { font-family: var(--mono); font-size: 12px; color: var(--brand-2); letter-spacing: .02em; }
.tech .t .v { font-weight: 700; margin-top: 6px; font-size: 15.5px; letter-spacing: -.01em; }
.tech .t p { margin: 6px 0 0; color: var(--faint); font-size: 13px; }

/* ---------- Download ---------- */
.download { position: relative; }
.dl-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 300px)); gap: 16px; margin-top: 0; justify-content: center; }
/* One store, one card — a single card stretched across a two-column track reads as a layout bug. */
.dl-grid.dl-grid-one { grid-template-columns: minmax(0, 340px); }
/* .sec-head reserves space for a title + sub; with only the kicker left it must not leave a gap. */
.download .sec-head:not(:has(.sec-title)) { margin-bottom: 16px; }
.dl-card {
  border: 1px solid var(--border); border-radius: var(--radius); padding: 26px 22px; text-align: center;
  background: linear-gradient(180deg, var(--panel), var(--bg-soft)); position: relative; overflow: hidden;
}
.dl-card .os { width: 46px; height: 46px; margin: 0 auto 14px; color: var(--text); }
.dl-card .os svg { width: 100%; height: 100%; }
.dl-card h3 { margin: 0 0 4px; font-size: 18px; }
.dl-card .desc { color: var(--faint); font-size: 13px; margin: 0 0 18px; min-height: 34px; }
.dl-btn {
  width: 100%; display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 11px 16px; border-radius: 10px; font-weight: 600; font-size: 14px;
  background: rgba(255,255,255,.04); border: 1px solid var(--border); color: var(--muted); cursor: not-allowed;
}
.dl-btn-live {
  background: var(--btn-bg); border-color: transparent; color: var(--btn-fg); cursor: pointer;
  text-decoration: none; transition: background .15s ease, transform .12s ease;
}
.dl-btn-live:hover { background: var(--btn-bg-hover); transform: translateY(-1px); }
.btn-soon { cursor: default; color: var(--muted); position: relative; }
.btn-soon:hover { background: transparent; border-color: var(--border); }
/* The pill is a TAB ON TOP of the button, not a chip inside it. Inline it ate ~80px of the label's
   room, so the two "coming soon" buttons could never be the same size as the three plain ones.
   Lifted out of the flow, every button in the row is one box, and the pill reads as an extension of
   it: rounded on the outer edge, flat and borderless where the two meet. top:100% resolves against
   the PADDING box, so the tab's first pixel lands on the button's bottom border rather than below
   it and the seam is a single line instead of two stacked ones. It hangs from the bottom RIGHT,
   inset by the button's corner radius so its own edge meets the straight run of the border rather
   than the curve, and its corners are rounded less than the button's so it reads as a tab on the
   box rather than a second, competing pill. */
.btn .soon {
  position: absolute; right: 8px; top: 100%;
  font-size: 10px; font-weight: 700; letter-spacing: .02em; line-height: 1; color: var(--warn);
  background: color-mix(in srgb, var(--warn) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--warn) 34%, transparent);
  border-top: 0; padding: 5px 10px 4px; border-radius: 0 0 5px 5px;
}
/* Every button the same box, in every row the line wraps into. The basis lets them stretch to fill
   the width, and the shared cap is what keeps a short trailing row (4+1, 3+2) from finishing wider
   than a full one — with a fixed width they would have matched but left a gap, and with a pure
   grow they would have matched only within a row. The row gap is the height of a "coming soon"
   tab plus clearance, since those sit above their buttons; padding-top is the same headroom at the
   top of the row, pulled back out with the negative margin so the gap under the sub-heading does
   not grow by it. */
/* 590px is exactly three buttons and two gaps at the cap below, so the row breaks 3 + 2 on its own:
   the three platforms, then the two page links. A width is doing this rather than a break element
   because a 100%-basis spacer would sit on a line of its own and cost a second row-gap. */
.hero-cta {
  display: flex; flex-wrap: wrap; gap: 26px 10px; justify-content: center; align-items: stretch;
  padding-bottom: 22px; max-width: 590px; margin-inline: auto;
}
.hero-cta > * { flex: 1 1 158px; max-width: 190px; justify-content: center; height: 46px; }
/* 8px corners, matching the 8px the tab is inset by, so the tab's edge lands exactly where the
   button's top border stops curving. At the button's usual 11px the tab either sat in from the
   corner with a visible step or overhung the curve. */
.hero-cta .btn { padding: 0 11px; font-size: 13.5px; gap: 7px; border-radius: 8px; }

/* ---------- Store badges (each vendor's official artwork) ---------- */
/* The hero's CTA is two rows rather than one because it holds two kinds of thing. A store badge is
   supplied artwork: fixed ratio, its own plate and corner radius, not ours to stretch or restyle.
   The buttons under it are the opposite — they exist to be one shared box. Stacking the two lets
   each keep its own rule instead of one compromising the other. The rest of the site's .hero-cta
   (the CTA band, the other pages) is untouched; this only applies where .hero-cta-split is set. */
.hero-cta-split { flex-direction: column; flex-wrap: nowrap; gap: 22px; max-width: 620px; }
/* .hero-cta > * makes every child an equal 46px box. Its children here are two ROWS, so that has to
   come back off before either row can size itself. */
.hero-cta-split > * { flex: 0 0 auto; width: 100%; max-width: none; height: auto; }
/* 46px, matching .cta-more's buttons exactly. Whole numbers only, at every step: nearly all of the
   Microsoft mark's detail sits in the middle third of the glyph (a gradient bag with four small
   squares), so a fractional height — 41.25px, which is what a vw clamp gave a 393px phone — put
   every one of those edges between pixels and smeared it. Steps rather than a clamp is how that
   stays guaranteed. Matching heights also keep the App Store badge no smaller than the one beside
   it, which is Apple's rule.
   The two belong side by side: stacked, the pair reads as two separate offers rather than a choice
   of platform, and it pushes the whole hero down a badge's height on the screen that can least
   afford it. Side by side costs 7.56 badge-heights plus the gap, so below ~430px the height has to
   come down to buy the width — which is the trade worth making, since a badge two points shorter
   still reads and a badge on its own line changes what the row means. */
.cta-stores {
  --badge-h: 46px;
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 10px;
}
@media (max-width: 430px) { .cta-stores { --badge-h: 44px; gap: 8px; } }
@media (max-width: 384px) { .cta-stores { --badge-h: 40px; gap: 8px; } }
@media (max-width: 348px) { .cta-stores { --badge-h: 34px; gap: 6px; } }
.cta-more {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: stretch;
  gap: 26px 10px; max-width: 590px; margin-inline: auto;
}
.cta-more > * { flex: 1 1 158px; max-width: 190px; justify-content: center; height: 46px; }
/* The badge is meant to sit in this row as one of the buttons, so it takes the button's box: the
   same 46px height, the same 8px corner and the same 1px var(--border) rule, in both themes. Only
   the width is its own, since the artwork's ratio sets that and may not be stretched — and the
   buttons beside it are flexible between 158 and 190 anyway, so a badge at 179 is inside the range
   the row already spans.
   A background rather than an <img>, so the link IS the badge with no second box to keep in step.
   aspect-ratio against the artwork's own viewBox turns the shared height into the right width
   without hardcoding one. */
.store-badge {
  display: block; height: var(--badge-h); width: auto;
  border: 1px solid var(--border); border-radius: 8px;
  background-repeat: no-repeat; background-position: center;
  /* The plate drawn INTO the artwork has its own corner — rounder than 8px on Apple's, squarer on
     Microsoft's — so at the corners it would either fall short of this box and leak a sliver of
     page, or sit inside it as a second, competing curve. Oversizing it by 2px a side pushes that
     corner out past the box, and the box's own radius clips it: what is left is one 8px curve, the
     same one the buttons have. The 2px it costs is flat plate on both, well outside the clear space
     either mark needs. border-box, so the artwork runs under the rule rather than stopping at it. */
  background-size: calc(100% + 4px) calc(100% + 4px);
  background-origin: border-box; background-clip: border-box;
}
/* The dark plate in both themes: the white-plate artwork read as two bright slabs against the dark
   page, louder than the headline above them, and against the light page the dark plate is the
   variant each vendor nominates anyway. */
.sb-apple { aspect-ratio: 156.10054 / 40; background-image: url("badges/apple-black.svg"); }
.sb-ms { aspect-ratio: 161 / 44; background-image: url("badges/ms-dark.svg"); }
/* Focus has to be visible on artwork that carries no border of its own. */
.store-badge:focus-visible { outline: 2px solid var(--brand-2); outline-offset: 3px; }

/* Sample-project dialog */
.sample-dlg {
  border: 1px solid var(--border); border-radius: 18px; background: var(--panel);
  color: var(--text); padding: 26px 26px 22px; max-width: 460px; width: calc(100% - 32px);
  box-shadow: var(--shadow); position: relative;
}
.sample-dlg::backdrop { background: rgba(3,6,12,.55); }
.sample-dlg h2 { margin: 0 0 8px; font-size: 20px; letter-spacing: -.02em; }
.sample-dlg > p { margin: 0 0 18px; color: var(--muted); font-size: 14.5px; line-height: 1.6; }
.sample-dlg .btn-primary { width: 100%; justify-content: center; }
/* Close: bordered so it reads as a control, warming to red on hover and filling on press —
   destructive-ish affordance for the one button that throws the dialog away. */
.sample-dlg-x {
  position: absolute; top: 12px; right: 12px; width: 32px; height: 32px; line-height: 1;
  display: grid; place-items: center;
  background: transparent; color: var(--faint); font-size: 20px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 10px;
  transition: background .14s ease, border-color .14s ease, color .14s ease, transform .1s ease;
}
.sample-dlg-x:hover {
  color: #e5484d; border-color: color-mix(in srgb, #e5484d 45%, transparent);
  background: color-mix(in srgb, #e5484d 12%, transparent);
}
.sample-dlg-x:active {
  background: #e5484d; border-color: #e5484d; color: #fff; transform: scale(.96);
}
.sample-steps { margin: 18px 0 0; padding-left: 20px; color: var(--muted); font-size: 14px; line-height: 1.75; }
.sample-steps strong { color: var(--text); }
.sample-steps code { font-family: var(--mono); font-size: 12.5px; }
.dl-btn .soon { font-size: 11px; font-weight: 700; color: var(--warn); background: rgba(251,191,36,.12); border: 1px solid rgba(251,191,36,.28); padding: 2px 8px; border-radius: 999px; }
.dl-card.store { background: linear-gradient(180deg, var(--panel-2), var(--bg-soft)); }
.dl-note { text-align: center; color: var(--faint); font-size: 13.5px; margin-top: 22px; }
.dl-note a { color: var(--brand-2); border-bottom: 1px dotted rgba(255,255,255,.4); }

/* ---------- Screenshot slider (hero + reused elsewhere) ---------- */
.shot-slider { position: relative; border-radius: 14px; overflow: hidden; border: 1px solid var(--border); background: var(--panel); box-shadow: 0 30px 80px -42px rgba(0,0,0,.6); }
.shot-frame { position: relative; aspect-ratio: 3584 / 2264; }
.shot { position: absolute; inset: 0; margin: 0; opacity: 0; transition: opacity .55s ease; pointer-events: none; }
.shot.on { opacity: 1; pointer-events: auto; }
.shot img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top left; }
.shot figcaption {
  position: absolute; left: 12px; bottom: 12px; max-width: 72%;
  padding: 6px 12px; border-radius: 999px; font-size: 12.5px; font-weight: 600;
  color: #fff; background: rgba(10,14,23,.62); backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px); border: 1px solid rgba(255,255,255,.12);
}
.shot-nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 38px; height: 38px; border-radius: 999px; border: 1px solid rgba(255,255,255,.28);
  background: rgba(10,14,23,.5); color: #fff; display: grid; place-items: center; cursor: pointer;
  opacity: 0; transition: opacity .2s, background .2s; backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
.shot-slider:hover .shot-nav, .shot-slider:focus-within .shot-nav { opacity: 1; }
.shot-nav:hover { background: rgba(10,14,23,.85); }
.shot-nav svg { width: 18px; height: 18px; }
.shot-nav.prev { left: 10px; } .shot-nav.next { right: 10px; }
.shot-dots { position: absolute; right: 14px; bottom: 14px; z-index: 3; display: flex; gap: 6px; }
.shot-dots i { width: 6px; height: 6px; border-radius: 999px; background: rgba(255,255,255,.5); cursor: pointer; transition: width .25s, background .25s; }
.shot-dots i.on { width: 18px; background: #fff; }
.shot-slider--wide { max-width: 1000px; margin: 40px auto 0; }

@media (max-width: 620px) { .shot-nav { display: none; } .shot figcaption { font-size: 11.5px; max-width: 80%; } }

/* ---------- CTA banner ---------- */
.cta-band {
  border: 1px solid var(--border); border-radius: 22px; padding: 48px; text-align: center;
  background: var(--grad-soft); position: relative; overflow: hidden;
}
.cta-band::before { content:""; position:absolute; inset:0; background: radial-gradient(600px 200px at 50% -40%, rgba(255,255,255,.25), transparent 70%); }
.cta-band h2 { font-size: clamp(22px, 2.8vw, 30px); margin: 0 0 12px; letter-spacing: -.02em; position: relative; }
.cta-band p { color: var(--muted); margin: 0 auto 26px; max-width: 540px; position: relative; }
.cta-band .hero-cta { justify-content: center; position: relative; }

/* ---------- Footer ---------- */
/* Opaque band, so the page's ambient wash does not carry on through the footer. */
/* Tighter top padding so the brand mark sits close to the start of the footer rather than floating
   in the middle of a band of empty space. */
/* Nav and footer are both --panel: the page's chrome is one tone, the body it frames is --bg, and
   cards sitting on the body are --panel again. That structure was only true in light mode, where
   grey chrome around white body reads immediately; dark mode had the nav tinted with --bg and the
   footer flat --bg, so top, middle and bottom were one undifferentiated field. The nav keeps its
   tint translucent so the blur still works; the footer takes the colour flat. */
footer { position: relative; z-index: 1; background: var(--panel); border-top: 1px solid var(--border); padding: 22px 0 26px; margin-top: 24px; }
/* The brand column carries the note box now, so it must not be so wide that the link columns wrap
   underneath it and leave the footer a tall single stack at ordinary laptop widths. It shrinks
   instead, and only genuinely narrow screens (<=620px) stack. */
.foot-grid { display: flex; align-items: stretch; gap: 20px; flex-wrap: wrap; }
/* Two columns: a sign-off line over the requirements box on the left, link columns on the right.
   Both columns are flex COLUMNS so their boxes can grow to a common height rather than one card
   floating short beside a taller one. */
/* min() on the floors, not a bare px: the floor exists to stop the two cards sitting side by side
   once they are too narrow to read, but below ~330px the floor itself was wider than the content
   box and the whole page picked up a few pixels of sideways scroll. Capping it at 100% keeps the
   floor everywhere it fits and drops it where it does not. */
.foot-left { flex: 1 1 420px; min-width: min(300px, 100%); display: flex; flex-direction: column; }
/* Centred, full width, above BOTH cards — so the two cards start on the same line. */
.foot-sign { color: var(--faint); font-size: 12.5px; text-align: center; margin: 0 0 14px; }
.foot-left .foot-note { flex: 1 1 auto; }
.foot-brand p { color: var(--faint); font-size: 14px; margin: 14px 0 0; }
/* Right-hand column: the three link groups, boxed to match the requirements box so the two halves
   of the footer read as one system. */
.foot-cols {
  flex: 1 1 380px; min-width: min(280px, 100%); align-self: stretch; align-content: start;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;
  margin-top: 0; padding: 14px 14px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-soft);
}
/* Left-aligned, because each link is a button now and a row of centred buttons has no common edge
   for the eye to run down. */
.foot-col { display: flex; flex-direction: column; align-items: stretch; text-align: left; gap: 6px; }
.foot-col h4 { display: flex; align-items: center; gap: 8px; margin: 0 0 2px; }
.foot-col-ic { width: 15px; height: 15px; flex: 0 0 auto; color: var(--brand-2); }
.foot-col a { display: inline-flex; align-items: center; gap: 7px; }
.foot-link-ic { width: 14px; height: 14px; flex: 0 0 auto; opacity: .75; }
/* Below this the Download label would meet the centred mark, so the button becomes its glyph.
   gap: 0 goes with it — the label collapses to nothing but .btn's 9px gap does not, which left the
   button 9px wider than it was tall: a stretched lozenge beside the square theme button. */
@media (max-width: 560px) {
  .nav-actions .btn-primary span,
  .nav-actions .btn-primary { font-size: 0; }
  .nav-actions .btn-primary { padding: 9px; gap: 0; }
  .nav-actions .btn-primary svg { width: 17px; height: 17px; }
  .theme-seg button { width: 24px; height: 24px; }
}
@media (max-width: 760px) {
  .foot-left { align-items: center; text-align: center; }
  .foot-left .foot-note { width: 100%; }
  .foot-note-row { justify-content: flex-start; text-align: left; }
}
.foot-col a, .foot-col h4 { max-width: 100%; }
.foot-col a span { overflow-wrap: anywhere; }
.foot-col h4 { font-size: 11.5px; text-transform: uppercase; letter-spacing: .1em; color: var(--faint); margin: 0 0 8px; }
/* Buttons, not bare text: icon then label, both hard against the left edge. */
.foot-col a {
  display: flex; align-items: center; gap: 8px;
  color: var(--muted); font-size: 12.5px; padding: 7px 9px;
  border: 1px solid var(--border-soft); border-radius: 9px; background: rgba(255,255,255,.03);
  transition: background .14s ease, border-color .14s ease, color .14s ease;
}
.foot-col a:hover { color: var(--text); background: var(--ghost-hover); border-color: var(--border); }
/* Narrow screens: three columns of one-per-line links turned six short words into a card taller
   than the page section above it. Each group becomes ONE row instead — heading, then its links
   side by side — so the whole block costs three lines rather than a full screen. */
/* Narrow: the SAME three columns as the wide layout, scaled down rather than restructured.
   Stacking them turned six short links into three full-width rows and made the footer the tallest
   block on the page; three narrow columns hold six words each without breaking a sweat. */
@media (max-width: 720px) {
  .foot-cols { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; padding: 12px 10px; }
  .foot-col { gap: 5px; }
  .foot-col h4 { font-size: 10px; letter-spacing: .07em; gap: 6px; margin: 0 0 6px; }
  .foot-col-ic { width: 13px; height: 13px; }
  .foot-col a { font-size: 11.5px; padding: 6px 8px; gap: 6px; }
  .foot-link-ic { width: 12px; height: 12px; }
}
/* Trademark note, under both cards: bordered like them but quieter, since it is small print. */
.foot-legal {
  display: flex; align-items: flex-start; gap: 10px;
  margin-top: 14px; padding: 11px 14px;
  border: 1px solid var(--border-soft); border-radius: var(--radius);
  color: var(--faint); font-size: 11.5px; line-height: 1.55;
}
.foot-legal-ic { width: 15px; height: 15px; flex: 0 0 auto; color: var(--muted); }
/* Wide: the heading is redundant beside one line of small print, so only its icon shows. */
.foot-legal-h { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; padding-top: 2px; }
.foot-legal-h span { display: none; }
.foot-legal p { margin: 0; }

/* Narrow: a titled block — icon and heading on one line, a rule under them, the small print
   below. Only here; at full width the note is one line and a heading over it would be three
   words of chrome above nine of content. */
@media (max-width: 720px) {
  .foot-legal { display: block; }
  .foot-legal-h {
    padding: 0 0 8px; margin-bottom: 9px; border-bottom: 1px solid var(--border-soft);
    color: var(--muted); font-size: 11px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .09em;
  }
  .foot-legal-h span { display: inline; }
}
.foot-bottom { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-top: 28px; padding-top: 22px; border-top: 1px solid var(--border-soft); color: var(--faint); font-size: 13px; }
.badge-oss { display:inline-flex; align-items:center; gap:7px; border:1px solid var(--border); border-radius:999px; padding:5px 12px; font-size:12.5px; color:var(--muted); }

/* ---------- Roadmap page ---------- */
.rm-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin: 8px 0 8px; }
.rm-stat { border: 1px solid var(--border); border-radius: var(--radius); padding: 22px; background: var(--bg-soft); text-align: center; }
.rm-stat .n { font-size: 34px; font-weight: 800; letter-spacing: -.03em; line-height: 1; }
.rm-stat .n.g { color: var(--brand-2); }
.rm-stat .l { color: var(--muted); font-size: 13.5px; margin-top: 8px; }
.progress-track { height: 12px; border-radius: 999px; background: var(--panel); border: 1px solid var(--border); overflow: hidden; display: flex; margin: 26px 0 6px; }
.progress-track .seg-done { background: var(--btn-bg); }
.progress-track .seg-prog { background: repeating-linear-gradient(45deg, var(--warn), var(--warn) 6px, rgba(251,191,36,.55) 6px, rgba(251,191,36,.55) 12px); }
.progress-legend { display: flex; gap: 20px; flex-wrap: wrap; color: var(--muted); font-size: 13.5px; justify-content: center; margin-top: 14px; }
.progress-legend span { display: inline-flex; align-items: center; gap: 8px; }
.dotsq { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }
.dotsq.done { background: var(--brand); } .dotsq.prog { background: var(--warn); } .dotsq.idle { background: var(--idle); }

.rm-group { margin-top: 40px; }
.rm-group > h3 { font-size: 14px; text-transform: uppercase; letter-spacing: .1em; color: var(--brand-2); margin: 0 0 4px; }
.rm-group > .gd { color: var(--faint); font-size: 14px; margin: 0 0 18px; }
.timeline { position: relative; padding-left: 28px; }
.timeline::before { content:""; position:absolute; left: 7px; top: 6px; bottom: 6px; width: 2px; background: var(--border); }
.rm-item { position: relative; padding: 0 0 22px; }
.rm-item::before { content:""; position:absolute; left: -28px; top: 5px; width: 16px; height: 16px; border-radius: 50%; background: var(--bg); border: 3px solid var(--idle); }
.rm-item.done::before { border-color: var(--brand); background: var(--brand); box-shadow: 0 0 0 4px rgba(255,255,255,.12); }
.rm-item.prog::before { border-color: var(--warn); box-shadow: 0 0 0 4px rgba(251,191,36,.12); }
.rm-row { border: 1px solid var(--border); border-radius: 12px; padding: 16px 18px; background: var(--bg-soft); transition: border-color .15s, transform .15s; }
.rm-item.done .rm-row { border-color: rgba(255,255,255,.3); }
.rm-row:hover { transform: translateX(2px); border-color: #2b3a54; }
.rm-row .top { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.rm-ph { font-family: var(--mono); font-size: 12px; color: var(--brand-2); background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.2); padding: 2px 9px; border-radius: 7px; }
.rm-row h4 { margin: 0; font-size: 16px; letter-spacing: -.01em; flex: 1 1 auto; min-width: 200px; }
.status { font-size: 11.5px; font-weight: 700; padding: 3px 11px; border-radius: 999px; display:inline-flex; align-items:center; gap:6px; white-space: nowrap; }
.status.done { color: var(--good); background: rgba(54,211,153,.1); border: 1px solid rgba(54,211,153,.28); }
.status.prog { color: var(--warn); background: rgba(251,191,36,.1); border: 1px solid rgba(251,191,36,.28); }
.status.idle { color: var(--faint); background: rgba(91,107,130,.1); border: 1px solid rgba(91,107,130,.3); }
.rm-row p { margin: 9px 0 0; color: var(--muted); font-size: 14px; }

.page-hero { padding: 40px 0 20px; text-align: center; }
.page-hero h1 { font-size: clamp(27px, 4vw, 40px); letter-spacing: -.03em; margin: 8px 0 14px; font-weight: 800; }
.page-hero h1 .g { color: var(--brand-2); }
/* balance, so the sentence breaks into even lines instead of a full-width one and an orphan. */
.page-hero p { color: var(--muted); font-size: 16px; max-width: 620px; margin: 0 auto; text-wrap: balance; }
/* On a phone that 620px measure is simply the width of the screen, so the line ran from edge to
   edge while every card below it sat inside a margin — the intro read as if it had been cut out of
   a wider page. Its own inset puts it back inside the same column as the rest. */
@media (max-width: 560px) {
  .page-hero { padding: 32px 0 16px; }
  .page-hero p { padding-inline: 14px; font-size: 15.5px; }
}

/* ---------- Interactive workspace demo ---------- */
.demo-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: 16px; padding-bottom: 2px; }
.demo-win {
  min-width: 820px; max-width: 1040px; height: 600px; margin: 0 auto;
  display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: 16px; overflow: hidden;
  background: linear-gradient(180deg, #0e1623, #0b111c); box-shadow: var(--shadow);
}
.demo-titlebar { display: flex; align-items: center; gap: 7px; padding: 10px 14px; border-bottom: 1px solid var(--border-soft); background: rgba(255,255,255,.015); }
.demo-titlebar i { width: 11px; height: 11px; border-radius: 50%; }
.demo-titlebar i:nth-child(1){ background:#ff5f57; } .demo-titlebar i:nth-child(2){ background:#febc2e; } .demo-titlebar i:nth-child(3){ background:#28c840; }
.demo-titlebar .ttl { margin-left: 10px; font-family: var(--mono); font-size: 12px; color: var(--faint); }

/* app top bar (breadcrumb + actions, like the real app) */
.demo-topbar { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; padding: 9px 14px; border-bottom: 1px solid var(--border-soft); background: rgba(255,255,255,.02); }
.demo-topbar .tl { width: 11px; height: 11px; border-radius: 50%; flex: 0 0 auto; }
.demo-topbar .tl.r { background: #ff5f57; } .demo-topbar .tl.y { background: #febc2e; } .demo-topbar .tl.g { background: #28c840; }
.crumb { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text); padding: 3px 8px; border-radius: 7px; cursor: default; white-space: nowrap; }
.crumb:first-of-type { margin-left: 6px; }
.crumb:hover { background: rgba(255,255,255,.05); }
.crumb svg { width: 14px; height: 14px; color: var(--brand-2); }
.crumb .car { color: var(--faint); font-size: 10px; }
.crumb-sep { color: var(--faint); }
.top-actions { margin-left: auto; display: flex; align-items: center; gap: 3px; }
.tac { font-size: 12.5px; color: var(--muted); padding: 6px 11px; border-radius: 8px; display: inline-flex; align-items: center; gap: 6px; cursor: default; white-space: nowrap; }
.tac:hover { background: rgba(255,255,255,.05); color: var(--text); }
.tac svg { width: 14px; height: 14px; }
.tac.pub { background: var(--btn-bg); color: #0a0e17; font-weight: 600; }
.tac.pub:hover { color: #0a0e17; }
.demo-menu { display: flex; gap: 2px; padding: 5px 10px; border-bottom: 1px solid var(--border-soft); font-size: 12.5px; color: var(--muted); flex-wrap: wrap; }
.demo-menu span { padding: 3px 9px; border-radius: 6px; cursor: default; }
.demo-menu span:hover { background: rgba(255,255,255,.05); color: var(--text); }

.demo-ribbon { border-bottom: 1px solid var(--border-soft); }
.demo-tabs { display: flex; gap: 2px; padding: 0 10px; border-bottom: 1px solid var(--border-soft); }
.demo-tab { padding: 9px 14px; font-size: 13px; color: var(--muted); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; user-select: none; }
.demo-tab:hover { color: var(--text); }
.demo-tab.active { color: var(--text); border-bottom-color: var(--brand); }
.demo-ribbon-row { display: flex; align-items: stretch; gap: 0; padding: 8px 12px 5px; overflow-x: auto; background: rgba(255,255,255,.012); }
.rb-group { display: flex; flex-direction: column; align-items: center; padding: 0 12px; border-right: 1px solid var(--border-soft); }
.rb-group:last-child { border-right: none; }
.rb-btns { display: flex; gap: 2px; flex: 1; align-items: flex-start; }
.rb-glabel { font-size: 10px; color: var(--faint); margin-top: 5px; white-space: nowrap; letter-spacing: .02em; }
.rb-btn { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 6px 8px; border-radius: 8px; border: 1px solid transparent; min-width: 50px; cursor: pointer; color: var(--muted); user-select: none; }
.rb-btn:hover { background: rgba(255,255,255,.05); border-color: var(--border-soft); color: var(--text); }
.rb-btn:active { transform: translateY(1px); }
.rb-btn svg { width: 18px; height: 18px; color: var(--brand-2); }
.rb-btn span { font-size: 11px; }
.rb-sep { width: 1px; align-self: stretch; background: var(--border-soft); margin: 4px 4px; }

/* body = left rail | middle | right rail (rails run full height; ribbon lives in the middle, not over the rails) */
.demo-body { display: grid; grid-template-columns: 46px 1fr 46px; flex: 1; min-height: 0; }
.demo-body.no-rb { grid-template-columns: 46px 1fr; }
.demo-mid { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.demo-content { display: grid; flex: 1; min-height: 0; }
.demo-content.c-lcr { grid-template-columns: 196px 1fr 200px; }   /* side · centre · right */
.demo-content.c-cr  { grid-template-columns: 1fr 200px; }          /* centre · right (no side) */
.demo-content.c-lc  { grid-template-columns: 196px 1fr; }          /* side · centre (no right) */
.demo-actbar, .demo-rightbar { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 10px 0; }
.demo-actbar { border-right: 1px solid var(--border-soft); }
.demo-rightbar { border-left: 1px solid var(--border-soft); }
.demo-actbar .rail-ver { margin-top: auto; font-size: 9px; color: var(--faint); font-family: var(--mono); }
.act-ic { width: 32px; height: 32px; border-radius: 9px; display: grid; place-items: center; color: var(--muted); cursor: pointer; }
.act-ic:hover { background: rgba(255,255,255,.06); color: var(--text); }
.act-ic.active { color: #fff; background: var(--btn-bg); box-shadow: 0 6px 16px -8px rgba(255,255,255,.8); }
.act-ic svg { width: 18px; height: 18px; }

.demo-side { border-right: 1px solid var(--border-soft); padding: 14px 12px; overflow: auto; }
.demo-right { border-left: 1px solid var(--border-soft); padding: 14px 12px; overflow: auto; }
.side-title { font-size: 11px; text-transform: uppercase; letter-spacing: .08em; color: var(--faint); margin: 0 0 12px; }
.tree-item, .field-item { display: flex; align-items: center; gap: 8px; padding: 5px 7px; border-radius: 7px; font-size: 13px; color: var(--muted); cursor: pointer; }
.tree-item:hover, .field-item:hover { background: rgba(255,255,255,.04); color: var(--text); }
.tree-item svg, .field-item svg { width: 15px; height: 15px; color: var(--brand-2); flex: 0 0 auto; }
.tree-item.indent { padding-left: 22px; }
.field-item .chk { width: 14px; height: 14px; border-radius: 4px; border: 1px solid var(--border); flex: 0 0 auto; }
.field-item.on .chk { background: var(--btn-bg); border-color: transparent; }
.chip-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
.ctype { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 9px 4px; border: 1px solid var(--border-soft); border-radius: 9px; font-size: 11px; color: var(--muted); cursor: pointer; }
.ctype:hover { border-color: #2b3a54; color: var(--text); background: rgba(255,255,255,.03); }
.ctype svg { width: 18px; height: 18px; color: var(--brand-2); }
.rel { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--muted); padding: 7px; border: 1px solid var(--border-soft); border-radius: 8px; margin-bottom: 7px; }
.rel .pill { margin-left: auto; font-size: 10px; color: var(--brand-2); }

.demo-canvas {
  padding: 16px;
  background:
    linear-gradient(rgba(255,255,255,.022) 1px, transparent 1px) 0 0/100% 28px,
    linear-gradient(90deg, rgba(255,255,255,.022) 1px, transparent 1px) 0 0/28px 100%;
  display: grid; grid-template-columns: 1fr 1fr; grid-auto-rows: minmax(88px, auto); gap: 12px; align-content: start;
}
.dcard { border: 1px solid var(--border-soft); border-radius: 10px; background: rgba(12,19,32,.88); padding: 12px; cursor: pointer; display: flex; flex-direction: column; gap: 8px; transition: border-color .15s, box-shadow .15s; }
.dcard:hover { border-color: #2b3a54; }
.dcard.sel { border-color: var(--brand); box-shadow: 0 0 0 3px rgba(255,255,255,.18); }
.dcard .lbl { font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em; color: var(--faint); }
.dcard.span2 { grid-column: span 2; }

.drop { border: 1px dashed var(--border); border-radius: 8px; padding: 8px 10px; font-size: 12px; color: var(--faint); margin-bottom: 8px; }
.drop b { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin-bottom: 4px; }
.drop .ftag { display: inline-block; background: var(--grad-soft); border: 1px solid var(--border); color: var(--text); border-radius: 6px; padding: 2px 8px; font-size: 11.5px; margin: 2px 3px 0 0; }
.toggle-row { display: flex; align-items: center; justify-content: space-between; font-size: 13px; color: var(--muted); padding: 7px 2px; }
.sw { width: 32px; height: 18px; border-radius: 999px; background: var(--border); position: relative; flex: 0 0 auto; cursor: pointer; transition: background .15s; }
.sw::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: #fff; transition: left .15s; }
.sw.on { background: var(--brand); } .sw.on::after { left: 16px; }
.swatches { display: flex; gap: 6px; margin-top: 6px; }
.swatches i { width: 18px; height: 18px; border-radius: 5px; cursor: pointer; }
.chat { display: flex; flex-direction: column; gap: 8px; }
.bubble { font-size: 12.5px; border-radius: 10px; padding: 8px 10px; max-width: 92%; }
.bubble.me { align-self: flex-end; background: var(--btn-bg); color: #0a0e17; }
.bubble.ai { align-self: flex-start; background: rgba(255,255,255,.04); border: 1px solid var(--border-soft); color: var(--muted); }
.chat-input { display: flex; gap: 6px; align-items: center; border: 1px solid var(--border); border-radius: 9px; padding: 6px 10px; color: var(--faint); font-size: 12.5px; margin-top: 2px; }

.demo-status { flex: 0 0 auto; display: flex; align-items: center; gap: 10px; padding: 7px 14px; border-top: 1px solid var(--border-soft); font-size: 11.5px; color: var(--faint); background: rgba(255,255,255,.012); }
.demo-status .sheet { padding: 2px 10px; border-radius: 6px; background: rgba(255,255,255,.05); color: var(--muted); cursor: pointer; }
.demo-status .sheet.active { background: var(--btn-bg); color: #0a0e17; font-weight: 600; }
.demo-status .sp { margin-left: auto; }
.demo-hint { text-align: center; color: var(--faint); font-size: 13.5px; margin-top: 16px; }
.demo-hint b { color: var(--brand-2); }

/* plugin / palette rows in the side panel */
.prow { display: flex; align-items: center; gap: 9px; padding: 6px 7px; border-radius: 7px; font-size: 13px; color: var(--muted); cursor: pointer; }
.prow:hover { background: rgba(255,255,255,.04); color: var(--text); }
.prow svg { width: 15px; height: 15px; color: var(--brand-2); flex: 0 0 auto; }
.prow .tier { margin-left: auto; font-size: 10px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border); color: var(--faint); }
.prow .tier.mybi { color: var(--brand-2); border-color: rgba(255,255,255,.3); background: rgba(255,255,255,.08); }
.prow .tier.trusted { color: var(--good); border-color: rgba(54,211,153,.3); background: rgba(54,211,153,.08); }
.prow .mini { margin-left: auto; display: flex; gap: 4px; }
.prow .mini i { width: 12px; height: 12px; border-radius: 3px; }

/* per-area views: ribbon / center / right / footer all swap together */
.ribview { display: block; }
.demo-center { overflow: auto; position: relative; }
.cview { padding: 16px; min-height: 100%; }
.cview.canvas-view {
  background:
    linear-gradient(rgba(255,255,255,.022) 1px, transparent 1px) 0 0/100% 28px,
    linear-gradient(90deg, rgba(255,255,255,.022) 1px, transparent 1px) 0 0/28px 100%;
  display: grid; grid-template-columns: 1fr 1fr; grid-auto-rows: minmax(88px, auto); gap: 12px; align-content: start;
}
.footview { display: flex; align-items: center; gap: 10px; flex: 1; }
.footview .sp { margin-left: auto; }
.demo-rightbar.dim .act-ic { opacity: .4; }

/* data grid (Data area centre) */
.grid-tbl { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.grid-tbl th, .grid-tbl td { text-align: left; padding: 7px 11px; border-bottom: 1px solid var(--border-soft); white-space: nowrap; }
.grid-tbl th { color: var(--faint); font-weight: 600; text-transform: uppercase; font-size: 10px; letter-spacing: .05em; position: sticky; top: 0; background: #0c1320; }
.grid-tbl td { color: var(--muted); }
.grid-tbl tr:hover td { background: rgba(255,255,255,.02); }
.grid-tbl td.num { text-align: right; font-variant-numeric: tabular-nums; color: var(--text); }
.grid-tbl .rownum { color: var(--faint); width: 24px; text-align: right; }

/* model diagram (Semantic area centre) */
.model { position: relative; min-height: 300px; height: 100%; }
.model .links { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.mbox { position: absolute; width: 132px; border: 1px solid var(--border); border-radius: 10px; background: #0e1726; box-shadow: var(--shadow); }
.mbox.sel { border-color: var(--brand); box-shadow: 0 0 0 3px rgba(255,255,255,.18); }
.mbox h5 { margin: 0; padding: 8px 11px; font-size: 12px; border-bottom: 1px solid var(--border-soft); display: flex; align-items: center; gap: 7px; }
.mbox h5 svg { width: 14px; height: 14px; color: var(--brand-2); }
.mbox ul { list-style: none; margin: 0; padding: 7px 11px; font-size: 11.5px; color: var(--muted); }
.mbox li { padding: 2px 0; display: flex; justify-content: space-between; gap: 8px; }
.mbox li .k { color: var(--faint); font-size: 10px; }

/* gallery cards (Plugins / Palettes area centre) */
.gallery { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-content: start; }
.gcard { border: 1px solid var(--border-soft); border-radius: 10px; background: rgba(12,19,32,.85); padding: 14px; cursor: pointer; transition: border-color .15s, box-shadow .15s; }
.gcard:hover { border-color: #2b3a54; }
.gcard.sel { border-color: var(--brand); box-shadow: 0 0 0 3px rgba(255,255,255,.18); }
.gcard .gh { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 14px; }
.gcard .gh svg { width: 18px; height: 18px; color: var(--brand-2); flex: 0 0 auto; }
.gcard .gh .tier { margin-left: auto; font-size: 10px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border); color: var(--faint); }
.gcard .gh .tier.mybi { color: var(--brand-2); border-color: rgba(255,255,255,.3); background: rgba(255,255,255,.08); }
.gcard .gh .tier.trusted { color: var(--good); border-color: rgba(54,211,153,.3); background: rgba(54,211,153,.08); }
.gcard p { margin: 9px 0 11px; font-size: 12px; color: var(--muted); }
.gcard .pal { display: flex; gap: 4px; margin: 10px 0 11px; }
.gcard .pal i { height: 18px; border-radius: 4px; flex: 1; }
.gcard .gbtn { font-size: 12px; font-weight: 600; color: var(--brand-2); }
.gcard .gbtn.done { color: var(--faint); }

/* settings form (Settings area centre) */
.set-form { display: flex; flex-direction: column; gap: 16px; max-width: 520px; }
.set-group h5 { margin: 0 0 2px; font-size: 13.5px; }
.set-group .sg-sub { color: var(--faint); font-size: 11.5px; margin: 0 0 10px; }
.set-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 13px; border: 1px solid var(--border-soft); border-radius: 9px; font-size: 13px; color: var(--muted); margin-bottom: 8px; }
.set-row .val { color: var(--text); font-size: 12.5px; }

/* right-panel: applied steps / properties rows */
.step { display: flex; align-items: center; gap: 9px; font-size: 12.5px; color: var(--muted); padding: 6px 7px; border-radius: 7px; }
.step:hover { background: rgba(255,255,255,.04); color: var(--text); }
.step .n { width: 16px; height: 16px; border-radius: 50%; background: var(--grad-soft); color: var(--brand-2); display: grid; place-items: center; font-size: 10px; flex: 0 0 auto; }
.prop { display: flex; justify-content: space-between; gap: 10px; font-size: 12.5px; padding: 7px 2px; border-bottom: 1px solid var(--border-soft); }
.prop .k { color: var(--faint); }
.prop .v { color: var(--text); }
.perm { font-family: var(--mono); font-size: 11px; color: var(--muted); background: rgba(255,255,255,.03); border: 1px solid var(--border-soft); border-radius: 6px; padding: 4px 8px; margin: 4px 4px 0 0; display: inline-block; }

/* activity panel (Semantic right) */
.act-sec { margin-bottom: 16px; }
.act-sec .h { font-size: 10px; text-transform: uppercase; letter-spacing: .08em; color: var(--faint); margin: 0 0 5px; display: flex; align-items: center; gap: 8px; }
.act-sec .h .pill { font-size: 9px; color: var(--brand-2); background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.25); border-radius: 999px; padding: 1px 7px; text-transform: none; letter-spacing: 0; }
.act-sec p { margin: 0; font-size: 12px; color: var(--muted); }

/* Model heading + auto-detect (Semantic centre) */
.model-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
.model-head h4 { margin: 0 0 4px; font-size: 17px; letter-spacing: -.01em; }
.model-head p { margin: 0; font-size: 12.5px; color: var(--muted); max-width: 360px; }
.btn-detect { font-size: 12px; color: var(--muted); border: 1px solid var(--border); border-radius: 8px; padding: 7px 12px; white-space: nowrap; cursor: pointer; background: rgba(255,255,255,.03); }
.btn-detect:hover { color: var(--text); border-color: #2b3a54; }
.model-canvas { border: 1px solid var(--border-soft); border-radius: 12px; min-height: 250px; position: relative; background-image: radial-gradient(rgba(255,255,255,.06) 1px, transparent 1px); background-size: 16px 16px; }

/* side-panel tabs + plugin rows (Plugins / Palettes) */
.side-tabs { display: flex; gap: 16px; border-bottom: 1px solid var(--border-soft); margin: 0 0 12px; }
.side-tab { font-size: 12.5px; color: var(--muted); padding: 6px 0; border-bottom: 2px solid transparent; margin-bottom: -1px; cursor: pointer; }
.side-tab.active { color: var(--text); border-bottom-color: var(--brand); }
.plug { display: flex; align-items: flex-start; gap: 9px; padding: 8px 7px; border-radius: 8px; cursor: pointer; }
.plug:hover { background: rgba(255,255,255,.04); }
.plug .pi { width: 26px; height: 26px; border-radius: 7px; display: grid; place-items: center; background: var(--grad-soft); color: var(--brand-2); flex: 0 0 auto; }
.plug .pi svg { width: 15px; height: 15px; }
.plug .pn { font-size: 13px; color: var(--text); display: flex; align-items: center; gap: 6px; }
.plug .pd { font-size: 11px; color: var(--faint); margin-top: 1px; }
.badge-en { font-size: 9px; color: var(--good); border: 1px solid rgba(54,211,153,.3); background: rgba(54,211,153,.1); border-radius: 999px; padding: 1px 6px; }
.badge-cm { font-size: 9px; color: var(--faint); border: 1px solid var(--border); border-radius: 999px; padding: 1px 6px; }

/* empty state (Plugins centre) */
.empty { display: grid; place-items: center; height: 100%; min-height: 220px; color: var(--faint); font-size: 13px; text-align: center; }

/* palette detail (Palettes centre) */
.pal-detail h4 { margin: 0 0 8px; font-size: 20px; letter-spacing: -.02em; }
.pal-badges { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; }
.pal-badge { font-size: 11px; color: var(--muted); border: 1px solid var(--border); border-radius: 999px; padding: 3px 10px; }
.pd-desc { font-size: 13px; color: var(--muted); max-width: 520px; margin: 0 0 16px; }
.pal-tabs { display: flex; gap: 18px; border-bottom: 1px solid var(--border-soft); margin-bottom: 14px; }
.pal-tab { font-size: 11.5px; color: var(--muted); padding: 8px 0; border-bottom: 2px solid transparent; margin-bottom: -1px; cursor: pointer; text-transform: uppercase; letter-spacing: .04em; }
.pal-tab.active { color: var(--text); border-bottom-color: var(--brand); }
.pal-swatches { display: flex; gap: 10px; }
.pal-swatches i { width: 40px; height: 40px; border-radius: 8px; }
.pal-use { font-size: 12px; font-weight: 600; color: #0a0e17; background: var(--btn-bg); border-radius: 8px; padding: 8px 14px; cursor: pointer; white-space: nowrap; }

/* ---------- Developer pages ---------- */
/* code blocks */
.codeblock { background: #0c1320; border: 1px solid var(--border); border-radius: 12px; padding: 16px 18px; overflow-x: auto; font-family: var(--mono); font-size: 12.5px; color: var(--muted); line-height: 1.75; white-space: pre; tab-size: 2; }
.codeblock .k { color: var(--brand-2); } /* keys / keywords */
.codeblock .s { color: #8bd5a0; }         /* strings */
.codeblock .c { color: var(--faint); }    /* comments */

/* numbered steps */
.steps { counter-reset: s; display: grid; gap: 16px; margin: 0; padding: 0; list-style: none; }
.steps li { counter-increment: s; display: flex; gap: 14px; }
.steps li::before { content: counter(s); flex: 0 0 auto; width: 28px; height: 28px; border-radius: 50%; background: var(--btn-bg); color: #0a0e17; font-weight: 800; font-size: 13px; display: grid; place-items: center; }
.steps li b { color: var(--text); display: block; font-size: 15px; margin-bottom: 2px; }
.steps li span { color: var(--muted); font-size: 14px; }

/* trust tiers */
/* Three tracks, floored at zero rather than at their content — three cards' worth of min-content is
   wider than a phone, and a 1fr track will not go below it. The count itself comes down with the
   viewport alongside the other card grids. */
.tiers { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
.tier-card { border: 1px solid var(--border); border-radius: var(--radius); padding: 24px; background: var(--bg-soft); }
.tier-card h3 { margin: 0 0 4px; font-size: 16px; display: flex; align-items: center; gap: 8px; }
.tier-card .badge { font-size: 10px; font-weight: 700; padding: 2px 9px; border-radius: 999px; border: 1px solid var(--border); color: var(--faint); }
.tier-card .badge.mybi { color: var(--brand-2); border-color: rgba(255,255,255,.3); background: rgba(255,255,255,.08); }
.tier-card .badge.trusted { color: var(--good); border-color: rgba(54,211,153,.3); background: rgba(54,211,153,.08); }
.tier-card p { margin: 8px 0 0; color: var(--muted); font-size: 14px; }

/* cross-sign studio skeleton */
.studio-flow { display: grid; grid-template-columns: 1fr auto 1fr; gap: 16px; align-items: center; }
.studio-win { border: 1px solid var(--border); border-radius: 14px; background: linear-gradient(180deg, #0e1623, #0b111c); box-shadow: var(--shadow); overflow: hidden; }
.studio-win .sw-bar { display: flex; align-items: center; gap: 7px; padding: 9px 12px; border-bottom: 1px solid var(--border-soft); font-size: 12px; color: var(--text); }
.studio-win .sw-bar i { width: 9px; height: 9px; border-radius: 50%; background: rgba(255,255,255,.12); }
.studio-win .sw-bar i:first-child { background: #ff5f57; }
.studio-win .sw-body { padding: 14px; display: grid; gap: 9px; }
.sw-row { display: flex; align-items: center; gap: 9px; font-size: 12.5px; color: var(--muted); border: 1px solid var(--border-soft); border-radius: 8px; padding: 9px 10px; }
.sw-row .ic { width: 24px; height: 24px; border-radius: 6px; background: var(--grad-soft); color: var(--brand-2); display: grid; place-items: center; flex: 0 0 auto; }
.sw-row .ic svg { width: 14px; height: 14px; }
.sw-row.key { color: var(--good); font-family: var(--mono); font-size: 11px; }
.studio-arrow { display: grid; place-items: center; gap: 6px; text-align: center; color: var(--brand-2); font-size: 11px; padding: 0 4px; }
.studio-arrow svg { width: 28px; height: 28px; }
.studio-arrow span { color: var(--faint); max-width: 90px; }

/* "coming soon" pill — usable anywhere (headings, cards) */
.badge-soon { display: inline-block; font-size: 12px; font-weight: 700; color: var(--warn); background: rgba(251,191,36,.1); border: 1px solid rgba(251,191,36,.25); padding: 3px 10px; border-radius: 999px; vertical-align: middle; }

/* Collapse is driven by MEASUREMENT (see assets/main.js), not by a width guess, because the tab
   row's natural width differs per page. JS adds .nav-compact when the tabs would reach the centred
   mark, then .nav-actions-compact when the actions would. */
/* Compact right zone: a theme icon showing the CURRENT mode (opens the three choices) and the
   Download glyph. Not one "more" menu: burying the download behind an extra tap hides the single
   thing most visitors came for. */
.theme-toggle {
  display: none; width: 38px; height: 38px; padding: 0; cursor: pointer;
  align-items: center; justify-content: center;
  background: transparent; border: 1px solid var(--border); border-radius: 10px; color: var(--text);
}
.theme-toggle svg { width: 18px; height: 18px; }
.theme-toggle:hover { background: var(--ghost-hover); }

/* The tab row becomes a LEFT DRAWER, not an inline panel. An inline panel made .nav-inner wrap,
   and because the mark is absolutely centred on that container it was dragged down into the open
   menu. A fixed drawer is out of flow entirely, so the bar keeps its 64px single row and the mark
   never moves. */
.nav-compact .nav-inner { flex-wrap: nowrap; height: 64px; }
.nav-compact .nav-burger { display: inline-flex; order: 1; }
.nav-compact .brand { order: 2; }
.nav-compact .nav-actions { order: 3; }
/* A panel, not a full-height column: four links against a floor-to-ceiling white slab left two
   thirds of the drawer as dead space. It hangs from the top-left corner, takes the height of what
   is in it, and carries the edge and shadow that say it sits ABOVE the page. */
.nav-compact .nav-tabs {
  display: flex; flex-direction: column; align-items: stretch; gap: 2px;
  position: fixed; top: 0; left: 0; bottom: auto; width: min(300px, 84vw);
  max-height: 100dvh; margin: 0;
  padding: 0 12px calc(14px + env(safe-area-inset-bottom));
  /* Frosted rather than a flat slab: the page moving under it is what says the panel is above it,
     and it is the same material as the bar the panel drops out of. */
  background: color-mix(in srgb, var(--panel) 86%, transparent);
  -webkit-backdrop-filter: blur(22px) saturate(150%); backdrop-filter: blur(22px) saturate(150%);
  border: 0;
  border-right: 1px solid var(--border); border-bottom: 1px solid var(--border);
  border-radius: 0 0 22px 0;
  box-shadow: 0 34px 64px -30px rgba(0,0,0,.62), inset 0 1px 0 rgba(255,255,255,.045);
  transform: translateX(-100%); transition: transform .26s cubic-bezier(.32,.72,0,1); z-index: 60;
  overflow-y: auto;
}
@supports not (backdrop-filter: blur(1px)) {
  .nav-compact .nav-tabs { background: var(--panel); }
}
.nav-compact.nav-open .nav-tabs { transform: none; }
/* Rows, not tags: a thumb-sized target, the label at reading size, and the icon given room rather
   than tucked against it. */
.nav-compact .nav-tab {
  justify-content: flex-start; gap: 13px; padding: 12px 12px;
  border-radius: 12px; font-size: 15px;
}
.nav-compact .nav-tab-ic { width: 18px; height: 18px; }
/* The page you are on keeps the accent tint and gets a dot at the end of the row, so it reads as
   the current one at a glance instead of merely as the coloured one. */
.nav-compact .nav-tab.on::after {
  content: ""; margin-left: auto; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
}
/* The rows arrive just behind the panel, which is what stops the drawer reading as one slab
   sliding in. */
.nav-compact.nav-open .nav-tab { animation: nav-row .3s cubic-bezier(.32,.72,0,1) both; }
.nav-compact.nav-open .nav-tab:nth-of-type(1) { animation-delay: .06s; }
.nav-compact.nav-open .nav-tab:nth-of-type(2) { animation-delay: .1s; }
.nav-compact.nav-open .nav-tab:nth-of-type(3) { animation-delay: .14s; }
.nav-compact.nav-open .nav-tab:nth-of-type(4) { animation-delay: .18s; }
@keyframes nav-row { from { opacity: 0; transform: translateX(-10px); } }
/* The drawer covers the left of the bar, burger included. Lift the burger over it so the same
   button that opened the menu still closes it. */
.nav-compact .nav-burger { position: relative; z-index: 61; }
/* Drawer header: the burger keeps its place in the bar and the panel titles itself beside it, so
   the top of the drawer reads as one row (button, then label) rather than a button floating in
   empty white. Full-bleed rule under it, matching the bar's own bottom border. */
.nav-drawer-head { display: none; }
.nav-compact .nav-drawer-head {
  display: flex; align-items: center; gap: 9px;
  flex: 0 0 auto; height: 64px;
  margin: 0 -12px 10px; padding: 0 14px 0 64px;
  border-bottom: 1px solid var(--border-soft);
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .1em;
  color: var(--faint);
}
.nav-drawer-head svg { width: 15px; height: 15px; color: var(--brand-2); flex: 0 0 auto; }
/* The burger leaves the bar's flow and squares off into the corner while the drawer is open: it is
   the panel's own header button then, not a floating pill sitting on top of it. The rule down its
   right edge is the divider between it and the panel's name. */
.nav-open .nav-burger {
  position: fixed; top: 0; left: 0; width: 56px; height: 64px;
  border: 0; border-right: 1px solid var(--border-soft); border-radius: 0;
  background: transparent; z-index: 61;
}
.nav-open .nav-burger:hover { background: var(--ghost-hover); }

/* Scrim behind the drawer. Click anywhere on it to close.
   BELOW the bar's z-index (50), not above it: the drawer lives inside .nav, and .nav is a stacking
   context, so any scrim above 50 would also dim the drawer it is meant to sit behind. */
.nav-scrim {
  position: fixed; inset: 0; background: rgba(3,6,12,.45); z-index: 45;
  opacity: 0; pointer-events: none; transition: opacity .2s ease;
}
html.nav-drawer-open .nav-scrim { opacity: 1; pointer-events: auto; }
/* No scroll lock here. `overflow: hidden` on the root stops being a scroll container, and a
   position:sticky bar inside one has nothing left to stick to — opening the drawer part-way down
   the page took the whole bar, burger included, off the screen. */
@media (prefers-reduced-motion: reduce) {
  .nav-compact .nav-tabs, .nav-scrim { transition: none; }
  .nav-compact.nav-open .nav-tab { animation: none; }
}

/* Compact: the theme SEGMENT becomes one button that CHANGES the theme on each press — system,
   light, dark, round again. It used to open the three as a dropdown, which is a menu to make a
   choice between three states you can simply step through, and a panel hanging off the bar on a
   phone besides. The segment itself is gone here, not hidden behind an open class. */
.nav-actions-compact .theme-toggle { display: inline-flex; }
.nav-actions-compact .theme-seg { display: none; }
.nav-actions-compact .btn-primary { padding: 9px; gap: 0; }
.nav-actions-compact .btn-primary span,
.nav-actions-compact .btn-primary { font-size: 0; }
.nav-actions-compact .btn-primary svg { width: 17px; height: 17px; }

/* No-JS / pre-JS fallback. 980px, not 760: the tabs meet the centred mark long before the three
   zones would fill the bar, so a lower value leaves them overlapping until JS loads. */
@media (max-width: 980px) {
  .nav-inner { flex-wrap: nowrap; height: 64px; }
  .nav-burger { display: inline-flex; order: 1; }
  .brand { order: 2; }
  .nav-actions { order: 3; }
  .nav-drawer-head {
    display: flex; flex: 0 0 auto; height: 64px; align-items: center; gap: 10px;
    margin: 0 -14px 10px; padding: 0 14px 0 66px;
    border-bottom: 1px solid var(--border-soft);
    font-size: 13px; font-weight: 700; letter-spacing: .01em; color: var(--text);
  }
  .nav-tabs {
    display: flex; flex-direction: column; align-items: stretch; gap: 4px;
    position: fixed; top: 0; left: 0; bottom: 0; width: min(284px, 82vw);
    margin: 0; padding: 0 14px 18px;
    background: var(--panel); border: 0; border-right: 1px solid var(--border); border-radius: 0;
    transform: translateX(-100%); transition: transform .24s ease; z-index: 60; overflow-y: auto;
  }
  .nav-open .nav-tabs { transform: none; }
  .nav-tab { justify-content: flex-start; padding: 11px 13px; }
  .nav-burger { position: relative; z-index: 61; }
}
/* Re-opened: these belonged to the 860px block whose nav rules were replaced above. */
@media (max-width: 860px) {
  .studio-flow { grid-template-columns: 1fr; }
  .studio-arrow { transform: rotate(90deg); padding: 8px 0; }
  .studio-arrow span { transform: rotate(-90deg); }
}

/* ---------- Theme switcher (Light / System / Dark) ---------- */
.theme-seg { display: inline-flex; align-items: center; gap: 2px; padding: 3px; margin-left: 6px; border: 1px solid var(--border); border-radius: 999px; background: transparent; }
.theme-seg button { width: 26px; height: 26px; border-radius: 999px; border: none; background: transparent; color: var(--faint); display: grid; place-items: center; cursor: pointer; padding: 0; transition: color .15s, background .15s; }
.theme-seg button:hover { color: var(--text); background: var(--ghost-hover); }
.theme-seg button.on { background: var(--btn-bg); color: var(--btn-fg); }
.theme-seg svg { width: 14px; height: 14px; }

/* ---------- Light-mode page chrome (app windows & code stay dark below) ---------- */
html[data-theme="light"] body::before {
  background:
    radial-gradient(900px 500px at 78% -8%, rgba(255,255,255,.10), transparent 60%),
    radial-gradient(800px 520px at 8% 8%, rgba(255,255,255,.07), transparent 55%),
    radial-gradient(700px 700px at 50% 120%, rgba(255,255,255,.07), transparent 60%);
}
html[data-theme="light"] .nav::before { background: rgba(244,246,250,.88); }
html[data-theme="light"] :is(.flow .node, .ai-chip, .dl-btn, .foot-col a) { background: rgba(16,27,45,.04); }
/* App mockups, demo windows, studio skeletons and code blocks DEPICT the (dark) app —
   they keep the dark surface in light mode, so re-pin the dark tokens inside them. */
html[data-theme="light"] :is(.mock, .demo-win, .studio-win, .codeblock) {
  --text: #e7eef7; --muted: #97a6bb; --faint: #6b7a90;
  --border: #1e2838; --border-soft: #18212f;
  --panel: #111827; --panel-2: #141c2b; --bg-soft: #0d1320;
  color: var(--text); color-scheme: dark;
}

/* The about-page family grid: four cards read best 2×2 */
.tiers.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* ---------- Overview: per-product sections + "more" links ---------- */
.sec-more { text-align: center; margin-top: 28px; }
.page-hero .badge-soon { margin-left: 10px; }

/* ---------- Comparison table (overview) ---------- */
.cmp-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); }
.cmp { width: 100%; border-collapse: collapse; font-size: 13.5px; min-width: 820px; }
.cmp th, .cmp td { padding: 13px 16px; text-align: left; border-bottom: 1px solid var(--border-soft); vertical-align: top; }
.cmp thead th { font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .07em; color: var(--faint); background: var(--panel-2); }
.cmp tbody th { color: var(--text); font-weight: 600; white-space: nowrap; font-size: 13.5px; }
.cmp td { color: var(--muted); }
.cmp .col-us { background: rgba(255,255,255,.07); color: var(--text); }
.cmp thead th.col-us { color: var(--brand-2); }
.cmp tbody tr:last-child th, .cmp tbody tr:last-child td { border-bottom: none; }
.cmp-note { color: var(--faint); font-size: 12.5px; margin-top: 14px; }
.cmp b.y { color: var(--good); font-weight: 700; }

/* ---------- Forensic page: the checks table ---------- */
.checks { width: 100%; border-collapse: collapse; font-size: 14px; }
.checks th, .checks td { padding: 13px 16px; text-align: left; border-bottom: 1px solid var(--border-soft); vertical-align: top; }
.checks thead th { font-size: 11.5px; text-transform: uppercase; letter-spacing: .07em; color: var(--faint); }
.checks td:first-child { color: var(--text); }
.checks td:last-child { color: var(--muted); }
.checks tr:last-child td { border-bottom: none; }
.checks-wrap { border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); overflow: hidden; }

/* the hidden attribute must always win, even over flex/grid panels */
[hidden] { display: none !important; }

/* ---------- Responsive ---------- */
@media (max-width: 960px) {
  .hero-grid { grid-template-columns: 1fr; gap: 40px; }
  .hero { padding: 40px 0 30px; }
  .principles, .features, .tech, .dl-grid, .rm-stats, .tiers { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* …but never the one-card variant: two tracks would park the lone card in column one and leave
     the other half empty, which reads as a missing card rather than a deliberate layout. */
  .dl-grid.dl-grid-one { grid-template-columns: minmax(0, 340px); }
  .split { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .split.rev .split-media { order: 0; }
}
/* Below this the Download label would meet the centred mark, so the button becomes its glyph.
   gap: 0 goes with it — the label collapses to nothing but .btn's 9px gap does not, which left the
   button 9px wider than it was tall: a stretched lozenge beside the square theme button. */
@media (max-width: 560px) {
  .nav-actions .btn-primary span,
  .nav-actions .btn-primary { font-size: 0; }
  .nav-actions .btn-primary { padding: 9px; gap: 0; }
  .nav-actions .btn-primary svg { width: 17px; height: 17px; }
  .theme-seg button { width: 24px; height: 24px; }
}
@media (max-width: 620px) {
  .principles, .features, .tech, .dl-grid, .rm-stats, .tiers { grid-template-columns: minmax(0, 1fr); }
  .dl-grid.dl-grid-one { grid-template-columns: minmax(0, 340px); }
  .flow .row { grid-template-columns: 1fr; }
  .cta-band { padding: 34px 22px; }
  section { padding: 30px 0; }
}

/* reduce motion */
@media (prefers-reduced-motion: reduce) {
  * { scroll-behavior: auto !important; transition: none !important; }
}

/* ---------- Support: the two ways to send feedback ---------- */
/* One rounded box split in two, rather than two cards: they are alternatives, not a list, and a
   single frame says "pick one" where two separate boxes would read as two separate asks. */
/* The heading lives inside the frame, over a divider, so the box is one object labelled "Send
   feedback" rather than a heading with an unrelated box under it. */
.sup-box {
  margin-top: 16px; border: 1px solid var(--border); border-radius: 18px;
  overflow: hidden; background: var(--panel);
}
/* Selector carries the parent so it beats any bare h2 sizing, and line-height is set rather than
   inherited: the header's height is padding plus one line, nothing else. */
.sup-box > .sup-box-h {
  display: flex; align-items: center; gap: 9px;
  margin: 0; padding: 11px 18px; font-size: 15.5px; line-height: 1.25; font-weight: 700;
  letter-spacing: -.01em; border-bottom: 1px solid var(--border);
}
.sup-box-ic { display: grid; place-items: center; color: var(--brand-2); }
.sup-box-ic svg { display: block; width: 17px; height: 17px; }
.sup-choice { display: grid; grid-template-columns: 1fr 1fr; }
.sup-opt { padding: 26px 24px 28px; text-align: center; }
.sup-opt h3 { margin: 0 0 7px; font-size: 16.5px; letter-spacing: -.01em; color: var(--text); }
.sup-opt p { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.6; }
.sup-opt .sup-path { margin-top: 10px; font-size: 13.5px; color: var(--faint); }
/* Big and centred: with only two choices the icon is the thing you aim at, so it leads each half
   instead of sitting in the corner of it. */
.sup-ic {
  width: 54px; height: 54px; border-radius: 16px; background: var(--grad-soft);
  display: grid; place-items: center; color: var(--brand-2); margin: 0 auto 15px;
}
.sup-ic svg { width: 26px; height: 26px; }
/* The right half is the control, so it is an actual button: keyboard-operable, and it says what it
   will do rather than relying on the cursor changing. */
button.sup-opt {
  font: inherit; color: inherit; cursor: pointer; width: 100%;
  background: transparent; border: 0; border-left: 1px solid var(--border);
  transition: background .18s ease;
}
button.sup-opt:hover { background: var(--ghost-hover); }
.sup-cue {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 13px;
  color: var(--brand-2); font-weight: 600; font-size: 13.5px;
}
.sup-cue svg { width: 14px; height: 14px; transition: transform .2s ease; }
button.sup-opt[aria-expanded="true"] .sup-cue svg { transform: rotate(180deg); }
.sup-form {
  margin-top: 14px; border: 1px solid var(--border); border-radius: 18px;
  overflow: hidden; background: var(--panel);
}
.sup-form iframe { display: block; width: 100%; height: 1180px; border: 0; }
@media (max-width: 700px) {
  .sup-choice { grid-template-columns: 1fr; }
  button.sup-opt { border-left: 0; border-top: 1px solid var(--border); }
  .sup-form iframe { height: 1320px; }
}

/* ---------- Button tip (App Store compliance note) ---------- */
/* Not a title attribute: this one carries a link, and a native tooltip cannot be moved into or
   clicked. The wrapper is the flex item now, so it inherits the row's sizing and the button fills
   it — the five buttons stay one size. */
.tip-wrap { position: relative; display: flex; }
/* The wrapper is the flex item, so .hero-cta's justify-content lands on IT and the button's own
   contents fell back to flex-start — the Apple mark and label sat left while every other button
   centred. The button re-centres its own contents. */
.tip-wrap > .btn { width: 100%; height: 100%; justify-content: center; }
/* Centred on the button, then nudged back inside the viewport by --tip-shift, which the script sets
   from the measured box. On a phone the App Store button's centre is barely 110px from the left
   edge while the tip wants 310px, so a plain translateX(-50%) hung half the box off-screen. */
/* The shift rides on margin-left, NOT on the transform. Inside the animated transform it measured
   wrong: while tip-in runs, a var() in the keyframe left the translate unresolved for a frame, so
   the box reported its untranslated position — half a box to the right — and the script "corrected"
   it further off the left edge. margin-left is nothing to do with the animation, so what the script
   measures is always the real centred box. */
.btn-tip {
  position: absolute; top: calc(100% + 9px); left: 50%; transform: translateX(-50%);
  margin-left: var(--tip-shift, 0px);
  z-index: 30; width: max-content; max-width: min(310px, 84vw);
  display: block; text-align: center; padding: 12px 14px 13px;
  border: 1px solid var(--border); border-radius: 13px; background: var(--panel-2);
  box-shadow: 0 22px 44px -24px rgba(0,0,0,.6);
  font-size: 12.5px; line-height: 1.55; color: var(--muted); font-weight: 400;
  animation: tip-in .16s ease both;
}
.btn-tip[hidden] { display: none; }
@keyframes tip-in { from { opacity: 0; transform: translateX(-50%) translateY(-4px); } }
@media (prefers-reduced-motion: reduce) { .btn-tip { animation: none; } }
/* The notch reads as "this belongs to the button above" without needing a second border to hide.
   It walks back by the same shift, so it keeps pointing at the button the box moved away from. */
.btn-tip::before {
  content: ""; position: absolute; bottom: 100%; left: calc(50% - var(--tip-shift, 0px));
  margin-left: -6px;
  border: 6px solid transparent; border-bottom-color: var(--border);
}
.btn-tip-t { display: block; }
/* A button, not a line of link text: it is the one thing in the tip you can act on, and at 12.5px
   in the middle of a paragraph a coloured phrase is a small target to hit with a thumb. */
.btn-tip-a {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  margin-top: 11px; padding: 8px 13px; min-height: 34px;
  border: 1px solid var(--border); border-radius: 8px; background: var(--panel);
  color: var(--brand-2); font-weight: 600; font-size: 12px; text-decoration: none;
  transition: border-color .15s ease, background .15s ease;
}
.btn-tip-a:hover { border-color: var(--brand-2); background: var(--panel-2); text-decoration: none; }
.btn-tip-a svg { width: 12px; height: 12px; flex: 0 0 auto; }
