/* Worgen landing — "Operations Room": paper-warm interior on a dark canvas,
   oxblood as the single accent. Tokens mirror the Design System. */

@font-face { font-family: 'Fraunces'; src: url('fonts/Fraunces.woff2') format('woff2-variations'), url('fonts/Fraunces.ttf') format('truetype-variations'); font-weight: 100 900; font-display: swap; }
@font-face { font-family: 'Fraunces'; src: url('fonts/Fraunces-Italic.woff2') format('woff2-variations'), url('fonts/Fraunces-Italic.ttf') format('truetype-variations'); font-weight: 100 900; font-style: italic; font-display: swap; }
@font-face { font-family: 'Plus Jakarta Sans'; src: url('fonts/PlusJakartaSans.woff2') format('woff2-variations'), url('fonts/PlusJakartaSans.ttf') format('truetype-variations'); font-weight: 200 800; font-display: swap; }
@font-face { font-family: 'JetBrains Mono'; src: url('fonts/JetBrainsMono.woff2') format('woff2-variations'), url('fonts/JetBrainsMono.ttf') format('truetype-variations'); font-weight: 100 800; font-display: swap; }

:root {
  --canvas: #0e1411; --surface: #161d19; --surface-2: #1c2520;
  --paper: #faf6ec; --card: #f2ebd9; --card-warm: #ebe1c8;
  --ink: #14181a; --ink-2: #4a463f;
  --bone: #ebe4d6; --bone-dim: #b8b09c; --bone-faint: #6b6555;
  --rule-light: rgba(20,24,26,.08); --rule-dark: rgba(235,228,214,.10);
  --accent: #b54243; --accent-deep: #9d2e2f; --accent-tint: rgba(181,66,67,.12);
  --display: 'Fraunces', Georgia, serif;
  --sans: 'Plus Jakarta Sans', system-ui, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, monospace;
}

* { box-sizing: border-box; margin: 0; }
html { scroll-behavior: smooth; }
body {
  background: var(--canvas); color: var(--bone);
  font-family: var(--sans); line-height: 1.6; font-size: 16.5px;
  letter-spacing: .003em;
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-synthesis: none; /* never fake bold/italic — use the real cuts */
}
/* Fraunces is a variable font whose DEFAULTS are the quirky cut: WONK=1
   (wonky glyph alternates) and opsz=9 (caption optical size). For a composed,
   editorial voice: wonk off, softness off, and let the browser pick the
   high-contrast display optical size from the rendered font size. */
h1, h2, h3, .brand {
  font-optical-sizing: auto;
  font-variation-settings: "SOFT" 0, "WONK" 0;
  line-height: 1.2; /* headings set tighter than the 1.6 body leading */
}
img, video { max-width: 100%; display: block; }
a { color: inherit; }

.wrap { max-width: 1080px; margin: 0 auto; padding: 0 24px; }

/* ---- top nav (dark chrome) ---- */
.nav { display: flex; align-items: center; gap: 28px; padding: 22px 0; }
.nav .brand { font-family: var(--display); font-weight: 600; font-size: 24px; color: var(--bone); text-decoration: none; letter-spacing: .02em; }
.nav .links { display: flex; gap: 22px; margin-left: auto; align-items: center; }
.nav .links a { color: var(--bone-dim); text-decoration: none; font-size: 14px; font-weight: 480; letter-spacing: .006em; }
.nav .links a:hover { color: var(--bone); }
/* `.nav .links a` (0,2,1) outranks `.btn` (0,1,0), so the nav's primary CTA was
   inheriting muted bone-dim on oxblood — 2.54:1, against 5.49:1 for the same
   button in the hero. Restore the button's own colour. */
.nav .links a.btn { color: #fff; }
.nav .links a.btn:hover { color: #fff; }
.btn { display: inline-block; background: var(--accent); color: #fff; text-decoration: none;
  padding: 11px 22px; border-radius: 6px; font-weight: 620; font-size: 15px; letter-spacing: .005em; border: 0; }
.btn:hover { background: var(--accent-deep); }
/* Phones: the single nav row overflows and scrolls the page sideways — wrap
   the links onto their own row instead. */
@media (max-width: 760px) {
  .nav { flex-wrap: wrap; gap: 14px; padding: 18px 0; }
  .nav .links { margin-left: 0; width: 100%; gap: 16px; flex-wrap: wrap; }
  .nav .links a { font-size: 13.5px; }
  .btn { padding: 9px 18px; font-size: 14px; }
}
/* Ghost buttons come in two contexts. The base is for the DARK canvas (hero,
   footer). On the paper interior the same rule rendered bone-on-cream — about
   1.1:1 contrast, i.e. invisible — so the paper variant below is required, not
   cosmetic. Any new ghost button placed inside .paper inherits the fix. */
/* Border alpha is .4 rather than --rule-dark (.10): that token is for decorative
   hairlines, and at .10 the outline measured 1.26:1 — the button read as a bare
   link. .4 measures 3.34:1, matching the paper variant. */
.btn.ghost { background: transparent; border: 1px solid rgba(235,228,214,.4); color: var(--bone); }
.btn.ghost:hover { border-color: var(--bone-dim); background: var(--surface-2); }
.paper .btn.ghost { color: var(--ink); border-color: rgba(20,24,26,.5); }
.paper .btn.ghost:hover { color: var(--ink); border-color: var(--ink); background: rgba(20,24,26,.06); }

/* ---- hero ---- */
.hero { padding: 72px 0 64px; position: relative; overflow: hidden; }
.hero .kicker { font-family: var(--mono); font-size: 11px; font-weight: 500; letter-spacing: .24em; text-transform: uppercase; color: var(--accent); }
.hero h1 { font-family: var(--display); font-weight: 560; font-size: clamp(40px, 6vw, 66px); line-height: 1.04; letter-spacing: -0.015em; margin: 18px 0; text-wrap: balance; }
/* Accent words carry emphasis through colour alone. The design system pairs
   oxblood with Fraunces' italic, but that italic is calligraphic — at the
   landing's 40-66px display sizes it reads as script rather than editorial,
   so the accent stays upright here. */
.hero h1 em { font-style: normal; color: var(--accent); }
/* Light-on-dark text renders optically thinner than dark-on-light at the same
   weight — the hero lead keeps a normal cut so it doesn't look washed out. */
.hero p.lead { max-width: 600px; color: var(--bone-dim); font-size: 18px; line-height: 1.65; text-wrap: pretty; }
.hero .cta { margin-top: 30px; display: flex; gap: 14px; flex-wrap: wrap; }
.hero .sub { margin-top: 14px; font-size: 13px; color: var(--bone-faint); }

/* ---- paper interior ---- */
.paper { background: var(--paper); color: var(--ink); border-radius: 14px 14px 0 0; }
.paper section { padding: 72px 0; border-bottom: 1px dashed var(--rule-light); }
.paper .kicker { font-family: var(--mono); font-size: 11px; font-weight: 500; letter-spacing: .24em; text-transform: uppercase; color: var(--accent); }
.paper h2 { font-family: var(--display); font-weight: 540; font-size: clamp(28px, 4vw, 40px); letter-spacing: -0.012em; line-height: 1.12; margin: 12px 0 10px; text-wrap: balance; }
.paper h2 em { font-style: normal; color: var(--accent); }
.paper p.sub { color: var(--ink-2); max-width: 620px; line-height: 1.65; text-wrap: pretty; }

.grid3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 18px; margin-top: 36px; }
.card { background: var(--card); border-radius: 10px; padding: 26px; }
.card h3 { font-family: var(--display); font-size: 21px; font-weight: 560; letter-spacing: -0.008em; margin-bottom: 8px; }
.card p { color: var(--ink-2); font-size: 15px; line-height: 1.6; }
.card .tag { font-family: var(--mono); font-size: 10px; letter-spacing: .18em; text-transform: uppercase; color: var(--accent); display: block; margin-bottom: 10px; }

/* ---- demo blocks ---- */
.demo { display: grid; grid-template-columns: 1fr 1fr; gap: 44px; align-items: center; margin-top: 48px; }
.demo:nth-of-type(even) .shot { order: -1; }
.demo h3 { font-family: var(--display); font-size: 26px; font-weight: 560; letter-spacing: -0.01em; margin-bottom: 10px; }
.demo p { color: var(--ink-2); }
.demo .num { font-family: var(--mono); color: var(--accent); font-size: 12px; letter-spacing: .18em; }
.shot { border-radius: 10px; overflow: hidden; box-shadow: 0 18px 44px rgba(20,24,26,.18); border: 1px solid var(--rule-light); }
.shot.phone { max-width: 300px; margin: 0 auto; }
@media (max-width: 800px) { .demo { grid-template-columns: 1fr; } .demo:nth-of-type(even) .shot { order: 0; } }

/* ---- steps ---- */
.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; margin-top: 36px; counter-reset: step; }
.step { background: var(--card-warm); border-radius: 10px; padding: 22px; }
.step::before { counter-increment: step; content: counter(step, decimal-leading-zero); font-family: var(--mono); color: var(--accent); font-size: 12px; letter-spacing: .18em; display: block; margin-bottom: 10px; }
.step strong { display: block; margin-bottom: 6px; }
.step span { color: var(--ink-2); font-size: 14px; }

/* ---- closing CTA / footer ---- */
.closing { text-align: center; }
.closing .cta { justify-content: center; display: flex; gap: 14px; margin-top: 26px; flex-wrap: wrap; }
.footer { padding: 44px 0 60px; color: var(--bone-faint); font-size: 13px; }
.footer .cols { display: flex; gap: 40px; flex-wrap: wrap; justify-content: space-between; }
.footer a { color: var(--bone-dim); text-decoration: none; }
.footer a:hover { color: var(--bone); }

/* ---- docs / media pages ---- */
.docpage { padding: 40px 0 90px; }
.docpage h1 { font-family: var(--display); font-weight: 560; font-size: 42px; letter-spacing: -0.014em; margin: 8px 0 6px; text-wrap: balance; }
.docpage h1 em { font-style: normal; color: var(--accent); }
.docpage h2 { font-family: var(--display); font-weight: 560; font-size: 26px; letter-spacing: -0.01em; margin: 44px 0 10px; }
.docpage h3 { font-size: 17px; margin: 26px 0 6px; }
.docpage p, .docpage li { color: var(--ink-2); max-width: 680px; line-height: 1.65; text-wrap: pretty; }
/* The global `* { margin: 0 }` reset means stacked paragraphs collide. Earlier
   pages never had two in a row; the pricing copy does. */
.docpage p + p { margin-top: 14px; }
.docpage ul { padding-left: 22px; }
.docpage li { margin: 6px 0; }
.docpage .kicker { font-family: var(--mono); font-size: 11px; letter-spacing: .22em; text-transform: uppercase; color: var(--accent); }
/* align-items:start so a tall portrait clip doesn't stretch its whole row into
   half-empty cards — each card sizes to its own content. */
.asset-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 20px; margin: 26px 0; align-items: start; }
.asset { background: var(--card); border-radius: 10px; padding: 16px; }
.asset .links { margin-top: 10px; font-size: 13px; }
.asset .links a { color: var(--accent); margin-right: 14px; }
.logo-tile { display: flex; align-items: center; justify-content: center; padding: 30px; border-radius: 8px; }

/* ═══════════════════════════════════════════════════════════════════
   Motion — 2026-08-13. The main page carries the pitch visually now;
   the prose moved to /docs/. All of it degrades to "everything visible,
   nothing moving" under prefers-reduced-motion or a blocked landing.js.
   ═══════════════════════════════════════════════════════════════════ */

/* Only ARM the reveal when landing.js ran (it sets .js on <html>). Without
   this guard a blocked script would leave the page permanently blank. */
.js .reveal { opacity: 0; transform: translateY(16px); }
.js .reveal.in { opacity: 1; transform: none; }
.js .reveal { transition: opacity .75s cubic-bezier(.22,.61,.36,1), transform .75s cubic-bezier(.22,.61,.36,1); }

/* Hero copy animates on load rather than on scroll — it's already in view. */
.hero .kicker, .hero h1, .hero .lead, .hero .cta, .hero .sub { animation: rise .9s cubic-bezier(.22,.61,.36,1) backwards; }
.hero .kicker { animation-delay: .05s }
.hero h1      { animation-delay: .14s }
.hero .lead   { animation-delay: .26s }
.hero .cta    { animation-delay: .36s }
.hero .sub    { animation-delay: .46s }
@keyframes rise { from { opacity: 0; transform: translateY(18px) } to { opacity: 1; transform: none } }

/* ---- hero layout: copy left, constellation right ---- */
.hero-grid { display: grid; grid-template-columns: 1.05fr .95fr; gap: 56px; align-items: center; }
@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; gap: 32px; }
  .constellation { max-width: 380px; margin: 0 auto; }
}

/* ---- the constellation: engineers converging on a site ----
   Nodes pop in, then their lines draw toward the hub. Purely decorative,
   so it's aria-hidden in the markup. */
.constellation { width: 100%; max-width: 460px; height: auto; margin-left: auto; display: block; }
.constellation .link {
  fill: none; stroke: var(--accent); stroke-width: 1.4; stroke-linecap: round;
  stroke-dasharray: 300; stroke-dashoffset: 300;
  animation: draw 1.1s cubic-bezier(.22,.61,.36,1) forwards;
}
.constellation .node { fill: var(--bone-dim); transform-box: fill-box; transform-origin: center;
  animation: pop .55s cubic-bezier(.34,1.56,.64,1) backwards; }
.constellation .hub { fill: var(--accent); transform-box: fill-box; transform-origin: center;
  animation: pop .6s cubic-bezier(.34,1.56,.64,1) backwards; }
.constellation .halo { fill: none; stroke: var(--accent); stroke-width: 1.2; opacity: 0;
  animation: ping 3.6s ease-out 1.2s infinite; }
.constellation .label { fill: var(--bone-faint); font-family: var(--mono); font-size: 9px; letter-spacing: .16em;
  animation: fade 1s ease-out backwards; }
@keyframes draw { to { stroke-dashoffset: 0 } }
@keyframes pop  { from { opacity: 0; transform: scale(.3) } to { opacity: 1; transform: scale(1) } }
@keyframes fade { from { opacity: 0 } to { opacity: 1 } }
@keyframes ping { 0% { r: 16; opacity: .55 } 70% { r: 58; opacity: 0 } 100% { r: 58; opacity: 0 } }

/* ---- compact three-beat strip under the hero ---- */
.beats { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-top: 64px; }
.beat { border-top: 1px solid var(--rule-dark); padding-top: 16px; }
.beat b { font-family: var(--display); font-weight: 560; font-size: 19px; display: block; letter-spacing: -0.008em; }
.beat span { color: var(--bone-faint); font-size: 14px; }

/* ---- clip trio: the product doing the talking ---- */
.clips { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 36px; }
@media (max-width: 820px) { .clips { grid-template-columns: 1fr; } }
.clip { background: var(--card); border-radius: 10px; overflow: hidden; border: 1px solid var(--rule-light);
  transition: transform .35s cubic-bezier(.22,.61,.36,1), box-shadow .35s ease; }
.clip:hover { transform: translateY(-4px); box-shadow: 0 16px 36px rgba(20,24,26,.16); }
.clip video { width: 100%; display: block; background: var(--canvas); }
.clip .cap { padding: 14px 16px 16px; }
.clip .cap b { font-family: var(--display); font-size: 16px; font-weight: 560; display: block; }
.clip .cap span { color: var(--ink-2); font-size: 13.5px; }

/* ---- two-audience split ---- */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 36px; }
@media (max-width: 760px) { .split { grid-template-columns: 1fr; } }
.side { background: var(--card); border-radius: 10px; padding: 30px;
  transition: transform .35s cubic-bezier(.22,.61,.36,1); }
.side:hover { transform: translateY(-4px); }
.side h3 { font-family: var(--display); font-size: 23px; font-weight: 560; letter-spacing: -0.01em; margin-bottom: 8px; }
.side p { color: var(--ink-2); font-size: 15.5px; }
.side a { color: var(--accent); text-decoration: none; font-weight: 560; font-size: 14.5px;
  display: inline-block; margin-top: 14px; }
.side a:hover { text-decoration: underline; }

/* Buttons gain a little lift now that the page is motion-forward. */
.btn { transition: transform .2s ease, background .2s ease; }
.btn:hover { transform: translateY(-1px); }

/* ---- the one switch that turns all of it off ---- */
@media (prefers-reduced-motion: reduce) {
  .js .reveal, .js .reveal.in { opacity: 1; transform: none; transition: none; }
  .hero .kicker, .hero h1, .hero .lead, .hero .cta, .hero .sub,
  .constellation .link, .constellation .node, .constellation .hub,
  .constellation .halo, .constellation .label { animation: none; }
  .constellation .link { stroke-dashoffset: 0; }
  .constellation .halo { opacity: 0; }
  .clip:hover, .side:hover, .btn:hover { transform: none; }
  html { scroll-behavior: auto; }
}

/* ---- constellation: interactive states (2026-08-13) ----
   The hub is draggable. Everything here is additive to the load animation
   above; without landing.js none of these classes are ever applied and the
   diagram stays exactly as it was. */
.constellation .grab {
  fill: none;
  cursor: grab;
  /* Stop the browser treating a drag on the hub as a page scroll/pan on touch.
     Scoped to the grab target only — the rest of the page scrolls normally. */
  touch-action: none;
}
.constellation.dragging .grab { cursor: grabbing; }

/* Hover affordance: the hub swells slightly so it reads as grabbable. */
.constellation .hub { transition: r .18s ease; }
.constellation .grab:hover + .hub,
.constellation.dragging .hub { r: 13; }

/* While live, the paths are owned by JS — kill the draw animation's dasharray,
   which would otherwise clip a redrawn curve that is longer than the original. */
.constellation.live .link {
  animation: none;
  stroke-dasharray: none;
  stroke-dashoffset: 0;
}
/* The halo pulse is distracting once someone is actively dragging. */
.constellation.dragging .halo { animation: none; opacity: 0; }

/* Double-click returns the hub home; ease that one move so it glides back. */
.constellation.settling .hub-group { transition: transform .4s cubic-bezier(.22,.61,.36,1); }
.constellation.settling .link { transition: d .4s cubic-bezier(.22,.61,.36,1); }

/* No "drag me" signage — the drag is an easter egg, found by fiddling. The
   grab cursor is the only tell. The label must not be selectable, or dragging
   across it highlights the text instead of moving the hub. */
.constellation text {
  user-select: none; -webkit-user-select: none;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .constellation .hub,
  .constellation.settling .hub-group,
  .constellation.settling .link { transition: none; }
}
