/* rev0 showcase page. One HTML, two CSS files, no build step. Colour tokens
   are lifted from the product's own frontend/src/styles/index.css.

   Motion rule: everything is laid out and VISIBLE by default; animation is added
   only inside `@supports` + `prefers-reduced-motion: no-preference`. Hence no
   blanket `* { animation: none }` reset, which with scroll-driven animation would
   strand elements at their hidden start state. */

/* --- fonts ---------------------------------------------------------------- */

@font-face {
  font-family: "Inter Variable";
  src: url("fonts/inter-latin-wght-normal.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono Variable";
  src: url("fonts/jetbrains-mono-latin-wght-normal.woff2") format("woff2");
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

/* The "by cpc.studio" byline, in the face cpc.studio itself names. */
@font-face {
  font-family: "Figtree Variable";
  src: url("fonts/figtree-latin-wght-normal.woff2") format("woff2");
  font-weight: 300 900;
  font-style: normal;
  font-display: swap;
}

/* --- tokens --------------------------------------------------------------- */

:root {
  color-scheme: dark;

  --surface-0: oklch(0.145 0.008 285);
  --surface-1: oklch(0.185 0.01 285);
  --surface-2: oklch(0.215 0.011 285);

  --fg: oklch(0.93 0.006 285);
  --fg-2: oklch(0.72 0.008 285);
  /* App uses 0.55, but that measures 3.6-4.1:1 here. 0.63 gives 4.97:1 worst case. */
  --fg-3: oklch(0.63 0.01 285);

  --edge: oklch(1 0 0 / 0.06);
  --edge-2: oklch(1 0 0 / 0.1);
  --edge-3: oklch(1 0 0 / 0.16);

  --accent: oklch(0.585 0.155 277);
  --accent-hi: oklch(0.7 0.16 277);
  --accent-glow: oklch(0.585 0.155 277 / 0.4);
  /* Monochrome chrome: the primary button, links and the focus ring are white on
     graphite, so the field's violet light is the page's one colour moment. */
  --ink: oklch(0.95 0.004 285);
  --ink-hover: oklch(0.84 0.006 285);

  /* the board's real status hues, reused so the lane strip is not invented colour */
  --todo: oklch(0.7 0.03 270);
  --progress: oklch(0.66 0.15 277);
  --pending: oklch(0.78 0.14 80);
  --review: oklch(0.7 0.15 300);
  --done: oklch(0.73 0.14 160);

  --r-sm: 6px;
  --r: 10px;
  --r-lg: 14px;

  --sans: "Inter Variable", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --mono: "JetBrains Mono Variable", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --enter: cubic-bezier(0.16, 1, 0.3, 1);
  --shell: min(1120px, 100% - 2.5rem);
}

/* Spring as a progressive upgrade: bezier baseline, spring only where linear()
   parses, transform only -- overshooting opacity means nothing. */
:root { --spring: cubic-bezier(0.16, 1, 0.3, 1); }
@supports (animation-timing-function: linear(0, 1)) {
  :root { --spring: linear(0, 0.407 12%, 0.82 24%, 1.06 34%, 1.13 42%, 1.06 55%, 0.99 70%, 1); }
}

* { box-sizing: border-box; }

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

body {
  margin: 0; background: var(--surface-0); color: var(--fg); overflow-x: hidden;
  font: 400 16px/1.6 var(--sans); font-feature-settings: "cv05";
  -webkit-font-smoothing: antialiased;
}

/* No grain layer: a fixed blend-mode tile recomposited on every scroll, and the
   field gives the hero its texture now. */
body > * { position: relative; z-index: 1; }

a { color: var(--ink); text-underline-offset: 3px; }
a:hover { color: var(--ink-hover); }

:where(a, button, video, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--ink); outline-offset: 3px; border-radius: var(--r-sm);
}

h1, h2, h3 { text-wrap: balance; letter-spacing: -0.02em; margin: 0; }
h1 { font-size: clamp(2.3rem, 6.6vw, 4.4rem); font-weight: 560; line-height: 1.02; letter-spacing: -0.028em; }
h2 { font-size: clamp(1.5rem, 3.8vw, 2.1rem); font-weight: 550; line-height: 1.15; }
h3 { font-size: 1.02rem; font-weight: 560; letter-spacing: -0.01em; }
p { margin: 0; }
code, kbd { font-family: var(--mono); font-size: 0.875em; }

.shell { width: var(--shell); margin-inline: auto; }
.eyebrow {
  font-family: var(--mono); font-size: 0.72rem; font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--fg-3);
}
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* Lit edges: a mask-composite hairline, what makes a dark surface read as one. */
.lit { position: relative; }
.lit::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1px;
  pointer-events: none;
  background: linear-gradient(160deg, oklch(1 0 0 / 0.14), oklch(1 0 0 / 0.02) 42%, oklch(1 0 0 / 0.07));
  mask-image: linear-gradient(#000, #000), linear-gradient(#000, #000);
  mask-clip: content-box, border-box; mask-composite: exclude;
  -webkit-mask-composite: xor;
}

/* --- nav ------------------------------------------------------------------ */

.nav {
  position: sticky; top: 0; z-index: 20; display: flex; align-items: center;
  gap: 0.9rem; padding: 0.7rem 0; border-bottom: 1px solid var(--edge);
  background: color-mix(in oklab, var(--surface-0) 82%, transparent);
  backdrop-filter: blur(14px);
}
.nav .shell { display: flex; align-items: center; gap: 0.9rem; width: var(--shell); }
.brand { display: flex; align-items: center; gap: 0.55rem; color: var(--fg); text-decoration: none; }
.brand img { display: block; width: 24px; height: 24px; border-radius: var(--r-sm); }
.brand:hover { color: var(--fg); }
/* The wordmark: mono at the letters' own weight; the font's 0 is the slashed one. */
.wm { font: 400 1.02rem/1.25 var(--mono); letter-spacing: -0.01em; white-space: nowrap; }
.byline {
  font: 500 0.84rem "Figtree Variable", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  color: var(--fg-3); text-decoration: none; white-space: nowrap;
}
.byline:hover { color: var(--fg); }
/* The roll: "rev" stays, the ending counts up through the words and lands on 0.
   The window is one 0 wide and clips only top and bottom, so the longer words run
   out to the right over the byline and badge, which are faded out while it rolls.
   Nothing here without roll.js: the markup is a plain "rev0". */
.roll { display: inline-block; width: 1ch; height: 1.25em; vertical-align: top; clip-path: inset(0 -40ch 0 0); }
.roll-col { display: flex; flex-direction: column; transform: translateY(calc(var(--i, 0) * -1.25em)); }
.roll-col[data-go] { transition: transform 0.17s var(--enter); }
.byline, .pill { transition: opacity 0.4s; }
[data-rolling] .byline, [data-rolling] .pill { opacity: 0; }
.pill {
  padding: 0.15rem 0.5rem; border: 1px solid var(--edge-2); border-radius: 999px;
  font-family: var(--mono); font-size: 0.68rem; color: var(--fg-3);
}
.nav-links { margin-left: auto; display: flex; gap: 1.1rem; font-size: 0.9rem; }
.nav-links a { color: var(--fg-2); text-decoration: none; }
.nav-links a:hover { color: var(--fg); }
@media (width < 480px) { .nav .pill { display: none; } }
/* Docs and Blog joined the nav; below 360px GitHub would push it 9px past the edge,
   and it is still in the footer. */
@media (width < 360px) { .nav .shell { gap: 0.6rem; } .nav-links { gap: 0.75rem; } .nav-links a[href^="https://github"] { display: none; } }

/* --- hero ----------------------------------------------------------------- */

.hero { position: relative; padding: clamp(2rem, 5.5vw, 3.5rem) 0 clamp(2rem, 5vw, 3rem); overflow: hidden; }

/* The lane field: the board abstracted to its columns. Static, deliberately: an
   @property-animated gradient composites nowhere and repaints every frame. */
.hero::before {
  content: ""; position: absolute; inset: -10% -5% 0; z-index: -1;
  background:
    radial-gradient(60% 45% at 50% 0%, oklch(0.585 0.155 277 / 0.18), transparent 70%),
    repeating-linear-gradient(90deg, var(--edge) 0 1px, transparent 1px calc(100% / 6));
  mask-image: linear-gradient(#000 35%, transparent 92%);
}

/* The chip row is the noun the headline leaves out: what this is, where it runs,
   what it drives. One row, so it replaces the badge, the engines line and the
   platform note, which is what pulls the window up into the first screen. */
.chips {
  display: flex; flex-wrap: wrap; gap: 0.45rem; margin: 0 0 1.3rem; padding: 0; list-style: none;
}
.chips li {
  display: inline-flex; align-items: center; gap: 0.45rem; padding: 0.28rem 0.7rem;
  border: 1px solid var(--edge-2); border-radius: 999px;
  background: color-mix(in oklab, var(--surface-1) 78%, transparent);
  font-family: var(--mono); font-size: 0.72rem; color: var(--fg-2);
}
.chips li::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--accent-hi); }
/* Two chips a row on a phone rather than four rows, which is what keeps the
   window's top edge near the first screen. */
@media (width < 720px) {
  .chips { gap: 0.35rem; margin-bottom: 1.2rem; }
  .chips li { padding: 0.22rem 0.55rem; font-size: 0.64rem; }
  .chip-x { display: none; }
}

/* Sized so the two phrase spans break as "Mission control / for agents." rather
   than orphaning a word. text-wrap: balance is already on h1. */
.hero h1 { max-width: 19ch; }
.lede {
  margin-top: 1.1rem; max-width: 56ch; color: var(--fg-2);
  font-size: clamp(1.02rem, 2.3vw, 1.18rem);
}
/* The hook carries the weight of a subtitle without being a second heading:
   full-strength foreground against the lede's --fg-2, same size. */
.lede b { color: var(--fg); font-weight: 560; }

/* --- install ---------------------------------------------------------------*/

.cta { margin-top: 1.7rem; display: flex; flex-wrap: wrap; gap: 0.9rem; align-items: center; }
/* The download badge, Apple's template: the black plate, the OS logo, two lines.
   badge.js turns the macOS badge into the Linux one when the browser says Linux. */
.badge {
  display: inline-flex; align-items: center; gap: 0.65rem;
  min-height: 3rem; padding: 0 1.05rem 0 0.85rem; border-radius: 7px;
  background: #000; color: #fff; border: 1px solid #a6a6a6;
  text-decoration: none; text-align: left; line-height: 1.1;
  transition: border-color 0.16s, transform 0.32s var(--spring);
}
.badge:hover { color: #fff; border-color: #fff; transform: translateY(-1px); }
.badge:active { transform: scale(0.97); }
.badge svg { flex: none; width: 26px; height: 26px; fill: currentColor; }
.badge-text { display: grid; gap: 0.1rem; }
.badge small { font-size: 0.68rem; letter-spacing: 0.01em; }
.badge b { font-size: 1.2rem; font-weight: 600; letter-spacing: -0.01em; white-space: nowrap; }
/* The other build, one quiet line under the badge. */
.badge-alt { margin-top: 0.8rem; font-size: 0.86rem; color: var(--fg-3); }
.badge-alt a { color: var(--fg-2); }
.badge-alt a:hover { color: var(--fg); }

/* The terminal line, folded behind a native <details> so it works with no script. */
.install-more { margin-top: 0.9rem; max-width: 40rem; }
.install-more summary {
  display: inline-flex; align-items: center; gap: 0.5rem; list-style: none;
  font-size: 0.86rem; color: var(--fg-2); cursor: pointer;
}
.install-more summary::-webkit-details-marker { display: none; }
.install-more summary::before {
  content: ""; width: 0.4rem; height: 0.4rem; margin-left: 0.1rem;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg); transition: transform 0.2s;
}
.install-more[open] summary::before { transform: rotate(45deg); }
.install-more summary:hover { color: var(--fg); }
.install-more .install { margin-top: 0.75rem; }
.install-more .install-note { margin-top: 0.6rem; }

.install {
  display: flex; align-items: stretch; gap: 0.5rem; min-width: 0;
  padding: 0.35rem 0.35rem 0.35rem 0.85rem; background: var(--surface-1);
  border: 1px solid var(--edge-2); border-radius: var(--r);
}
.install code {
  flex: 1; align-self: center; min-width: 0; overflow-x: auto; white-space: nowrap;
  font-size: 0.8rem; color: var(--fg-2); scrollbar-width: none;
}
.install code b { color: var(--fg); font-weight: 400; }
.btn {
  flex: none; padding: 0.5rem 0.95rem; border: 0; border-radius: var(--r-sm);
  background: var(--ink);
  color: oklch(0.17 0.01 285);
  font: 560 0.83rem var(--sans);
  cursor: pointer;
  transition: background 0.16s, transform 0.32s var(--spring);
}
.btn:hover { background: var(--ink-hover); }
.btn:active { transform: scale(0.96); }
.btn[data-copied] { background: var(--done); color: oklch(0.16 0.02 160); }

/* Watching the run is the thing that converts, so it is a button of the same
   height as the install row, not an underlined note under it. */
.btn-ghost {
  display: inline-flex; align-items: center; gap: 0.55rem; flex: none;
  padding: 0.6rem 1.05rem; border: 1px solid var(--edge-3); border-radius: var(--r);
  background: color-mix(in oklab, var(--surface-1) 72%, transparent);
  color: var(--fg); font: 560 0.86rem var(--sans); text-decoration: none; cursor: pointer;
  transition: background 0.16s, border-color 0.16s, transform 0.32s var(--spring);
}
.btn-ghost svg { color: var(--accent-hi); }
.btn-ghost span { font: 400 0.72rem var(--mono); color: var(--fg-3); }
.btn-ghost:hover { background: var(--surface-2); border-color: var(--accent-hi); }
.btn-ghost:active { transform: scale(0.97); }
.install-note { margin-top: 0.9rem; max-width: 62ch; font-size: 0.86rem; color: var(--fg-3); }

/* --- the demo, framed ------------------------------------------------------*/

.demo { width: var(--shell); margin: clamp(1.8rem, 4vw, 2.5rem) auto 0; }
.window {
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface-1);
  border: 1px solid var(--edge-2);
  box-shadow: 0 40px 90px -50px var(--accent-glow), 0 2px 30px -12px oklch(0 0 0 / 0.7);
}
.titlebar {
  display: flex; align-items: center; gap: 0.55rem; padding: 0.55rem 0.85rem;
  border-bottom: 1px solid var(--edge); background: var(--surface-2);
}
.dot { width: 10px; height: 10px; border-radius: 50%; background: var(--edge-3); }
.titlebar span { font-family: var(--mono); font-size: 0.72rem; color: var(--fg-3); }

.stage { position: relative; aspect-ratio: 1152 / 720; background: oklch(0.1 0.01 285); }
/* Descendant, not child: the poster is inside a <picture>. */
.stage img,
.stage video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* The poster is a real <img> so it can be the LCP element with fetchpriority=high.
   The video layers over it and never replaces it, so there is no flash and no CLS. */
.stage video { opacity: 0; transition: opacity 0.5s ease; }
.stage[data-playing] video { opacity: 1; }
.stage[data-wrapping] video { opacity: 0; transition: opacity 0.28s linear; }
.stage[data-full] video { object-fit: contain; opacity: 1; }
.stage[data-full] img { opacity: 0; }

.playbtn {
  position: absolute; inset: 0; display: grid; place-items: center; width: 100%;
  border: 0; background: transparent; color: var(--fg); cursor: pointer;
}
.playbtn span {
  display: grid; place-items: center; width: 84px; height: 84px;
  padding-left: 5px;  /* optical centring: the triangle's mass sits left of centre */
  border-radius: 50%; border: 1px solid var(--edge-3);
  background: color-mix(in oklab, var(--surface-0) 72%, transparent);
  backdrop-filter: blur(10px);
  transition: transform 0.36s var(--spring), background 0.2s;
}
.playbtn:hover span { transform: scale(1.07); background: color-mix(in oklab, var(--surface-0) 88%, transparent); }
.playbtn:active span { transform: scale(0.97); }
.stage[data-full] .playbtn { display: none; }
figcaption { margin-top: 0.85rem; font-size: 0.86rem; color: var(--fg-3); max-width: 76ch; }

/* The chapter strip: five moments in the demo, each a real button that seeks the
   full video. The active one follows playback. */
.chapters { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.9rem; }
.chapters button {
  display: inline-flex; align-items: baseline; gap: 0.45rem; padding: 0.38rem 0.75rem;
  border: 1px solid var(--edge-2); border-radius: 999px; background: var(--surface-1);
  color: var(--fg-2); font: 500 0.78rem var(--sans); cursor: pointer;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.chapters b { font: 500 0.64rem var(--mono); letter-spacing: 0.04em; color: var(--fg-3); }
.chapters button:hover { color: var(--fg); border-color: var(--edge-3); }
.chapters button[aria-current] {
  color: var(--fg); border-color: var(--accent-hi);
  background: color-mix(in oklab, var(--accent) 16%, var(--surface-1));
}
.chapters button[aria-current] b { color: var(--accent-hi); }
/* --- motion ----------------------------------------------------------------
   Everything above renders complete without a single line below this point. */

@media (prefers-reduced-motion: no-preference) {
  /* Phrase-level blur-in. The animated copy is aria-hidden; a visually-hidden
     copy carries the real text, so assistive tech never sees the split. */
  .in span {
    display: inline-block;
    animation: rise 0.85s var(--enter) backwards;
  }
  .in span:nth-child(2) { animation-delay: 0.08s; }
  .in span:nth-child(3) { animation-delay: 0.16s; }
  .lede.in { animation: rise 0.85s var(--enter) 0.22s backwards; }
  .cta { animation: rise 0.85s var(--enter) 0.32s backwards; }
  .demo { animation: rise 1s var(--enter) 0.4s backwards; }

  @keyframes rise {
    from { opacity: 0; filter: blur(10px); transform: translateY(18%); }
    to { opacity: 1; filter: blur(0); transform: none; }
  }
}

