/* ==========================================================================
   Cannvas marketing chassis — the Linear language
   Spec: docs/redesign-spec/DESIGN.md  ·  Plan: §13 (reskin) + §14 (real front end)

   North star: "The Darkened Gallery" — the page is an unlit room; the real
   product, mounted live, is the only thing emitting colour and light.

   This file styles PAGE CHROME ONLY. It never contains a semantic colour and it
   never reaches inside a mounted product surface. Product styling arrives from
   _real/cannvas-ui.css, vendored verbatim.

   NOTE for future passes: the mono "N.0" chapter markers are a pinned part of
   the brief (Ryan, from 16 Linear reference shots) and the numbers are load-
   bearing — they are the ordered beats of a real department workflow, not
   decorative section numbering. Do not strip them as eyebrows.
   ========================================================================== */

:root {
  /* Ground + surfaces */
  --cs-ground:          #08090A;
  --cs-ground-raised:   #0A0A0B;
  --cs-surface:         #0F0F11;
  --cs-surface-raised:  #16161A;

  /* Greyscale text ramp — the only text colours on the site */
  --cs-text:            #F7F8F8;
  --cs-text-bright:     #D0D6E0;   /* Linear's subhead grey — measured 2026-08-17 */
  --cs-text-2:          #8A8F98;
  --cs-text-3:          #62666D;

  /* Faded hairlines instead of shadows */
  --cs-border:          rgba(255, 255, 255, 0.06);
  --cs-border-strong:   rgba(255, 255, 255, 0.10);

  --cs-font:  Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --cs-mono:  "SF Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Full-bleed layout: no container cap — content runs edge to edge with wide
     gutters (~200px on large displays, scaling down with the viewport). */
  --cs-gutter:   clamp(40px, 12vw, 200px);
  --cs-measure:  860px;
  --cs-section:  128px;   /* Linear's measured block rhythm */
  --cs-chapter:  160px;

  --cs-ease: cubic-bezier(0.16, 1, 0.3, 1);
}

/* ── Base ─────────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--cs-ground);
  color: var(--cs-text-2);
  font-family: var(--cs-font);
  font-size: 15px;
  line-height: 24px;
  letter-spacing: -0.011em;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: rgba(255, 255, 255, 0.16); color: #F7F8F8; }

:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.10);
  border-radius: 6px;
}

img, svg, canvas { max-width: 100%; display: block; }

/* ── Layout ───────────────────────────────────────────────────────────── */

.cs-container {
  width: 100%;
  margin-inline: auto;
  padding-inline: var(--cs-gutter);
}

.cs-section  { padding-block: var(--cs-section); }
.cs-chapter-gap { height: var(--cs-chapter); }

/* A normal-flow chapter. It carries its own ground and sits ABOVE the pinned
   reveals, so scrolling lifts it OFF the pin (uncover) and the next chapter
   buries the pin again (cover). Without this the sticky pin covers live content
   the moment the reveal's -100svh margin starts. */
.cs-chapter {
  position: relative;
  z-index: 2;
  background: var(--cs-ground);
}

/* Row of mounted product cards. The product ships `.cv-stat` itself but its
   ROW layout is page-level in the real dashboard (`.cv-stat-row` exists only in
   a mobile media query), so the marketing wrapper supplies it here. This is the
   control layer doing its job — not a fork of product CSS. */
.cs-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  gap: 12px;
  align-items: stretch;
}

.cs-row > * { min-width: 0; }

.cs-list > * + * { margin-top: 8px; }

/* Body copy holds 65–75ch even when a scene beside it runs full width. */
.cs-measure { max-width: var(--cs-measure); }

.cs-rule {
  height: 1px;
  border: 0;
  margin: 0;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.10) 12%,
    rgba(255, 255, 255, 0.10) 88%,
    transparent
  );
}

/* ── Type ─────────────────────────────────────────────────────────────── */

.cs-display, .cs-headline, .cs-title { color: var(--cs-text); text-wrap: balance; }

.cs-display {
  font-size: clamp(44px, 5vw, 72px);
  font-weight: 500;
  line-height: 1.0;
  letter-spacing: -0.022em;
  margin: 0;
}

.cs-headline {
  font-size: 48px;
  font-weight: 510;
  line-height: 1.0;
  letter-spacing: -0.022em;
  margin: 0;
}

.cs-title {
  font-size: 24px;
  font-weight: 510;
  line-height: 1.33;
  letter-spacing: -0.012em;
  margin: 0;
}

.cs-subhead {
  font-size: 24px;
  font-weight: 400;
  line-height: 1.33;
  letter-spacing: -0.012em;
  color: var(--cs-text-bright);
  margin: 0;
}

.cs-body    { font-size: 15px; line-height: 24px; letter-spacing: -0.011em; color: var(--cs-text-2); }
.cs-body-lg { font-size: 15px; line-height: 24px; letter-spacing: -0.011em; color: var(--cs-text-2); }
.cs-caption { font-size: 13px; line-height: 20px; color: var(--cs-text-3); }

/* The Two-Tone Headline Rule: white clause, grey continuation, same sentence. */
.cs-dim { color: var(--cs-text-2); }

/* The Mono Chapter Rule: every beat opens with "1.0 The floor". */
.cs-marker {
  font-size: 15px;
  font-weight: 400;
  line-height: 24px;
  letter-spacing: -0.011em;
  font-variant-numeric: tabular-nums;
  color: var(--cs-text-3);
  display: block;
  margin: 0 0 16px;
}

.cs-fig { /* "FIG 0.2" — same register, used under an illustration */
  font-family: var(--cs-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--cs-text-3);
  margin-top: 16px;
}

/* ── Nav ──────────────────────────────────────────────────────────────── */

.cs-nav {
  position: fixed;
  inset: 0 0 auto;
  z-index: 100;
  background: rgba(8, 9, 10, 0.72);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s var(--cs-ease), background 0.3s var(--cs-ease);
}

.cs-nav.is-scrolled { border-bottom-color: rgba(255, 255, 255, 0.10); }

.cs-nav__inner {
  display: flex;
  align-items: center;
  gap: 32px;
  height: 56px;
  margin-inline: auto;
  padding-inline: var(--cs-gutter);
}

.cs-nav__links { display: flex; align-items: center; gap: 24px; margin-left: auto; }

.cs-nav__link {
  font-size: 15px;
  color: var(--cs-text-2);
  text-decoration: none;
  transition: color 0.2s var(--cs-ease);
}

.cs-nav__link:hover      { color: var(--cs-text); }
.cs-nav__link.is-active  { color: var(--cs-text); }

/* ── Buttons ──────────────────────────────────────────────────────────── */

/* The One Loud Thing Rule: the only white fill on the page. */
.cs-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 20px;
  border-radius: 999px;
  border: 0;
  background: #FFFFFF;
  color: #08090A;
  font-family: inherit;
  font-size: 15px;
  font-weight: 520;
  line-height: 1.4;
  text-decoration: none;
  cursor: pointer;
  transition: opacity 0.2s var(--cs-ease);
}

.cs-btn:hover { opacity: 0.88; }

/* A nav pill is a flex item of .cs-nav__inner. Without this it compresses to a
   circle with its label wrapped to three lines on a phone — the mobile block's
   `.cs-nav__links > *` rule only reaches pills nested INSIDE the link row, and
   the pages put theirs alongside it. Asserted here so every page inherits the
   fix regardless of which side of .cs-nav__links its CTA sits on. */
.cs-nav .cs-btn, .cs-nav__link { flex: 0 0 auto; white-space: nowrap; }

.cs-btn--ghost {
  background: transparent;
  color: var(--cs-text-2);
  padding: 10px 16px;
  border-radius: 999px;
}

.cs-btn--ghost:hover { color: var(--cs-text); opacity: 1; }

.cs-link {
  color: var(--cs-text-2);
  font-size: 15px;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 0.2s var(--cs-ease), border-color 0.2s var(--cs-ease);
}

.cs-link:hover { color: var(--cs-text); border-bottom-color: rgba(255, 255, 255, 0.10); }

/* ── Cards ────────────────────────────────────────────────────────────── */

.cs-card {
  background: var(--cs-surface);
  border: 1px solid var(--cs-border);
  border-radius: 14px;
  padding: 24px;
}

/* The Lit Stage — the one surface lighter than the panels, reserved for
   exhibit frames holding dark product captures (Linear's device). Top-lit:
   a soft white glow at the top edge over a falling grey gradient. */
.cs-lit {
  background:
    radial-gradient(90% 60% at 50% 0%, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0) 60%),
    linear-gradient(180deg, #2A2B30 0%, #17181B 100%);
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 20px;
}

/* Stacked / receding cards — each step back dims toward the ground. */
.cs-stack { position: relative; display: grid; }

.cs-stack > .cs-card {
  grid-area: 1 / 1;
  transform: translateY(calc(var(--i, 0) * 28px)) scale(calc(1 - var(--i, 0) * 0.035));
  opacity: calc(1 - var(--i, 0) * 0.28);
  background: var(--cs-surface-raised);
  z-index: calc(10 - var(--i, 0));
}

.cs-stack > .cs-card:not(:first-child) { background: var(--cs-surface); }

/* ── Split hero + index row ───────────────────────────────────────────── */

.cs-split {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 40px;
  align-items: end;
}

.cs-index {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0;
  border-top: 1px solid var(--cs-border);
}

.cs-index__col {
  min-width: 0;
  padding: 24px 24px 24px 0;
  border-right: 1px solid var(--cs-border);
}

.cs-index__col:last-child { border-right: 0; }

/* ── Chapter reveal (the verified curtain mechanic) ───────────────────── */
/*
   height 360svh + sticky 100svh pin + -100svh margins on both sides
   ⇒ uncover 100 / dwell ~60 / cover 100. At 200svh the dwell is zero and the
   reveal never reads. Scroll-native — no JS.
*/
.cs-reveal {
  position: relative;
  z-index: 1;              /* sits BEHIND .cs-chapter, which lifts off it */
  height: 360svh;
  margin-top: -100svh;
  margin-bottom: -100svh;
}

.cs-reveal__pin {
  position: sticky;
  top: 0;
  height: 100svh;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--cs-ground);
}

.cs-reveal__body { position: relative; z-index: 2; text-align: center; padding-inline: var(--cs-gutter); }

/* Full-viewport chapter break: a faded product backdrop carries the reveal now
   that dark-on-dark means the old light→dark inversion no longer can. */
.cs-backdrop {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  opacity: 0.07;
  filter: brightness(0.8) saturate(0.5);
  pointer-events: none;
}

.cs-backdrop::after { /* vignette so the backdrop dies into the ground */
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.35) 20%, rgba(0, 0, 0, 0.95) 85%);
}

/* ── Perspective hero backdrop ────────────────────────────────────────── */

.cs-perspective {
  perspective: 1600px;
  perspective-origin: 50% 0%;
}

.cs-perspective__plane {
  transform: rotateX(34deg) rotateZ(-8deg) translateZ(-120px);
  transform-origin: 50% 0%;
  opacity: 0.16;
  filter: brightness(0.85);
  mask-image: linear-gradient(180deg, #000 0%, #000 45%, transparent 92%);
}

/* ── Mounted product surface (the signature component) ────────────────── */
/*
   Everything here is the marketing CONTROL LAYER. It scales, tilts, frames and
   scrolls the real surface from the outside. It must never restyle what is
   inside — that is The Never-Fork Rule.
*/
.cs-surface {
  position: relative;
  border: 1px solid var(--cs-border-strong);
  border-radius: 20px;
  overflow: hidden;
  background: var(--cs-surface);
  isolation: isolate;
}

/* Fidelity at size: render at true resolution, then scale the whole surface. */
.cs-surface__scale {
  transform: scale(var(--scale, 1));
  transform-origin: top left;
  width: calc(100% / var(--scale, 1));
  height: calc(100% / var(--scale, 1));
}

/* Scroll-in-frame: the worker moves through the task while the frame holds. */
.cs-surface--scroll { height: var(--frame-h, 420px); }
.cs-surface--scroll .cs-surface__track {
  transform: translateY(var(--scroll-y, 0px));
  transition: transform 0.9s var(--cs-ease);
  will-change: transform;
}

/* Phone frame for the floor / manager push moments. */
.cs-phone {
  width: 300px;
  border: 1px solid var(--cs-border-strong);
  border-radius: 20px;
  overflow: hidden;
  background: var(--cs-ground);
}

/* ── Motion ───────────────────────────────────────────────────────────── */

.cs-fade {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.7s var(--cs-ease), transform 0.7s var(--cs-ease);
}

.cs-fade.is-in { opacity: 1; transform: none; }

/* The Linear headline entrance — §13's house move for type: the copy rises
   from below while a blur resolves to sharp. TEXT ONLY — a blur entrance on
   imagery is paint-heavy and reads as a loading defect, so images keep the
   plain fade above. The subhead trails the headline by a beat. */
.cs-display.cs-fade, .cs-headline.cs-fade, .cs-title.cs-fade {
  transform: translateY(22px);
  filter: blur(14px);
  transition: opacity 1.5s var(--cs-ease), transform 1.5s var(--cs-ease),
              filter 1.5s var(--cs-ease);
}

.cs-subhead.cs-fade {
  transform: translateY(18px);
  filter: blur(9px);
  transition: opacity 1.4s var(--cs-ease) 0.25s, transform 1.4s var(--cs-ease) 0.25s,
              filter 1.4s var(--cs-ease) 0.25s;
}

.cs-display.cs-fade.is-in, .cs-headline.cs-fade.is-in,
.cs-title.cs-fade.is-in, .cs-subhead.cs-fade.is-in { filter: blur(0); }

/* ── Responsive — 768px, and only 768px ───────────────────────────────── */

@media (max-width: 768px) {
  :root { --cs-section: 64px; --cs-chapter: 96px; --cs-gutter: 20px; }

  .cs-headline { font-size: 32px; line-height: 1.1; }

  .cs-split { grid-template-columns: minmax(0, 1fr); gap: 24px; align-items: start; }
  .cs-index { grid-template-columns: minmax(0, 1fr); }
  .cs-index__col { border-right: 0; border-bottom: 1px solid var(--cs-border); padding-right: 0; }
  .cs-index__col:last-child { border-bottom: 0; }

  .cs-card { padding: 16px; }

  /* Seven links + the pill overflow a phone. Until the production sheet menu
     exists, the link row scrolls horizontally inside the bar — legible, no
     body overflow, no JS. */
  .cs-nav__links { gap: 16px; overflow-x: auto; scrollbar-width: none; }
  .cs-nav__links::-webkit-scrollbar { display: none; }
  .cs-nav__links > * { flex: 0 0 auto; }  /* links AND the CTA pill: scroll, never compress */

  /* Dense surfaces scroll inside their own frame rather than shrinking below
     legibility. The page body never scrolls horizontally. */
  .cs-surface { overflow-x: auto; }
  .cs-phone { width: 260px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }

  /* Scenes resolve to their final state rather than animating. */
  .cs-fade { opacity: 1; transform: none; filter: none; }
  .cs-surface--scroll .cs-surface__track { transform: none; }
}


/* ═══════════ Vignette kit (2026-08-19) — built sections that break the screenshot
   rhythm: gradient-lit stage panels, layered depth cards, light statement cards,
   bento cells with recreated UI, animated isometric diagrams, tri-panels.
   Recreated product UI drawn in HTML/SVG — never a screenshot. ═══════════ */

  /* Gradient-framed panel — the top-lit stage that frames depth vignettes. */
  .vig-panel--lit {
    background:
      radial-gradient(120% 90% at 50% -10%, rgba(208,214,224,0.16) 0%, rgba(208,214,224,0.05) 36%, rgba(208,214,224,0) 62%),
      #0A0A0B;
  }
  .stage-panel { margin-top: 48px; padding: 40px clamp(20px, 4vw, 56px); }
  .stage-panel .stack { margin-top: 0; }

  /* Layered depth cards — batch over batch receding into the record. */
  .stack { position: relative; height: 440px; margin-top: 48px; }
  .b-card { position: absolute; width: min(420px, 86%); background: rgba(16,17,19,0.94); border: 1px solid var(--cs-border-strong); border-radius: 14px; padding: 22px 24px; }
  .b-card--back  { left: 6%; top: 24px; opacity: 0.32; transform: scale(0.94); }
  .b-card--mid   { left: 50%; transform: translateX(-70%) scale(0.97); top: 52px; opacity: 0.58; }
  .b-card--front { right: 6%; top: 96px; box-shadow: 0 24px 80px rgba(0,0,0,0.5); }
  .b-card__hd { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
  .b-card__hd b { font-size: 15px; font-weight: 590; color: var(--cs-text); }
  .b-card__hd .mono { font-family: var(--cs-mono); font-size: 12px; color: var(--cs-text-3); }
  .b-stats { display: flex; gap: 22px; margin-top: 14px; }
  .b-stat span { display: block; font-size: 12px; color: var(--cs-text-3); }
  .b-stat b { font-size: 15px; font-weight: 590; color: var(--cs-text); font-variant-numeric: tabular-nums; }
  .b-card svg { display: block; width: 100%; height: 84px; margin-top: 16px; }
  @media (max-width: 768px) {
    .stack { height: 540px; }
    .b-card--back { left: 0; top: 0; } .b-card--mid { left: 8%; transform: scale(0.97); top: 70px; } .b-card--front { right: 0; top: 170px; }
  }

  /* Light statement cards — the one deliberate color break on the page. */
  .quotes { display: grid; grid-template-columns: 1.55fr 1fr; gap: 16px; }
  .qcard { border-radius: 14px; padding: 44px 44px 36px; min-height: 340px; display: flex; flex-direction: column; }
  .qcard--paper { background: #F4F4F2; color: #0B0C0E; }
  .qcard--moss  { background: #DFE9E2; color: #0B0C0E; }
  .qcard__q { font-size: 24px; line-height: 1.3; font-weight: 540; letter-spacing: -0.01em; max-width: 24ch; }
  .qcard__q .dim { color: #5A5F58; }
  .qcard__tag { margin-top: auto; padding-top: 40px; font-family: var(--cs-mono); font-size: 12px; letter-spacing: 0.08em; color: #5A5F58; }
  @media (max-width: 768px) { .quotes { grid-template-columns: minmax(0,1fr); } .qcard { min-height: 240px; padding: 32px 28px; } }

  /* Bento — one bordered panel, hairline-split cells, recreated UI floating inside. */
  .vig-panel { border: 1px solid var(--cs-border); border-radius: 14px; background: #0A0A0B; overflow: hidden; }
  .bento { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); margin-top: 48px; }
  .bento__cell { padding: 48px 40px 36px; border-left: 1px solid var(--cs-border); display: flex; flex-direction: column; gap: 32px; min-height: 460px; }
  .bento__cell:first-child { border-left: 0; }
  .bento__stage { flex: 1; position: relative; min-height: 250px; }
  .bento__t { font-size: 15px; font-weight: 560; color: var(--cs-text); }
  .bento__d { font-size: 13.5px; line-height: 21px; color: var(--cs-text-2); margin-top: 6px; max-width: 44ch; }
  @media (max-width: 768px) {
    .bento { grid-template-columns: minmax(0,1fr); }
    .bento__cell { border-left: 0; border-top: 1px solid var(--cs-border); min-height: 0; }
    .bento__cell:first-child { border-top: 0; }
  }
  .trow { display: flex; align-items: center; gap: 12px; background: var(--cs-surface-raised); border: 1px solid var(--cs-border); border-radius: 10px; padding: 12px 14px; font-size: 13px; color: var(--cs-text-2); }
  .trow b { color: var(--cs-text); font-weight: 560; }
  .trow .mono { font-family: var(--cs-mono); font-size: 12px; color: var(--cs-text-3); margin-left: auto; white-space: nowrap; }
  .trow .av { width: 22px; height: 22px; border-radius: 50%; background: #2A2B30; display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--cs-text-2); flex: 0 0 auto; }
  .dot { width: 6px; height: 6px; border-radius: 50%; flex: 0 0 auto; }
  .dot--live { background: #5FA97C; }
  .dot--wait { background: #C9943A; }
  .chipfloat { position: absolute; display: flex; align-items: center; gap: 10px; background: var(--cs-surface-raised); border: 1px solid var(--cs-border); border-radius: 999px; padding: 8px 14px; font-size: 13px; color: var(--cs-text-2); white-space: nowrap; max-width: 100%; }
  .chipfloat .mono { font-family: var(--cs-mono); font-size: 12px; color: var(--cs-text-3); }

  /* Tri-panel — three tall colored cards, each a floating recreated vignette. */
  .tri { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 16px; margin-top: 48px; }
  .tri__card { border-radius: 14px; min-height: 560px; padding: 36px 32px 32px; display: flex; flex-direction: column; position: relative; overflow: hidden; }
  .tri__card--clay { background: #B4532A; color: #F6EDE7; }
  .tri__card--moss { background: linear-gradient(180deg, #DFE9E2 0%, #CDE0D3 100%); color: #0B0C0E; }
  .tri__card--paper { background: #F4F4F2; color: #0B0C0E; }
  .tri__badge { font-family: var(--cs-mono); font-size: 12px; letter-spacing: 0.12em; opacity: 0.85; }
  .tri__stage { flex: 1; position: relative; margin: 28px 0; min-height: 220px; }
  .tri__t { font-size: 15px; font-weight: 590; }
  .tri__d { font-size: 13.5px; line-height: 21px; margin-top: 6px; opacity: 0.78; max-width: 40ch; }
  .tri__term { position: absolute; inset: 8% 0 auto 0; background: rgba(0,0,0,0.28); border: 1px solid rgba(246,237,231,0.28); border-radius: 10px; padding: 20px 22px; font-family: var(--cs-mono); font-size: 12px; line-height: 2.05; color: #F6EDE7; }
  .tri__menu { position: absolute; left: 0; right: 8%; background: #FFFFFF; border-radius: 10px; box-shadow: 0 18px 50px rgba(11,15,12,0.18); padding: 10px; font-size: 13px; color: #0B0C0E; }
  .tri__menu .mrow { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 6px; }
  .tri__menu .mrow.is-on { background: #EEF4EF; }
  .tri__menu .mrow .mono { font-family: var(--cs-mono); font-size: 12px; color: #5A5F58; margin-left: auto; }
  .tri__dark { position: absolute; left: 6%; right: 0; background: #141517; border: 1px solid rgba(255,255,255,0.10); border-radius: 10px; box-shadow: 0 18px 50px rgba(0,0,0,0.35); padding: 10px; font-size: 13px; color: #D0D6E0; }
  .tri__dark .mrow { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 6px; }
  .tri__dark .mrow.is-on { background: #2A2B30; color: #F7F8F8; }
  .tri__dark .mrow .mono { font-family: var(--cs-mono); font-size: 12px; color: #8A8F98; margin-left: auto; }
  .tri__prompt { position: absolute; top: 0; left: 0; right: 12%; background: #FFFFFF; border: 1px solid rgba(11,12,14,0.12); border-radius: 999px; padding: 12px 18px; font-size: 13px; color: #5A5F58; box-shadow: 0 10px 30px rgba(11,15,12,0.12); }
  @media (max-width: 900px) { .tri { grid-template-columns: minmax(0,1fr); } .tri__card { min-height: 480px; } }

  /* Isometric line diagram — the mirror, drawn. Amber sync-flow travels the gap;
     faint rings breathe behind; a warm glow sits where the flows meet. */
  .iso { position: relative; padding: 72px 40px; min-height: 560px; display: flex; align-items: center; justify-content: center; margin-top: 48px; }
  .iso svg.diagram { position: relative; z-index: 2; width: min(560px, 80%); height: auto; color: var(--cs-text-3); }
  .iso__rings { position: absolute; inset: 0; z-index: 0; display: flex; align-items: center; justify-content: center; pointer-events: none; }
  .iso__rings i { position: absolute; border: 1px solid rgba(255,255,255,0.06); border-radius: 50%; opacity: 0.55; }
  .iso__rings i:nth-child(1) { width: 560px; height: 560px; animation: ring-breathe 16s ease-in-out infinite; }
  .iso__rings i:nth-child(2) { width: 820px; height: 820px; opacity: 0.4; animation: ring-breathe 16s ease-in-out 2s infinite; }
  .iso__rings i:nth-child(3) { width: 1120px; height: 1120px; opacity: 0.25; animation: ring-breathe 16s ease-in-out 4s infinite; }
  @keyframes ring-breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.035); } }
  .iso__glow {
    position: absolute; z-index: 1; left: 50%; top: 50%; width: 300px; height: 170px;
    transform: translate(-50%, -50%); pointer-events: none;
    background: radial-gradient(50% 50% at 50% 50%, rgba(201,148,58,0.14) 0%, rgba(201,148,58,0) 70%);
    animation: glow-pulse 4.8s ease-in-out infinite;
  }
  @keyframes glow-pulse { 0%, 100% { opacity: 0.5; } 50% { opacity: 1; } }
  .iso .flow path { opacity: 0; filter: drop-shadow(0 0 5px rgba(201,148,58,0.55)); }
  .flow--up path   { animation: flow-up 2.6s cubic-bezier(0.33, 0, 0.35, 1) infinite; }
  .flow--down path { animation: flow-down 2.6s cubic-bezier(0.33, 0, 0.35, 1) infinite; }
  .flow--up path:nth-child(2), .flow--down path:nth-child(2) { animation-delay: 0.45s; }
  .flow--up path:nth-child(3), .flow--down path:nth-child(3) { animation-delay: 0.9s; }
  @keyframes flow-up {
    0%   { opacity: 0; transform: translateY(18px); }
    28%  { opacity: 1; }
    62%  { opacity: 0.9; }
    100% { opacity: 0; transform: translateY(-18px); }
  }
  @keyframes flow-down {
    0%   { opacity: 0; transform: translateY(-18px); }
    28%  { opacity: 1; }
    62%  { opacity: 0.9; }
    100% { opacity: 0; transform: translateY(18px); }
  }
  @media (prefers-reduced-motion: reduce) {
    .iso__rings i, .iso__glow { animation: none; }
    .iso .flow path { animation: none; opacity: 0.85; }
    .iso .flow path:nth-child(2), .iso .flow path:nth-child(3) { opacity: 0; }
  }

  .iso__cap { position: absolute; max-width: 280px; font-family: var(--cs-mono); }
  .iso__cap b { display: block; font-size: 12px; letter-spacing: 0.1em; color: var(--cs-text); font-weight: 560; }
  .iso__cap span { display: block; margin-top: 8px; font-size: 12px; line-height: 1.7; color: var(--cs-text-3); }
  .iso__cap--tl { left: 40px; top: 25%; text-align: right; }
  .iso__cap--bl { left: 40px; bottom: 23%; text-align: right; }
  .iso__cap--tr { right: 40px; top: 25%; }
  .iso__cap--br { right: 40px; bottom: 23%; }
  @media (max-width: 980px) {
    .iso { flex-direction: column; gap: 28px; padding: 48px 24px; min-height: 0; }
    .iso__cap { position: static; text-align: left !important; max-width: none; }
  }

/* ═══════════ Site footer (2026-08-21) — full-nav footer, Linear grammar:
   hairline top rule, link columns, slim legal row. Chrome, not a vignette —
   identical across pages by design. ═══════════ */
.cs-footer { border-top: 1px solid var(--cs-border); padding: 64px 0 40px; }
.cs-footer__grid { display: grid; grid-template-columns: 1.4fr repeat(3, minmax(0, 1fr)); gap: 40px 24px; }
.cs-footer__brand { font-size: 15px; font-weight: 520; color: var(--cs-text); }
.cs-footer__tag { margin-top: 10px; font-size: 13px; line-height: 20px; color: var(--cs-text-3); max-width: 26ch; }
.cs-footer__h { font-family: var(--cs-mono); font-size: 12px; letter-spacing: 0.08em; color: var(--cs-text-3); margin-bottom: 14px; }
.cs-footer__col a { display: block; font-size: 13.5px; line-height: 30px; color: var(--cs-text-2); text-decoration: none; transition: color 0.2s var(--cs-ease); }
.cs-footer__col a:hover { color: var(--cs-text); }
.cs-footer__bottom { display: flex; flex-wrap: wrap; gap: 10px 24px; align-items: baseline; justify-content: space-between; margin-top: 56px; padding-top: 24px; border-top: 1px solid var(--cs-border); }
.cs-footer__legalrow { display: flex; flex-wrap: wrap; gap: 18px; }
.cs-footer__legalrow a { font-size: 12.5px; color: var(--cs-text-3); text-decoration: none; }
.cs-footer__legalrow a:hover { color: var(--cs-text-2); }
.cs-footer__note { font-size: 12.5px; color: var(--cs-text-3); max-width: 72ch; }
@media (max-width: 900px) { .cs-footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ═══════════ Accessibility (2026-08-21 publish) — keyboard operability.
   Published Accessibility Statement commits to WCAG 2.1 AA; these are the
   focus-visibility and bypass-block basics. ═══════════ */
.cs-skip {
  position: absolute; left: 12px; top: -60px; z-index: 10000;
  background: var(--cs-text); color: var(--cs-ground);
  padding: 10px 18px; border-radius: 0 0 10px 10px;
  font-size: 14px; font-weight: 560; text-decoration: none;
  transition: top 0.15s var(--cs-ease);
}
.cs-skip:focus { top: 0; }
/* Visible focus ring on every interactive control (2.4.7 Focus Visible). */
a:focus-visible, button:focus-visible, [tabindex]:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid #F7F8F8;
  outline-offset: 3px;
  border-radius: 4px;
}
/* Light vignette cards invert the ring so it stays visible on paper/moss. */
.qcard a:focus-visible, .tri__card a:focus-visible { outline-color: #0B0C0E; }

/* ══════════════════════════════════════════════════════════════════════════
   MOBILE CHROME — the dashboard's "reveal underneath" drawer, ported.
   The nav sits STATIC underneath on the left; tapping ☰ slides the whole top
   screen (bar + page + its scrim) right and mutes it, uncovering the nav.
   Mirrors app/dashboard/wireframes/shell.css so the marketing site and the
   product open their menus the same way. Three differences, all deliberate:
   the marketing site scrolls the document (so open() locks scroll in JS rather
   than relying on an app-shell inner scroller), aria-expanded is kept live, and
   reduced motion is honoured — all three are gaps in the dashboard original.
   ══════════════════════════════════════════════════════════════════════════ */

.cs-mbtn, .cs-drawer, .cs-mscrim { display: none; }

@media (max-width: 768px) {
  /* Belt and braces against sideways drift: `clip` (unlike `hidden`) cannot
     silently turn an ancestor into a scroll container, so a stray wide child
     is contained without stealing the page's vertical scroll. */
  html, body { overflow-x: clip; }

  body { --mnav-w: min(78vw, 320px); }

  /* The link row and its utility links move into the drawer — nothing stranded.
     `:not(:first-child)` spares the wordmark, which is itself a .cs-nav__link. */
  .cs-nav__links { display: none; }
  .cs-nav .cs-btn { display: none; }
  .cs-nav__inner > .cs-nav__link:not(:first-child) { display: none; }
  .cs-nav__inner { justify-content: space-between; gap: 12px; }

  .cs-mbtn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 42px; height: 42px; flex: 0 0 42px; margin-left: auto;
    padding: 0; border: 0; border-radius: 11px;
    background: none; color: var(--cs-text); cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .cs-mbtn:active { background: rgba(255, 255, 255, 0.08); }
  .cs-mbtn svg { stroke: currentColor; fill: none; }

  /* The drawer — static, anchored left, UNDERNEATH the top screen. It never
     slides; it is revealed. */
  .cs-drawer {
    display: flex; flex-direction: column;
    position: fixed; top: 0; left: 0; bottom: 0; right: auto;
    width: var(--mnav-w); z-index: 1;
    overflow-y: auto; overscroll-behavior: contain;
    background: var(--cs-surface); border-right: 1px solid var(--cs-border);
    padding: calc(env(safe-area-inset-top) + 18px) 14px calc(env(safe-area-inset-bottom) + 18px);
  }
  .cs-drawer__brand {
    font-size: 15px; font-weight: 560; color: var(--cs-text);
    text-decoration: none; padding: 6px 10px 14px;
  }
  .cs-drawer__nav { display: flex; flex-direction: column; }
  .cs-drawer__link {
    padding: 12px 10px; border-radius: 9px;
    font-size: 16px; line-height: 24px; color: var(--cs-text-2); text-decoration: none;
    -webkit-tap-highlight-color: transparent;
  }
  .cs-drawer__link:active { background: var(--cs-surface-raised); }
  .cs-drawer__link.is-active { color: var(--cs-text); font-weight: 540; }
  .cs-drawer__foot {
    margin-top: auto; padding-top: 18px;
    display: flex; flex-direction: column; gap: 9px;
    border-top: 1px solid var(--cs-border);
  }
  .cs-drawer__foot .cs-btn { display: inline-flex; justify-content: center; }
  .cs-drawer__foot .cs-drawer__link { text-align: center; }

  /* The "top screen" — bar + page — opaque, above the drawer, slides to reveal. */
  /* NO will-change here. .cs-screen is the height of the WHOLE document, so
     promoting it permanently hands iOS Safari a layer of roughly
     390 × doc-height × dpr² pixels — past the rasterisation budget, at which
     point images inside it stop decoding and render as broken placeholders.
     The transform on open promotes it transiently, which Safari tiles; a
     standing will-change does not give it that choice. */
  .cs-screen {
    position: relative; z-index: 10; background: var(--cs-ground);
    transform-origin: top left;
    transition: transform 0.36s cubic-bezier(.32,.72,0,1), border-radius 0.36s;
  }
  .cs-nav {
    transform-origin: top left;
    transition: transform 0.36s cubic-bezier(.32,.72,0,1), border-radius 0.36s,
                border-color 0.3s var(--cs-ease), background 0.3s var(--cs-ease);
  }

  body.cs-mnav-open { position: fixed; left: 0; right: 0; width: 100%; }
  body.cs-mnav-open .cs-screen,
  body.cs-mnav-open .cs-nav,
  body.cs-mnav-open .cs-mscrim { transform: translateX(var(--mnav-w)) scale(.955); }
  body.cs-mnav-open .cs-screen { border-radius: 22px; overflow: hidden; box-shadow: -14px 0 50px rgba(0, 0, 0, 0.44); }
  body.cs-mnav-open .cs-nav { border-radius: 22px 22px 0 0; box-shadow: -14px 0 50px rgba(0, 0, 0, 0.3); }

  /* Mute + tap-to-close. Carries the same transform as the screen, so it covers
     only the slid page and never the revealed drawer — nav items stay tappable. */
  .cs-mscrim {
    display: block; position: fixed; inset: 0; z-index: 15;
    background: rgba(0, 0, 0, 0.38);
    opacity: 0; pointer-events: none; transform-origin: top left;
    transition: opacity 0.3s ease, transform 0.36s cubic-bezier(.32,.72,0,1);
  }
  body.cs-mnav-open .cs-mscrim { opacity: 1; pointer-events: auto; }

  /* Companion-panel pairs — a main exhibit with its drawer/detail beside it —
     STACK on a phone. They are one composition, not a series: swiping hid the
     companion behind a cut edge (Ryan 2026-08-24, ten captures). Swipe is for
     true series only (.car-/.step-/.rep- stages, .apexphones, .prow).
     !important outranks both the pages' own grid declarations (they load after
     this sheet) and the two inline grid-template-columns on sales.html. */
  .duo, .brain-duo, .ph-duo, .pr-duo { grid-template-columns: minmax(0, 1fr) !important; }

  /* ── Pane groups become swipe tracks ──────────────────────────────────
     Desktop shows one pane at a time behind a button row. Stacking that series
     vertically on a phone buries it, and the off-stage panes' translateX is
     what pushed the document sideways. On touch the set becomes one horizontal
     scroll-snap track: every frame reachable by swipe, with momentum, velocity
     handoff and rubber-banding supplied by the platform rather than
     re-simulated in JS. !important is load-order, not laziness — the chassis
     loads before each page's inline <style>, so equal specificity loses. */
  .cs-swipe {
    /* `display` needs the override too: a series container declares its own
       `display: grid` in the page's inline <style>, which loads after this file
       and wins on equal specificity. Without it the track lays out as a grid,
       the frames divide the row instead of overflowing, and nothing scrolls. */
    position: static; display: flex !important; gap: 12px;
    height: auto; min-height: 0; aspect-ratio: auto;
    overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    padding-inline: var(--cs-gutter);
    margin-inline: calc(var(--cs-gutter) * -1);
    scroll-padding-inline: var(--cs-gutter);
  }
  .cs-swipe::-webkit-scrollbar { display: none; }
  /* Deliberately no `display` here: carousel panes already carry their own
     centring flex, and a plain series frame must keep whatever display it had.
     Forcing one would break the other. */
  .cs-swipe > * {
    position: relative !important; inset: auto !important;
    flex: 0 0 86%; scroll-snap-align: center;
    opacity: 1 !important; visibility: visible !important;
    transform: none !important; pointer-events: auto !important;
    transition: none !important;
    margin-top: 0 !important;
  }
  .cs-swipe > * > img,
  .cs-swipe > * > .cs-surface { max-width: 100%; }

  /* Progress dots — the swipe's only affordance beyond the frames themselves. */
  .cs-dots { display: flex; gap: 7px; justify-content: center; margin-top: 14px; }
  .cs-dots__d {
    width: 6px; height: 6px; padding: 0; border: 0; border-radius: 50%;
    background: rgba(255, 255, 255, 0.24); cursor: pointer;
    transition: background 0.25s var(--cs-ease), transform 0.25s var(--cs-ease);
    -webkit-tap-highlight-color: transparent;
  }
  .cs-dots__d.is-on { background: var(--cs-text); transform: scale(1.35); }
}

@media (min-width: 769px) {
  .cs-mbtn, .cs-drawer, .cs-mscrim, .cs-dots { display: none !important; }
}

/* The slide is a large translate+scale — exactly the vestibular motion reduced
   motion asks us to drop. The drawer still reveals; it just cuts rather than
   travels. (The dashboard original does not do this.) */
@media (prefers-reduced-motion: reduce) {
  .cs-screen, .cs-nav, .cs-mscrim { transition: opacity 0.2s ease !important; }
  body.cs-mnav-open .cs-screen,
  body.cs-mnav-open .cs-nav,
  body.cs-mnav-open .cs-mscrim { transform: translateX(var(--mnav-w)) !important; }
  .cs-swipe { scroll-behavior: auto; }
}

/* ── Live capture loops ─────────────────────────────────────────────────
   Screen recordings of the real product, dropped into the same frames the
   static captures use. Sized like .shotframe img; playback is governed by
   wireVideos() in cannvas-site.js (in-view play, out-of-view pause, no
   autoplay under prefers-reduced-motion — the poster carries the frame). */
.cs-surface video.vidloop { width: 100%; height: auto; display: block; }
.rep-pane .cs-surface video.vidloop { height: 100%; object-fit: cover; object-position: center 30%; }
