/* jqode.com company site — page styles.
   Built on the jQode design tokens (styles/tokens.css). The rules this page is held to:

   - warm neutral monochrome, one Ember accent moment per section, sentence case, mono eyebrows
   - flat tonal bands only: white → gray-50 → white → gray-50 → ink. No gradients, no textures,
     no imagery. The only decoration is the mark's own module geometry (the "pixel").
   - first-class dark mode; surfaces get lighter as they raise
   - motion is understated: fades + 8px rise, 200ms ease-out, staggered, and switched off
     entirely under prefers-reduced-motion */

:root {
  --header-h: 64px;
  --header-bg: oklch(0.99 0.003 75 / 0.8);
  /* Ink sections (contact + footer): explicit tokens so dark mode can raise instead of blend. */
  --ink-bg: var(--gray-950);
  --ink-fg: var(--gray-0);
  --ink-fg-2: oklch(0.72 0.008 65);
  --ink-fg-3: oklch(0.52 0.01 58);
  --ink-border: oklch(0.26 0.01 42);
  /* Product mockups: neutrals that stay legible when the theme flips. */
  --mock-chrome: var(--gray-50);
  --mock-bar: var(--gray-200);
  --hover-fill: var(--gray-100);
}

[data-theme="dark"] {
  --header-bg: oklch(0.17 0.01 40 / 0.8);
  --ink-bg: var(--bg-surface);
  --ink-fg: var(--text-primary);
  --ink-fg-2: var(--text-secondary);
  --ink-fg-3: var(--text-muted);
  --ink-border: var(--border-default);
  --mock-chrome: var(--bg-sunken);
  --mock-bar: var(--border-strong);
  --hover-fill: var(--bg-raised);
}

html { scroll-behavior: smooth; }
body { overflow-x: hidden; }

/* ---------- primitives ---------- */

.container {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 var(--space-6);
}

.eyebrow {
  font: var(--type-eyebrow);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-secondary);
  margin: 0;
}

.mono-meta {
  font: var(--type-data);
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

/* The logo's offset accent pixel — the one decorative element. One per composition. */
.pixel {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 2px;
  background: var(--accent);
  flex: none;
}

h1, h2, h3 { margin: 0; color: var(--text-primary); }

.section-head { max-width: 660px; }
.section-head h2 {
  font: var(--type-display-2);
  font-size: clamp(28px, 3.6vw, 44px);
  line-height: 1.06;
  letter-spacing: var(--tracking-display-2);
  margin-top: var(--space-4);
}
.section-head p {
  font: var(--type-body-lg);
  color: var(--text-secondary);
  margin: var(--space-5) 0 0;
}

.band {
  background: var(--bg-sunken);
  border-top: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
}

section > .container { padding-top: var(--space-24); padding-bottom: var(--space-24); }

/* ---------- buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: var(--control-h-lg);
  padding: 0 var(--space-5);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font: var(--type-label);
  font-size: 14px;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.btn svg { width: 16px; height: 16px; }

.btn-primary { background: var(--accent); color: var(--text-on-accent); }
.btn-primary:hover { background: var(--accent-hover); }
.btn-primary:active { background: var(--accent-active); }

.btn-secondary {
  background: var(--bg-surface);
  color: var(--text-primary);
  border-color: var(--border-default);
}
.btn-secondary:hover { background: var(--hover-fill); border-color: var(--border-strong); }

.btn-sm { height: var(--control-h-sm); padding: 0 var(--space-3); font-size: 13px; }

/* ---------- header ---------- */

.header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--header-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border-subtle);
}
.header > .container {
  height: var(--header-h);
  display: flex;
  align-items: center;
  gap: var(--space-8);
}

.wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-1);
  text-decoration: none;
  color: var(--text-primary);
  font: 600 18px/1 var(--font-sans);
  letter-spacing: -0.02em;
}
.wordmark:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-xs); }

.nav { display: flex; gap: var(--space-1); flex: 1; }
.nav a {
  font: 500 13.5px/1 var(--font-sans);
  color: var(--text-secondary);
  text-decoration: none;
  padding: 9px var(--space-3);
  border-radius: var(--radius-sm);
  transition: background var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.nav a:hover { color: var(--text-primary); background: var(--hover-fill); }
.nav a:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.header-actions { display: flex; align-items: center; gap: var(--space-3); }

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--control-h-sm);
  height: var(--control-h-sm);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.icon-btn:hover { background: var(--hover-fill); color: var(--text-primary); }
.icon-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.icon-btn svg { width: 16px; height: 16px; }
.icon-btn .icon-moon { display: none; }
[data-theme="dark"] .icon-btn .icon-sun { display: none; }
[data-theme="dark"] .icon-btn .icon-moon { display: block; }

.skip-link {
  position: absolute;
  left: -9999px;
  top: var(--space-2);
  padding: var(--space-2) var(--space-4);
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  font: var(--type-label);
  color: var(--text-primary);
  z-index: 100;
}
.skip-link:focus { left: var(--space-4); }

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

.hero > .container { padding-top: var(--space-24); padding-bottom: var(--space-24); }

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr);
  gap: var(--space-12);
  align-items: center;
}

.hero h1 {
  font: var(--type-display-1);
  font-size: clamp(34px, 4.4vw, 52px);
  line-height: 1.03;
  letter-spacing: var(--tracking-display-1);
  margin-top: var(--space-5);
  text-wrap: balance;
}
.hero .lede {
  font: var(--type-body-lg);
  color: var(--text-secondary);
  max-width: 480px;
  margin: var(--space-5) 0 0;
}
.hero-actions {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-top: var(--space-8);
}

/* The signature visual — "two surfaces, one system": the operations screen a manager reads, with
   the phone the person doing the work carries layered over its lower-left corner. Both are built
   from the design tokens, so they flip with the theme; the offset and the quiet shadow do the
   depth, not a gradient or a device photo.

   Accent discipline: the primary CTA is the hero's Ember moment; inside the visual there is
   exactly one more — the phone's active tab module (the pixel motif as an active-state dot). */
.hero-visual { justify-self: end; width: 100%; max-width: 520px; }

/* The phone hangs off the surface's lower-left corner: far enough down that it crosses the
   invoice rows rather than the chart, so nothing important reads as cut in half. */
.stack {
  position: relative;
  padding: 0 0 76px 56px;
}

.surface {
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  overflow: hidden;
}

/* the web surface */

.surface-web {
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}
.surface-rail {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: 10px var(--space-4);
  background: var(--mock-chrome);
  border-bottom: 1px solid var(--border-subtle);
}
.surface-rail .eyebrow { font-size: 10.5px; }
.surface-body {
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.wstats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); }
.wstat {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.wstat-l { font: 500 10.5px/1.2 var(--font-sans); color: var(--text-secondary); }
.wstat-v { font: 600 19px/1.1 var(--font-mono); letter-spacing: -0.015em; color: var(--text-primary); }
.wstat-d { font: var(--type-data); font-size: 10px; color: var(--text-muted); }
.wstat-d.up { color: var(--status-success); }
[data-theme="dark"] .wstat-d.up { color: oklch(0.78 0.13 150); }

.wpanel {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
}
.wpanel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  font: 500 11.5px/1.3 var(--font-sans);
  color: var(--text-primary);
  padding-bottom: var(--space-3);
}

/* A line, not a bar chart — the showcase further down the page already owns bars. */
.spark { display: block; width: 100%; height: 66px; }
.spark-base { stroke: var(--border-subtle); stroke-width: 1; vector-effect: non-scaling-stroke; }
.spark-line {
  fill: none;
  stroke: var(--text-muted);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  /* drawn once on arrival */
  stroke-dasharray: 340;
  stroke-dashoffset: 340;
  animation: spark-draw 620ms var(--ease-out) 160ms both;
}
@keyframes spark-draw { to { stroke-dashoffset: 0; } }
.spark-dots rect { fill: var(--border-strong); }
.spark-dots rect:last-child { fill: var(--text-secondary); }
.wpanel-axis { display: flex; margin-top: 6px; }
.wpanel-axis span {
  flex: 1;
  text-align: center;
  font: 400 9px/1 var(--font-mono);
  color: var(--text-muted);
}

.wtable { border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); }
.wrow {
  display: grid;
  grid-template-columns: 68px minmax(0, 1fr) auto 62px;
  gap: var(--space-3);
  align-items: center;
  padding: 8px var(--space-3);
  font: 400 11.5px/1.3 var(--font-sans);
  color: var(--text-secondary);
}
.wrow + .wrow { border-top: 1px solid var(--border-subtle); }
.wrow .mono { font: var(--type-data); font-size: 10.5px; color: var(--text-secondary); }
.wrow .wnum { color: var(--text-primary); text-align: right; }
.wrow > span:nth-child(2) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wrow .chip { font-size: 9.5px; }

/* the phone surface, layered over the lower-left corner */

.surface-phone {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 158px;
  z-index: 1;
  border-radius: var(--radius-lg);
  /* A page-coloured knockout ring reads as a gap between the two surfaces — depth without a
     glow, and it keeps working when the theme flips. */
  box-shadow: 0 0 0 5px var(--bg-page), var(--shadow-lg);
  display: flex;
  flex-direction: column;
}
[data-theme="dark"] .surface-phone { background: var(--bg-raised); }

.phone-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 7px var(--space-3) 3px;
}
.phone-status .mono-meta { font-size: 9.5px; color: var(--text-secondary); }
.phone-sig { display: inline-flex; align-items: flex-end; gap: 2px; }
.phone-sig i { width: 3px; background: var(--border-strong); border-radius: 1px; }
.phone-sig i:nth-child(1) { height: 4px; }
.phone-sig i:nth-child(2) { height: 6px; }
.phone-sig i:nth-child(3) { height: 8px; }

.phone-body {
  flex: 1;
  padding: var(--space-2) var(--space-3) var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.phone-title {
  font: 600 13px/1.2 var(--font-sans);
  letter-spacing: -0.01em;
  color: var(--text-primary);
  padding-bottom: 2px;
}
.phone-card {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
[data-theme="dark"] .phone-card { background: var(--bg-surface); }
.phone-card-l { font: 500 9.5px/1.2 var(--font-sans); color: var(--text-secondary); }
.phone-card-v { font: 600 16px/1.1 var(--font-mono); letter-spacing: -0.015em; color: var(--text-primary); }
.phone-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  padding: 7px 0;
  border-top: 1px solid var(--border-subtle);
}
.phone-row-t {
  font: 400 10.5px/1.3 var(--font-sans);
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.phone-row .mono-meta { font-size: 9.5px; flex: none; }

.phone-tabs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--border-subtle);
  background: var(--mock-chrome);
}
.phone-tab {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 8px 0 9px;
  font: 500 9px/1 var(--font-sans);
  color: var(--text-muted);
}
.phone-tab .dot { width: 5px; height: 5px; border-radius: 2px; background: var(--border-strong); }
.phone-tab.is-active { color: var(--text-primary); }
/* The one Ember moment inside the visual. */
.phone-tab.is-active .dot { background: var(--accent); }

/* motion: the screen settles, then the phone arrives over it */

.js .surface-web { animation: surface-in var(--duration-base) var(--ease-out) both; }
.js .surface-phone { animation: phone-in var(--duration-slow) var(--ease-out) 180ms both; }
@keyframes surface-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
@keyframes phone-in {
  from { opacity: 0; transform: translate(8px, 8px); }
  to { opacity: 1; transform: none; }
}

/* ---------- capability rail ---------- */

.rail {
  border-top: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-page);
}
.rail > .container {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  padding-top: var(--space-5);
  padding-bottom: var(--space-5);
}
.rail span {
  display: inline-flex;
  align-items: center;
  font: var(--type-eyebrow);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
}
.rail span + span::before {
  content: "";
  width: 3px;
  height: 3px;
  border-radius: 1px;
  background: var(--border-strong);
  margin: 0 clamp(14px, 4vw, 44px);
  flex: none;
}

/* Six items only hold one line down to about 790px. Below that the flex row wrapped ragged —
   5 + 1 around 700px, 3 + 3 at 390px — and every wrapped line opened with an orphaned separator,
   because the dot belongs to the span, not to the line. So the rail becomes a deliberate 3 x 2
   block instead, and the dots go: a separator only reads as one on a single line.
   The column gap reproduces the desktop rhythm exactly — two separator margins plus the dot —
   so the words keep their spacing and only the line breaks. Above 860px nothing changes. */
@media (max-width: 860px) {
  .rail > .container {
    display: grid;
    grid-template-columns: repeat(3, auto);
    justify-content: center;
    justify-items: center;
    column-gap: calc(2 * clamp(14px, 4vw, 44px) + 3px);
    row-gap: var(--space-4);
  }
  .rail span + span::before { display: none; }
}

/* ---------- what the AI does ---------- */
/* Four themes, each carried by proof rows attributed to the product it runs in. Same card
   treatment as the product grid so the page still reads as one system, in two columns rather
   than three because the proof rows need the measure. The section's one Ember moment is the
   module node on the agent-access card — the same module used as a step marker in "how we work". */

.ai-grid {
  margin-top: var(--space-12);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-5);
}

.ai-card {
  display: flex;
  flex-direction: column;
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  box-shadow: var(--shadow-card);
  transition: border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}
.ai-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); }

.ai-head { display: flex; align-items: center; gap: var(--space-3); }
.ai-node {
  width: 7px;
  height: 7px;
  border-radius: 2px;
  background: var(--text-muted);
  flex: none;
}
/* Agent access is the theme that is actually ours, so it carries the section's Ember. */
.ai-card-agents .ai-node { background: var(--accent); }
.ai-num {
  font: var(--type-data);
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}
.ai-card h3 {
  font: var(--type-title-2);
  letter-spacing: var(--tracking-title-2);
  margin: var(--space-4) 0 0;
}
.ai-card > p {
  font: var(--type-body);
  color: var(--text-secondary);
  margin: var(--space-3) 0 0;
}

/* A proof row: the product on the left in mono, the thing it actually does on the right. */
.ai-proof {
  display: grid;
  grid-template-columns: 104px minmax(0, 1fr);
  gap: var(--space-4);
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: 1px solid var(--border-subtle);
}
.ai-proof-tag {
  font: var(--type-eyebrow);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
  padding-top: 3px;
}
.ai-proof p {
  font: var(--type-body-sm);
  color: var(--text-secondary);
  margin: 0;
}

/* ---------- what we do: six separate capability cards ---------- */
/* Same gap and card treatment as the product grid below, so the two card sections read as one
   system. This replaced a hairline bento (gap: 1px over a --border-default field, one outer
   border, overflow: hidden), which fused the six cards into a single slab. */

.bento {
  margin-top: var(--space-12);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-5);
}
.cell {
  position: relative;
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  box-shadow: var(--shadow-card);
  transition: background var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}
/* Background one step, and the lift this system uses for a freestanding card (see .product-card):
   a stronger edge plus --shadow-md. Not a translate — the reveal animation's `both` fill mode
   pins transform on these children, so a hover translate would never apply. */
.cell:hover {
  background: var(--hover-fill);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-md);
}
.cell-num {
  position: absolute;
  top: var(--space-5);
  right: var(--space-5);
  font: var(--type-data);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}
.cell h3 {
  font: var(--type-title-3);
  letter-spacing: var(--tracking-title-3);
  margin-top: var(--space-5);
}
.cell p {
  font: var(--type-body);
  color: var(--text-secondary);
  margin: var(--space-2) 0 0;
  max-width: 34ch;
}
.cell-icon {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-default);
  background: var(--bg-sunken);
  color: var(--text-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color var(--duration-fast) var(--ease-out);
}
.cell:hover .cell-icon { border-color: var(--border-strong); }
.cell-icon svg { width: 19px; height: 19px; }

/* ---------- product mockups ---------- */
/* Built from the design tokens, not screenshots, so they flip with the theme. Sample data. */

.showcase {
  margin-top: var(--space-12);
  display: grid;
  grid-template-columns: 1.45fr 1fr;
  gap: var(--space-5);
  align-items: stretch;
}
.showcase-side { display: grid; grid-template-rows: auto 1fr; gap: var(--space-5); }

.mock {
  margin: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
  overflow: hidden;
  transition: box-shadow var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out);
}
.mock:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); }

.mock-rail {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: var(--mock-chrome);
  border-bottom: 1px solid var(--border-subtle);
}
.mock-rail .eyebrow { font-size: 10.5px; }
.mock-body {
  flex: 1;
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.mstats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2); }
.mstat {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.mstat-label { font: 500 10.5px/1.2 var(--font-sans); color: var(--text-secondary); }
.mstat-value { font: 600 16px/1.2 var(--font-mono); color: var(--text-primary); letter-spacing: -0.01em; }
.mstat-delta { font: var(--type-data); font-size: 10px; color: var(--text-muted); }
.mstat-delta.up { color: var(--status-success); }

.mpanel {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
}
.mpanel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  font: 500 11.5px/1.3 var(--font-sans);
  color: var(--text-primary);
  padding-bottom: var(--space-3);
}

.bars { display: flex; align-items: flex-end; gap: 5px; height: 92px; }
.bars span {
  flex: 1;
  height: var(--h);
  background: var(--mock-bar);
  border-radius: 2px 2px 0 0;
}
/* The one Ember data accent: the current month. */
.bars span.is-current { background: var(--accent); }
.bar-labels { display: flex; gap: 4px; margin-top: 6px; }
.bar-labels span {
  flex: 1;
  text-align: center;
  font: 400 9px/1 var(--font-mono);
  color: var(--text-muted);
}

.mtable .mpanel-head { border-bottom: 1px solid var(--border-subtle); }
.mrow {
  display: grid;
  grid-template-columns: 72px 1fr auto 60px;
  gap: var(--space-3);
  align-items: center;
  padding: 8px 0;
  font: 400 11.5px/1.3 var(--font-sans);
  color: var(--text-secondary);
}
.mrow + .mrow { border-top: 1px solid var(--border-subtle); }
.mrow .mono { font: var(--type-data); font-size: 11px; color: var(--text-secondary); }
.mrow .num { color: var(--text-primary); text-align: right; }

.chip {
  justify-self: end;
  font: var(--type-data);
  font-size: 10px;
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
.chip.ok { background: var(--status-success-soft); color: var(--status-success); }
.chip.warn { background: var(--status-warning-soft); color: var(--status-warning); }
.chip.late { background: var(--status-danger-soft); color: var(--status-danger); }
[data-theme="dark"] .chip.ok { color: oklch(0.78 0.13 150); }
[data-theme="dark"] .chip.warn { color: oklch(0.82 0.13 80); }
[data-theme="dark"] .chip.late { color: oklch(0.76 0.15 25); }

/* invoice */
.inv-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); }
.inv-head > div { display: flex; flex-direction: column; gap: 3px; }
.inv-to { font: 600 13px/1.2 var(--font-sans); color: var(--text-primary); letter-spacing: -0.005em; }
.inv-lines { display: flex; flex-direction: column; }
.inv-line {
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  padding: 7px 0;
  border-top: 1px solid var(--border-subtle);
  font: 400 11.5px/1.3 var(--font-sans);
  color: var(--text-secondary);
}
.inv-line .num { font: var(--type-data); font-size: 11px; color: var(--text-primary); }
.inv-total {
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border-default);
  font: 600 12.5px/1.2 var(--font-sans);
  color: var(--text-primary);
}
.inv-total .num { font: 600 13px/1.2 var(--font-mono); }

/* digital card */
.mock-card .mock-body { justify-content: center; }
.vcard {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  background: var(--ink-bg);
  border: 1px solid var(--ink-border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  color: var(--ink-fg);
}
/* In dark mode the nested card raises instead of going darker than its container. */
[data-theme="dark"] .vcard { background: var(--bg-raised); }
.vcard-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}
.vcard-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--ink-border);
}
.vcard-cta {
  font: var(--type-label);
  font-size: 11px;
  color: var(--ink-fg);
  border: 1px solid var(--ink-border);
  border-radius: var(--radius-xs);
  padding: 4px var(--space-3);
}
.vcard-id { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.vcard-id > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.vcard-mark { width: 34px; height: 34px; flex: none; fill: var(--ink-fg); }
.vcard-mark-tail { fill: var(--accent); }
.vcard-name { font: 600 13px/1.2 var(--font-sans); letter-spacing: -0.005em; }
.vcard-role { font: 400 11px/1.3 var(--font-sans); color: var(--ink-fg-2); }
.vcard .mono-meta { color: var(--ink-fg-3); }
.qr { width: 52px; height: 52px; flex: none; color: var(--ink-fg); fill: var(--ink-fg); }

/* ---------- product cards ---------- */

/* Six tracks, two per card. While a row is full this is arithmetically identical to three equal
   columns — same card width, same gap — but the finer track lets an odd trailing row centre
   instead of hanging left. With five products the grid reads 3 + 2, the last two centred under
   the first three. Cards stay separate: own border, own radius, own surface, gap unchanged. */
.grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: var(--space-5);
  margin-top: var(--space-10);
}
.grid > .card { grid-column: span 2; }
/* Only matches when the grid holds exactly five cards — the 4th is then also the 2nd from last.
   Add a sixth product and the row fills naturally, with no rule to remember to remove. */
.grid > .card:nth-child(4):nth-last-child(2) { grid-column: 2 / span 2; }

.card {
  position: relative;
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition: background var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}
.card p {
  font: var(--type-body);
  color: var(--text-secondary);
  margin: var(--space-2) 0 0;
}

/* Tag first, then title: keeps every card's title and body on the same baseline
   even when a title wraps to two lines. */
.product-card { display: flex; flex-direction: column; align-items: flex-start; }
.product-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--duration-base) var(--ease-out);
}
.product-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); }
.product-card:hover::before { transform: scaleX(1); }
.product-card .tag {
  padding: 3px var(--space-2);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-xs);
  background: var(--bg-sunken);
  font: var(--type-code);
  font-size: 12px;
  color: var(--text-secondary);
}
[data-theme="dark"] .product-card .tag { background: var(--bg-raised); }
.product-card h3 {
  font: var(--type-title-2);
  letter-spacing: var(--tracking-title-2);
  margin: var(--space-4) 0 0;
}
.product-card p { margin-top: var(--space-3); }

/* Apple's official App Store badge — the one place this page links off-site. Apple's marketing
   guidelines require the artwork unmodified and self-hosted, so both colourways are vendored
   into assets/ and served from this domain; nothing is recoloured or filtered here.
   The black badge would vanish against the dark theme's --bg-surface, so the dark theme swaps
   in Apple's own white colourway rather than inverting the black one (inverting would be a
   modification, and the guidelines forbid it). Native 119.66x40 artwork, drawn at 120x40.
   `.card-ai`'s `margin-top: auto` still pins the AI annotation to the bottom of the row, so
   the card carrying this badge stays aligned with the ones that don't. */
.badge-link {
  display: block;
  width: 120px;
  height: 40px;
  margin-top: var(--space-4);
  background: url("/assets/app-store-badge-black.a26fc5b3.svg") no-repeat left center;
  background-size: contain;
  border-radius: var(--radius-xs);
}
[data-theme="dark"] .badge-link { background-image: url("/assets/app-store-badge-white.056de2f8.svg"); }
.badge-link:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* Hidden from sight, not from screen readers — and, deliberately, not from a visitor whose
   stylesheet failed to load: without this rule the label renders as plain text, so the badge
   link never degrades into an empty anchor. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The AI line, on the products that have one. Ruled off and set smaller so it reads as an
   annotation on the product rather than part of its description; `margin-top: auto` lines the
   annotations up along the bottom of a row. Neutral, not Ember — this section's accent is
   already spent on the current-month bar in the chart above. */
.card-ai {
  align-self: stretch;
  margin-top: auto;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-3);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
}
.card-ai-label {
  font: var(--type-eyebrow);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
  padding-top: 3px;
}
.card-ai p {
  font: var(--type-body-sm);
  color: var(--text-secondary);
  margin: 0;
}

/* ---------- how we work: a segmented rail with module nodes ---------- */

.steps {
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-6);
  margin: var(--space-16) 0 0;
}
.step {
  position: relative;
  border-top: 1px solid var(--border-strong);
  padding-top: var(--space-6);
}
.step .node {
  position: absolute;
  top: -4px;
  left: 0;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  background: var(--text-muted);
}
/* The ongoing step carries this section's Ember moment. */
.step-ongoing .node { background: var(--accent); }
.step .num {
  font: var(--type-data);
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}
.step h3 {
  font: var(--type-title-3);
  letter-spacing: var(--tracking-title-3);
  margin: var(--space-3) 0 0;
}
.step p { font: var(--type-body); color: var(--text-secondary); margin: var(--space-2) 0 0; }

/* ---------- contact (ink) ---------- */

.ink { background: var(--ink-bg); color: var(--ink-fg); }
[data-theme="dark"] .ink { border-top: 1px solid var(--ink-border); }

.contact { position: relative; overflow: hidden; }
/* The mark as a quiet watermark — the only "art" on the page, at 5% and bleeding off the edge. */
.contact .watermark {
  position: absolute;
  right: -40px;
  top: 50%;
  transform: translateY(-50%);
  width: 380px;
  height: 380px;
  fill: var(--ink-fg);
  opacity: 0.05;
  pointer-events: none;
}
.contact > .container {
  position: relative;
  z-index: 1;
  padding-top: var(--space-24);
  padding-bottom: var(--space-24);
  text-align: center;
}
.contact .eyebrow { color: var(--ink-fg-3); }
.contact h2 {
  font: var(--type-display-2);
  font-size: clamp(28px, 3.8vw, 46px);
  line-height: 1.05;
  letter-spacing: var(--tracking-display-2);
  color: var(--ink-fg);
  margin: var(--space-4) auto 0;
  max-width: 680px;
}
.contact p {
  font: var(--type-body-lg);
  color: var(--ink-fg-2);
  max-width: 520px;
  margin: var(--space-5) auto 0;
}
.contact-actions { margin-top: var(--space-8); display: flex; justify-content: center; }
.contact-actions .btn-primary { font: var(--type-data); font-size: 14px; }

/* ---------- footer ---------- */

.footer { background: var(--ink-bg); color: var(--ink-fg); }
.footer > .container { padding: var(--space-16) var(--space-6) var(--space-10); }
.footer-top {
  display: grid;
  grid-template-columns: 1.6fr repeat(2, 1fr);
  gap: var(--space-8);
}
.footer .wordmark { color: var(--ink-fg); }
.footer-blurb {
  font: var(--type-body-sm);
  color: var(--ink-fg-2);
  margin: var(--space-4) 0 0;
  max-width: 280px;
}
.footer-col .eyebrow { color: var(--ink-fg-3); }
.footer-col ul {
  list-style: none;
  padding: 0;
  margin: var(--space-4) 0 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.footer-col a {
  font: var(--type-body-sm);
  color: var(--ink-fg-2);
  text-decoration: none;
}
.footer-col a:hover { color: var(--ink-fg); text-decoration: underline; }
.footer-col a:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-xs); }

.footer-bottom {
  border-top: 1px solid var(--ink-border);
  margin-top: var(--space-12);
  padding-top: var(--space-6);
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  font: var(--type-body-sm);
  color: var(--ink-fg-3);
}
.footer-bottom .tagline { font: var(--type-code); font-size: 12px; }

/* ---------- scroll reveal ---------- */
/* Only applied when script is running (html.js), so the page is never blank without it.
   Groups marked data-stagger animate their children; JS sets --rd per child. */

.js [data-reveal]:not([data-stagger]) { opacity: 0; }
.js [data-reveal]:not([data-stagger]).is-in {
  animation: rise var(--duration-base) var(--ease-out) both;
}
.js [data-reveal][data-stagger] > * { opacity: 0; }
.js [data-reveal][data-stagger].is-in > * {
  animation: rise var(--duration-base) var(--ease-out) both;
  animation-delay: var(--rd, 0ms);
}
@keyframes rise {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

/* ---------- responsive ---------- */

@media (max-width: 980px) {
  .hero-grid { grid-template-columns: 1fr; gap: var(--space-12); }
  .hero-visual { justify-self: start; max-width: 520px; }
  .hero .lede { max-width: 560px; }
  .ai-grid { grid-template-columns: 1fr; }
  .bento { grid-template-columns: repeat(2, 1fr); }
  /* Two columns, same trick: four tracks, two per card, and the fifth card centres on its own
     row rather than sitting alone on the left. */
  .grid { grid-template-columns: repeat(4, 1fr); }
  .grid > .card,
  .grid > .card:nth-child(4):nth-last-child(2) { grid-column: span 2; }
  .grid > .card:nth-child(5):nth-last-child(1) { grid-column: 2 / span 2; }
  .showcase { grid-template-columns: 1fr; }
  .steps { grid-template-columns: repeat(2, 1fr); gap: var(--space-8) var(--space-6); }
  .footer-top { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 680px) {
  .container { padding: 0 var(--space-5); }
  section > .container { padding-top: var(--space-16); padding-bottom: var(--space-16); }
  .hero > .container { padding-top: var(--space-16); padding-bottom: var(--space-16); }
  .nav { display: none; }
  .bento, .steps { grid-template-columns: 1fr; }
  /* One column: every card takes the full row, including the two the wider grids offset. */
  .grid { grid-template-columns: 1fr; }
  .grid > .card,
  .grid > .card:nth-child(4):nth-last-child(2),
  .grid > .card:nth-child(5):nth-last-child(1) { grid-column: 1 / -1; }
  /* Below this width the mono product label and its proof each need the full measure. */
  .ai-proof { grid-template-columns: 1fr; gap: var(--space-2); margin-top: var(--space-4); padding-top: var(--space-4); }
  .ai-proof-tag { padding-top: 0; }
  /* The hero layering survives at 390px: the surface keeps the full width and drops its ID column
     (the site's own tables do the same here), and the phone shrinks and steps further down —
     overlapping the last row only — so the screen behind it stays readable. */
  .hero-visual { max-width: 100%; justify-self: stretch; }
  .stack { padding: 0 0 158px 34px; }
  /* One agenda row is enough at this size — it keeps the phone short enough that it clips the
     surface's bottom edge instead of cutting through its rows. */
  .phone-row:last-of-type { display: none; }
  .surface-body { padding: var(--space-3); gap: var(--space-2); }
  .wrow { grid-template-columns: minmax(0, 1fr) auto 58px; }
  .wrow > span:nth-child(1) { display: none; }
  .surface-phone { width: 128px; box-shadow: 0 0 0 4px var(--bg-page), var(--shadow-md); }
  .phone-body { padding: var(--space-1) 10px var(--space-2); gap: 6px; }
  .phone-card { padding: 8px; }
  .phone-card-v { font-size: 14px; }
  .phone-tab { font-size: 8.5px; padding: 7px 0 8px; }
  .hero-actions .btn { flex: 1 1 auto; }
  .mrow { grid-template-columns: 66px 1fr 58px; }
  .mrow > span:nth-child(2) { display: none; }
  .bar-labels span:nth-child(even) { visibility: hidden; }
  .contact .watermark { width: 260px; height: 260px; right: -150px; opacity: 0.04; }
  .footer-top { grid-template-columns: 1fr; gap: var(--space-10); }
  .footer-bottom { flex-direction: column; }
}

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation: none !important; transition: none !important; }
  .js [data-reveal], .js [data-reveal] > * { opacity: 1 !important; }
  .spark-line { stroke-dashoffset: 0; }
  .js .surface-web,
  .js .surface-phone { opacity: 1 !important; transform: none !important; }
  .product-card::before { display: none; }
}
