/* Palmer AI Consulting Group
 *
 * The colours, fonts and circuit-board background are the original site's,
 * rescued from its saved-page export (docs/02_Deployment.md). The layout is
 * the second design pass (docs/04 W15): less text, one animated system
 * diagram, and a short scroll story.
 *
 * Motion rules for this file: transform and opacity only; every loop pauses
 * off screen; nothing runs under prefers-reduced-motion; nothing is hidden
 * unless site.js has run (the `.js` class), so the page reads in full with
 * scripting off.
 */

/* ---------------------------------------------------------------- fonts --
 *
 * Self-hosted. The original declared these two families and shipped neither:
 * its only stylesheet link pointed at a relative path inside the saved-page
 * folder, which was never uploaded and returned 404 in production. Every
 * visitor since launch has seen the fallback sans-serif.
 *
 * Outfit is a variable font, so one file covers the four weights in use
 * (300, 400, 500, 600) and `font-weight: 100 900` lets the browser
 * interpolate. See src/assets/fonts/README.md for licensing.
 */

@font-face {
  font-family: 'Outfit';
  src: url('../fonts/outfit-variable-latin.woff2') format('woff2-variations'),
       url('../fonts/outfit-variable-latin.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Bebas Neue';
  src: url('../fonts/bebas-neue-400-latin.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

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

:root {
  --blue: #00D4E0;
  --blue-dim: rgba(0, 212, 224, 0.15);
  --blue-glow: rgba(0, 212, 224, 0.5);
  --dark: #071428;
  --dark2: #0a1a35;
  --dark3: #0d2040;
  --gray: #c8d0dc;
  --gray-dim: rgba(200, 208, 220, 0.5);
  --white: #e8edf5;

  /* Added in the redesign. `--muted` replaces `--gray-dim` for text: a solid
   * colour at about 8:1 on the page, where 50 percent opacity fell below
   * WCAG AA at small sizes. Amber marks examples, and only examples. */
  --muted: #a3aec0;
  --amber: #ffd76a;

  /* The stack every custom face falls back to. Named once so the fallback is
   * a decision rather than an accident, which is what the original had. */
  --font-fallback: system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;
}

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

html { scroll-behavior: smooth; }

body {
  background-color: #071428;
  background-image:
    linear-gradient(rgba(0, 212, 224, 0.04) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0, 212, 224, 0.04) 1px, transparent 1px),
    radial-gradient(ellipse 80% 60% at 50% 30%, rgba(0, 80, 140, 0.25) 0%, transparent 70%);
  background-size: 60px 60px, 60px 60px, 100% 100%;
  color: var(--gray);
  font-family: 'Outfit', var(--font-fallback);
  font-weight: 300;
  overflow-x: hidden;
}

body::before {
  content: '';
  position: fixed;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cg stroke='rgba(0,212,224,0.07)' stroke-width='1' fill='none'%3E%3Cpath d='M20 20 h80 v40 h60'/%3E%3Ccircle cx='100' cy='20' r='3' fill='rgba(0,212,224,0.15)'/%3E%3Cpath d='M200 60 h60 v-40'/%3E%3Ccircle cx='260' cy='60' r='3' fill='rgba(0,212,224,0.15)'/%3E%3Cpath d='M300 100 v80 h-60'/%3E%3Ccircle cx='300' cy='100' r='3' fill='rgba(0,212,224,0.15)'/%3E%3Cpath d='M80 200 h-60 v60'/%3E%3Ccircle cx='80' cy='200' r='3' fill='rgba(0,212,224,0.15)'/%3E%3Cpath d='M160 300 v-60 h80 v-40'/%3E%3Ccircle cx='160' cy='300' r='3' fill='rgba(0,212,224,0.15)'/%3E%3Cpath d='M320 200 h60 v80'/%3E%3Ccircle cx='320' cy='200' r='3' fill='rgba(0,212,224,0.15)'/%3E%3Cpath d='M40 340 h100 v-60 h40'/%3E%3Ccircle cx='40' cy='340' r='3' fill='rgba(0,212,224,0.15)'/%3E%3Cpath d='M260 320 v60 h-80'/%3E%3Ccircle cx='260' cy='320' r='3' fill='rgba(0,212,224,0.15)'/%3E%3Cpath d='M350 40 v100 h-60 v40'/%3E%3Ccircle cx='350' cy='40' r='3' fill='rgba(0,212,224,0.15)'/%3E%3Cpath d='M120 140 h-60 v80'/%3E%3Ccircle cx='120' cy='140' r='3' fill='rgba(0,212,224,0.15)'/%3E%3C/g%3E%3C/svg%3E");
  background-size: 400px 400px;
  pointer-events: none;
  z-index: 0;
  opacity: 0.8;
}

nav,
main,
footer { position: relative; z-index: 1; }

img { max-width: 100%; }

/* Keyboard focus was invisible in the original: it cleared the outline on form
 * fields and never replaced it anywhere else. `:focus-visible` shows a ring to
 * keyboard users without putting one on every mouse click. */
a:focus-visible,
button:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--blue);
  color: #000;
  padding: 12px 20px;
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
}

.skip-link:focus { left: 12px; top: 12px; }

/* --------------------------------------------------------------- cursor --
 *
 * The original set `cursor: none` on `body` unconditionally and drew its own
 * dot in JavaScript. That leaves a visitor with no pointer at all if the
 * script fails, and it means nothing on a touch screen.
 *
 * Here the effect is opt-in: it applies only where there is a real hovering
 * pointer and the visitor has not asked for reduced motion, and only once the
 * script has confirmed it is running by setting `data-cursor` on the root.
 * Everywhere else the normal system cursor is left alone and the two dots are
 * never rendered. The desktop experience is unchanged.
 */

.cursor,
.cursor-ring { display: none; }

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  html[data-cursor='custom'] body,
  html[data-cursor='custom'] a,
  html[data-cursor='custom'] button { cursor: none; }

  html[data-cursor='custom'] .cursor,
  html[data-cursor='custom'] .cursor-ring { display: block; }
}

.cursor {
  position: fixed;
  width: 8px;
  height: 8px;
  background: var(--blue);
  border-radius: 50%;
  pointer-events: none;
  z-index: 9999;
  transform: translate(-50%, -50%);
  transition: width 0.2s, height 0.2s;
  box-shadow: 0 0 10px var(--blue-glow);
}

.cursor-ring {
  position: fixed;
  width: 32px;
  height: 32px;
  border: 1px solid rgba(74, 158, 255, 0.4);
  border-radius: 50%;
  pointer-events: none;
  z-index: 9998;
  transform: translate(-50%, -50%);
  transition: width 0.2s, height 0.2s, opacity 0.2s;
}

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

nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 20px 60px;
  background: linear-gradient(to bottom, rgba(7, 20, 40, 0.97), transparent);
  backdrop-filter: blur(10px);
}

.nav-logo { display: inline-block; line-height: 0; }
.nav-logo img { height: 52px; width: auto; display: block; }

.nav-links { display: flex; gap: 36px; list-style: none; }

.nav-links a,
.nav-cta {
  color: var(--muted);
  text-decoration: none;
  font-size: 12px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  font-weight: 400;
  transition: color 0.3s;
}

.nav-links a:hover { color: var(--blue); }

/* The CTA is a sibling of the link list, not a member of it. In the original
 * it lived inside `.nav-links`, so the mobile rule that hid the list also hid
 * the only call to action on the page. */
.nav-cta {
  border: 1px solid rgba(74, 158, 255, 0.4);
  color: var(--blue);
  padding: 8px 20px;
  border-radius: 2px;
  white-space: nowrap;
  transition: background 0.3s, box-shadow 0.3s;
}

.nav-cta:hover { background: var(--blue-dim); box-shadow: 0 0 20px var(--blue-glow); }

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

.btn-primary {
  display: inline-block;
  padding: 16px 32px;
  font-family: 'Outfit', var(--font-fallback);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: #000;
  background: var(--blue);
  border: 0;
  border-radius: 2px;
  box-shadow: 0 0 24px rgba(0, 212, 224, 0.35);
  transition: box-shadow 0.3s, transform 0.2s;
}

.btn-primary:hover { box-shadow: 0 0 44px rgba(0, 212, 224, 0.65); transform: translateY(-2px); }
.btn-large { padding: 20px 44px; font-size: 13px; }

/* The secondary action is a link, not a second button competing with the
 * first. Its underline grows from the left on hover (a transform). */
.btn-text {
  position: relative;
  display: inline-block;
  padding: 16px 2px;
  font-size: 15px;
  font-weight: 500;
  color: var(--white);
  text-decoration: none;
}

.btn-text::after {
  content: '';
  position: absolute;
  left: 2px;
  right: 2px;
  bottom: 10px;
  height: 1px;
  background: var(--blue);
  transform: scaleX(0.35);
  transform-origin: left;
  transition: transform 0.3s ease;
}

.btn-text:hover::after,
.btn-text:focus-visible::after { transform: scaleX(1); }

/* -------------------------------------------------------------- section -- */

section { padding: 120px 60px; max-width: 1200px; margin: 0 auto; }

.section-title {
  font-family: 'Bebas Neue', var(--font-fallback);
  font-size: clamp(40px, 5.2vw, 68px);
  font-weight: 400;
  line-height: 0.98;
  letter-spacing: 0.01em;
  color: var(--white);
  max-width: 22ch;
  text-wrap: balance;
}

.section-lede { margin-top: 18px; max-width: 46ch; font-size: 17px; line-height: 1.6; color: var(--muted); }

.fine-print { margin-top: 28px; font-size: 13px; color: var(--muted); }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* Every small inline icon. Strokes only, so one colour rule themes them. */
.step svg,
.channel svg,
.notice-head svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex-shrink: 0;
}

/* ----------------------------------------------------------------- hero --
 *
 * Type-led: the headline is the hero, the diagram shows it. The oversized
 * wordmark image the rescue carried here is gone (53 KB); the nav keeps the
 * logo. */

.hero {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  align-items: center;
  gap: 40px;
  min-height: min(100vh, 780px);
  padding-top: 132px;
  padding-bottom: 40px;
}

.hero-copy { container-type: inline-size; }

/* Sized from the hero column's own width, so the longest word,
 * COMMUNICATIONS, always fits on one line: it is never hyphenated or broken,
 * and never overflows (checked at 360px, 390px, 768px and desktop). The vw
 * value is the fallback where container units are unsupported. */
.hero-title {
  font-family: 'Bebas Neue', var(--font-fallback);
  font-size: clamp(38px, 12vw, 92px);
  font-size: clamp(38px, 15.5cqw, 92px);
  hyphens: none;
  overflow-wrap: normal;
  word-break: normal;
  font-weight: 400;
  line-height: 0.9;
  letter-spacing: 0.005em;
  color: var(--white);
  text-shadow: 0 0 40px rgba(0, 212, 224, 0.18);
  text-wrap: balance;
}

.hero-lede { margin-top: 24px; max-width: 34ch; font-size: 19px; line-height: 1.55; color: var(--muted); }

.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 28px; margin-top: 36px; }

.hero-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 22px;
  margin-top: 40px;
  list-style: none;
  font-size: 14px;
  color: var(--muted);
}

.hero-facts li { display: flex; align-items: center; gap: 8px; }

.hero-facts li::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--blue);
  box-shadow: 0 0 8px var(--blue);
}

/* The one-time entrance: the copy and the diagram arrive together, once. */
.hero-copy,
.flow { animation: fadeUp 0.8s 0.15s both; }
.flow { animation-delay: 0.35s; }

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

.flow { position: relative; margin: 0; }
.flow-svg { display: block; width: 100%; height: auto; overflow: visible; }
.flow-svg--narrow { display: none; }

.traces path { fill: none; stroke: rgba(0, 212, 224, 0.32); stroke-width: 1.5; }
.solder circle { fill: rgba(0, 212, 224, 0.55); }

.node rect { fill: rgba(10, 26, 53, 0.92); stroke: rgba(0, 212, 224, 0.4); stroke-width: 1; }
.node use { fill: none; stroke: var(--blue); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.node text { font-family: 'Outfit', var(--font-fallback); font-size: 15px; font-weight: 500; fill: var(--white); }
.node--out rect { stroke: rgba(0, 212, 224, 0.25); }
.node .node-flash { fill: rgba(0, 212, 224, 0.28); stroke: var(--blue); opacity: 0; }

.core-halo { fill: rgba(0, 212, 224, 0.08); stroke: rgba(0, 212, 224, 0.25); }
.core-ring { fill: none; stroke: rgba(0, 212, 224, 0.55); stroke-width: 1; stroke-dasharray: 3 5; }
.core-body { fill: #0d2040; stroke: var(--blue); stroke-width: 1.5; }
.core-label { font-family: 'Bebas Neue', var(--font-fallback); font-size: 22px; letter-spacing: 0.06em; fill: var(--white); }
.core-label--small { font-size: 18px; }

.pkt circle { fill: var(--blue); }
.pkt .pkt-glow { fill: rgba(0, 212, 224, 0.28); }
.pkt { opacity: 0; }

/* Motion, where it is welcome. Transform and opacity only. */
@media (prefers-reduced-motion: no-preference) {
  .pkt { animation: 6s linear infinite; }
  .pkt-w-in1, .pkt-n-in1 { animation-delay: 0s; }
  .pkt-w-in2, .pkt-n-in2 { animation-delay: 2s; }
  .pkt-w-in3, .pkt-n-in3 { animation-delay: 4s; }
  .pkt-w-in1 { animation-name: pkt-w-in1; }
  .pkt-w-in2 { animation-name: pkt-w-in2; }
  .pkt-w-in3 { animation-name: pkt-w-in3; }
  .pkt-n-in1 { animation-name: pkt-n-in1; }
  .pkt-n-in2 { animation-name: pkt-n-in2; }
  .pkt-n-in3 { animation-name: pkt-n-in3; }

  .pkt-w-o1, .pkt-w-o2, .pkt-w-o3, .pkt-w-o4 { animation-duration: 8s; }
  .pkt-w-o1 { animation-name: pkt-w-o1; animation-delay: 1.8s; }
  .pkt-w-o2 { animation-name: pkt-w-o2; animation-delay: 3.8s; }
  .pkt-w-o3 { animation-name: pkt-w-o3; animation-delay: 5.8s; }
  .pkt-w-o4 { animation-name: pkt-w-o4; animation-delay: 7.8s; }
  .pkt-n-o1, .pkt-n-o2 { animation-duration: 4s; }
  .pkt-n-o1 { animation-name: pkt-n-o1; animation-delay: 1.8s; }
  .pkt-n-o2 { animation-name: pkt-n-o2; animation-delay: 3.8s; }

  /* An output lights up as its packet arrives: same cycle, same delay. */
  .flow-svg--wide .node-flash { animation: flash-wide 8s linear infinite; }
  .flow-svg--wide .node--o1 .node-flash { animation-delay: 1.8s; }
  .flow-svg--wide .node--o2 .node-flash { animation-delay: 3.8s; }
  .flow-svg--wide .node--o3 .node-flash { animation-delay: 5.8s; }
  .flow-svg--wide .node--o4 .node-flash { animation-delay: 7.8s; }
  .flow-svg--narrow .node-flash { animation: flash-narrow 4s linear infinite; }
  .flow-svg--narrow .node--o1 .node-flash { animation-delay: 1.8s; }
  .flow-svg--narrow .node--o2 .node-flash { animation-delay: 3.8s; }

  /* The core breathes each time a message reaches it. */
  .core-halo {
    transform-box: fill-box;
    transform-origin: center;
    animation: core-pulse 2s ease-out 1.8s infinite;
  }

  /* Off screen, nothing runs: site.js sets `is-paused` from an observer. */
  .is-paused .pkt,
  .is-paused .node-flash,
  .is-paused .core-halo,
  .is-paused .stage-link b { animation-play-state: paused; }
}

@keyframes flash-wide { 0%, 24% { opacity: 0; } 26% { opacity: 1; } 38%, 100% { opacity: 0; } }
@keyframes flash-narrow { 0%, 48% { opacity: 0; } 51% { opacity: 1; } 70%, 100% { opacity: 0; } }
@keyframes core-pulse { 0% { transform: scale(0.94); opacity: 1; } 70% { transform: scale(1.12); opacity: 0.2; } 100% { transform: scale(1.12); opacity: 0; } }

/* flow packets: generated by tools/flow_keyframes.py from the trace
 * coordinates in index.html. Regenerate rather than edit by hand. */
@keyframes pkt-w-in1 {
  0% { transform: translate(160px, 90px); opacity: 0; }
  3% { opacity: 1; }
  7.03% { transform: translate(205px, 90px); }
  21.09% { transform: translate(205px, 180px); }
  27% { opacity: 1; }
  30% { transform: translate(262px, 180px); opacity: 0; }
  100% { transform: translate(262px, 180px); opacity: 0; }
}
@keyframes pkt-w-in2 {
  0% { transform: translate(160px, 200px); opacity: 0; }
  3% { opacity: 1; }
  27% { opacity: 1; }
  30% { transform: translate(262px, 200px); opacity: 0; }
  100% { transform: translate(262px, 200px); opacity: 0; }
}
@keyframes pkt-w-in3 {
  0% { transform: translate(160px, 310px); opacity: 0; }
  3% { opacity: 1; }
  7.03% { transform: translate(205px, 310px); }
  21.09% { transform: translate(205px, 220px); }
  27% { opacity: 1; }
  30% { transform: translate(262px, 220px); opacity: 0; }
  100% { transform: translate(262px, 220px); opacity: 0; }
}
@keyframes pkt-w-o1 {
  0% { transform: translate(378px, 170px); opacity: 0; }
  3% { opacity: 1; }
  6.13% { transform: translate(430px, 170px); }
  19.1% { transform: translate(430px, 60px); }
  22% { opacity: 1; }
  25% { transform: translate(480px, 60px); opacity: 0; }
  100% { transform: translate(480px, 60px); opacity: 0; }
}
@keyframes pkt-w-o2 {
  0% { transform: translate(378px, 190px); opacity: 0; }
  3% { opacity: 1; }
  12.05% { transform: translate(445px, 190px); }
  18.71% { transform: translate(445px, 153px); }
  22% { opacity: 1; }
  25% { transform: translate(480px, 153px); opacity: 0; }
  100% { transform: translate(480px, 153px); opacity: 0; }
}
@keyframes pkt-w-o3 {
  0% { transform: translate(378px, 210px); opacity: 0; }
  3% { opacity: 1; }
  12.05% { transform: translate(445px, 210px); }
  18.71% { transform: translate(445px, 247px); }
  22% { opacity: 1; }
  25% { transform: translate(480px, 247px); opacity: 0; }
  100% { transform: translate(480px, 247px); opacity: 0; }
}
@keyframes pkt-w-o4 {
  0% { transform: translate(378px, 230px); opacity: 0; }
  3% { opacity: 1; }
  6.13% { transform: translate(430px, 230px); }
  19.1% { transform: translate(430px, 340px); }
  22% { opacity: 1; }
  25% { transform: translate(480px, 340px); opacity: 0; }
  100% { transform: translate(480px, 340px); opacity: 0; }
}
@keyframes pkt-n-in1 {
  0% { transform: translate(56px, 50px); opacity: 0; }
  3% { opacity: 1; }
  6.99% { transform: translate(56px, 95px); }
  22.38% { transform: translate(155px, 95px); }
  27% { opacity: 1; }
  30% { transform: translate(155px, 144px); opacity: 0; }
  100% { transform: translate(155px, 144px); opacity: 0; }
}
@keyframes pkt-n-in2 {
  0% { transform: translate(170px, 50px); opacity: 0; }
  3% { opacity: 1; }
  27% { opacity: 1; }
  30% { transform: translate(170px, 140px); opacity: 0; }
  100% { transform: translate(170px, 140px); opacity: 0; }
}
@keyframes pkt-n-in3 {
  0% { transform: translate(284px, 50px); opacity: 0; }
  3% { opacity: 1; }
  6.99% { transform: translate(284px, 95px); }
  22.38% { transform: translate(185px, 95px); }
  27% { opacity: 1; }
  30% { transform: translate(185px, 144px); opacity: 0; }
  100% { transform: translate(185px, 144px); opacity: 0; }
}
@keyframes pkt-n-o1 {
  0% { transform: translate(160px, 238px); opacity: 0; }
  3% { opacity: 1; }
  10.95% { transform: translate(160px, 268px); }
  38.32% { transform: translate(85px, 268px); }
  47% { opacity: 1; }
  50% { transform: translate(85px, 300px); opacity: 0; }
  100% { transform: translate(85px, 300px); opacity: 0; }
}
@keyframes pkt-n-o2 {
  0% { transform: translate(180px, 238px); opacity: 0; }
  3% { opacity: 1; }
  10.95% { transform: translate(180px, 268px); }
  38.32% { transform: translate(255px, 268px); }
  47% { opacity: 1; }
  50% { transform: translate(255px, 300px); opacity: 0; }
  100% { transform: translate(255px, 300px); opacity: 0; }
}
/* end of generated flow packets */

/* --------------------------------------------------------------- story -- */

.steps { list-style: none; margin-top: 64px; display: flex; flex-direction: column; gap: 96px; }

.step {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: 64px;
}

.step-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid rgba(0, 212, 224, 0.45);
  border-radius: 50%;
  font-family: 'Bebas Neue', var(--font-fallback);
  font-size: 22px;
  color: var(--blue);
  box-shadow: 0 0 18px rgba(0, 212, 224, 0.15);
}

.step-title {
  margin-top: 20px;
  font-family: 'Bebas Neue', var(--font-fallback);
  font-size: clamp(32px, 3.6vw, 46px);
  font-weight: 400;
  line-height: 1;
  color: var(--white);
}

.step-line { margin-top: 14px; max-width: 38ch; font-size: 17px; line-height: 1.6; color: var(--muted); }

.step-visual {
  min-height: 250px;
  padding: 28px;
  background: rgba(10, 26, 53, 0.85);
  border: 1px solid rgba(0, 212, 224, 0.14);
  border-radius: 6px;
}

/* Step 1: an iPhone Messages screen, in HTML and CSS only.
 *
 * Everything inside the phone is sized in `em` from one font size that tracks
 * the phone's own width (container query units), and the phone keeps a fixed
 * aspect ratio, so it scales as one piece and never shifts the layout.
 * System fonts only: nothing is downloaded to draw it.
 *
 * Colours, with measured contrast:
 *   sent (the customer, SMS)   #1E8238 with white text   4.88:1
 *   received (Palmer AI)       #E9E9EB with black text  17.3:1
 *   captions and placeholder   #6E6E73 on #F9F9FB/white  4.7 to 5.1:1
 * The commonly quoted SMS green #1F8A3B measures 4.41:1 with white, just
 * under AA, which is why it is not used. */

.phone-stage {
  display: flex;
  justify-content: center;
  min-height: 0;
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
}

.iphone {
  position: relative;
  width: min(300px, 100%);
  aspect-ratio: 300 / 612;
  padding: 3.6%;
  container-type: inline-size;
  border-radius: 15% / 7.4%;
  background: linear-gradient(145deg, #2c2f36, #0b0c0f 45%, #1d1f25);
  box-shadow:
    0 0 0 1px #4a4e57,
    inset 0 0 0 1px rgba(255, 255, 255, 0.14),
    inset 0 0 0 3px #08090b,
    0 30px 60px rgba(0, 0, 0, 0.55),
    0 0 50px rgba(0, 212, 224, 0.12);
}

/* Side buttons: the action button and volume rocker on the left, drawn by one
 * pseudo-element and its shadows; the side button on the right. */
.iphone::before,
.iphone::after {
  content: '';
  position: absolute;
  width: 1.2%;
  border-radius: 2px;
  background: linear-gradient(90deg, #3b3f47, #1a1c21);
}

.iphone::before {
  left: -1.1%;
  top: 17%;
  height: 5%;
  box-shadow: 0 60px 0 0 #2a2d33, 0 104px 0 0 #2a2d33;
}

.iphone::after { right: -1.1%; top: 27%; height: 11%; }

.iphone-screen {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  border-radius: 12% / 5.8%;
  background: #fff;
  color: #000;
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif;
  font-size: 15px;
  font-size: clamp(9px, 5.4cqw, 15px);
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: -0.01em;
  -webkit-font-smoothing: antialiased;
}

.iphone-island {
  position: absolute;
  top: 0.62em;
  left: 50%;
  width: 5.6em;
  height: 1.75em;
  margin-left: -2.8em;
  border-radius: 1em;
  background: #000;
  z-index: 2;
}

.ios-top { flex-shrink: 0; background: #f9f9fb; border-bottom: 1px solid #dcdce0; }

.ios-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 3.1em;
  padding: 0 1.3em 0 2.1em;
}

.ios-clock { font-size: 1em; font-weight: 600; letter-spacing: 0; }
.ios-status-icons { display: flex; align-items: center; gap: 0.3em; }
.ios-ico { display: block; color: #000; }
.ios-ico--signal { width: 1.05em; height: 0.72em; }
.ios-ico--wifi { width: 0.98em; height: 0.74em; }
.ios-ico--battery { width: 1.6em; height: 0.78em; }

.ios-header { position: relative; padding: 0.1em 1em 0.55em; text-align: center; }

.ios-back {
  position: absolute;
  left: 0.55em;
  top: 0.75em;
  width: 1.5em;
  height: 1.5em;
  color: #0a7aff;
}

.ios-contact { display: flex; flex-direction: column; align-items: center; gap: 0.25em; }

.ios-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.9em;
  height: 2.9em;
  border-radius: 50%;
  font-size: 0.95em;
  font-weight: 600;
  color: #fff;
  background: linear-gradient(180deg, #a5aab4, #7f8591);
}

.ios-name { font-size: 0.72em; font-weight: 500; color: #000; }

.ios-thread {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.2em;
  padding: 0.55em 0.95em 0.3em;
  overflow: hidden;
  list-style: none;
}

.ios-stamp {
  margin-bottom: 0.55em;
  font-size: 0.68em;
  line-height: 1.35;
  text-align: center;
  color: #6e6e73;
}

.ios-stamp b { font-weight: 600; }

/* A new speaker gets a little air; the same speaker groups tightly. */
.imsg { position: relative; display: flex; }
.imsg--in + .imsg--out,
.imsg--out + .imsg--in { margin-top: 0.45em; }
.imsg--out { justify-content: flex-end; }

.imsg-bubble {
  position: relative;
  max-width: 76%;
  padding: 0.42em 0.78em;
  border-radius: 1.15em;
  font-size: 0.95em;
  line-height: 1.28;
}

.imsg--out .imsg-bubble { background: #1e8238; color: #fff; }
.imsg--in .imsg-bubble { background: #e9e9eb; color: #000; }

/* The iOS tail: a curved nub of bubble colour, then a notch of screen
 * colour over it. Only the last bubble of a group has one. */
.imsg--tail .imsg-bubble::before,
.imsg--tail .imsg-bubble::after {
  content: '';
  position: absolute;
  bottom: 0;
  height: 1.3em;
}

.imsg--out.imsg--tail .imsg-bubble::before { right: -0.45em; width: 1.3em; background: #1e8238; border-bottom-left-radius: 1em 0.9em; }
.imsg--out.imsg--tail .imsg-bubble::after { right: -0.65em; width: 0.65em; background: #fff; border-bottom-left-radius: 0.6em; }
.imsg--in.imsg--tail .imsg-bubble::before { left: -0.45em; width: 1.3em; background: #e9e9eb; border-bottom-right-radius: 1em 0.9em; }
.imsg--in.imsg--tail .imsg-bubble::after { left: -0.65em; width: 0.65em; background: #fff; border-bottom-right-radius: 0.6em; }

/* Typing dots: decorative, only ever shown by the entrance timeline below. */
.imsg-typing {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  gap: 0.22em;
  padding: 0.62em 0.78em;
  border-radius: 1.15em;
  background: #e9e9eb;
  opacity: 0;
}

.imsg-typing i { width: 0.45em; height: 0.45em; border-radius: 50%; background: #8e8e93; }

.ios-receipt { margin-top: 0.1em; font-size: 0.66em; font-weight: 500; text-align: right; color: #6e6e73; }

.ios-input {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.45em 0.8em 1.5em;
}

.ios-input-ico { width: 1.45em; height: 1.45em; color: #6e6e73; flex-shrink: 0; }

.ios-field {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 2.15em;
  padding: 0 0.45em 0 0.85em;
  border: 1px solid #c6c6c8;
  border-radius: 1.1em;
  font-size: 0.95em;
  color: #6e6e73;
}

.ios-input-ico--mic { width: 1.3em; height: 1.3em; }

.ios-home {
  position: absolute;
  bottom: 0.5em;
  left: 50%;
  width: 8.4em;
  height: 0.3em;
  margin-left: -4.2em;
  border-radius: 0.2em;
  background: #000;
}

/* Step 2: the actions Palmer takes. */
.actions { list-style: none; display: flex; flex-direction: column; justify-content: center; gap: 14px; }

.actions li {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  font-size: 15px;
  color: var(--white);
  background: rgba(7, 20, 40, 0.7);
  border: 1px solid rgba(0, 212, 224, 0.2);
  border-radius: 4px;
}

.actions svg { color: var(--blue); }

/* Step 3: the text the owner receives. */
.notice { display: flex; flex-direction: column; justify-content: center; }

.notice-head {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  font-weight: 600;
  color: var(--white);
}

.notice-head svg { color: var(--blue); }
.notice-head span { margin-left: auto; font-weight: 400; color: var(--muted); }

.notice-body {
  margin-top: 14px;
  padding: 16px 18px;
  font-size: 16px;
  line-height: 1.6;
  color: var(--white);
  background: #13294d;
  border-left: 2px solid var(--blue);
  border-radius: 4px;
}

/* --------------------------------------------------------- direction --
 *
 * The page's single, labelled home for what Palmer is building toward. The
 * dashed borders here mean "not live yet", everywhere in this section. */

.direction { position: relative; }

.direction::before {
  content: '';
  position: absolute;
  inset: 60px 20px 60px;
  border: 1px dashed rgba(0, 212, 224, 0.22);
  border-radius: 10px;
  pointer-events: none;
}

.direction-label {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 500;
  color: var(--blue);
  border: 1px dashed rgba(0, 212, 224, 0.5);
  border-radius: 999px;
}

.channels { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 40px; list-style: none; }

.channel {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  font-size: 15px;
  color: var(--white);
  border-radius: 4px;
}

.channel span { font-size: 12px; color: var(--muted); }
.channel--live { background: rgba(0, 212, 224, 0.1); border: 1px solid rgba(0, 212, 224, 0.5); }
.channel--live svg, .channel--live span { color: var(--blue); }
.channel--next { border: 1px dashed rgba(163, 174, 192, 0.55); color: var(--muted); }

/* The pipeline: conversations to structure to patterns to recommendations. */
.pipeline {
  display: grid;
  grid-template-columns: 1fr 48px 1fr 48px 1fr 48px 1fr;
  align-items: stretch;
  margin-top: 56px;
}

.stage {
  display: flex;
  flex-direction: column;
  padding: 18px;
  background: rgba(10, 26, 53, 0.85);
  border: 1px solid rgba(0, 212, 224, 0.16);
  border-radius: 6px;
}

.stage-name { font-size: 13px; font-weight: 500; color: var(--blue); }
.stage-art { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 8px; min-height: 120px; margin-top: 14px; }
.stage-art i { display: block; font-style: normal; }

.art-convos i { height: 12px; border-radius: 6px; background: #1a3561; }
.art-convos i:nth-child(1) { width: 80%; }
.art-convos i:nth-child(2) { width: 60%; margin-left: auto; background: rgba(0, 212, 224, 0.55); }
.art-convos i:nth-child(3) { width: 70%; }
.art-convos i:nth-child(4) { width: 45%; margin-left: auto; background: rgba(0, 212, 224, 0.55); }

.art-rows i {
  padding: 5px 8px;
  font-size: 12px;
  color: var(--white);
  background: rgba(7, 20, 40, 0.8);
  border: 1px solid rgba(0, 212, 224, 0.2);
  border-radius: 3px;
}

.art-bars { flex-direction: row; align-items: flex-end; gap: 6px; height: 120px; }
.art-bars i { flex: 1; background: rgba(0, 212, 224, 0.35); border-radius: 2px 2px 0 0; transform-origin: bottom; }
.art-bars i:nth-child(1) { height: 40%; }
.art-bars i:nth-child(2) { height: 55%; }
.art-bars i:nth-child(3) { height: 100%; background: var(--blue); box-shadow: 0 0 14px rgba(0, 212, 224, 0.6); }
.art-bars i:nth-child(4) { height: 62%; }
.art-bars i:nth-child(5) { height: 50%; }
.art-bars i:nth-child(6) { height: 72%; }
.art-bars i:nth-child(7) { height: 30%; }

.art-recs i {
  padding: 10px 12px;
  font-size: 13px;
  line-height: 1.35;
  color: #001214;
  background: var(--blue);
  border-radius: 3px;
  font-weight: 500;
}

/* A dot travels each link, left to right, forever while on screen. */
.stage-link { position: relative; align-self: center; height: 2px; overflow: hidden; background: rgba(0, 212, 224, 0.2); }
.stage-link b { position: absolute; inset: 0; }

.stage-link b::after {
  content: '';
  position: absolute;
  right: 0;
  top: -3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--blue);
  box-shadow: 0 0 10px var(--blue);
}

@media (prefers-reduced-motion: no-preference) {
  .stage-link b { animation: link-flow 1.8s linear infinite; transform: translateX(-100%); }
  .stage-link:nth-child(4) b { animation-delay: 0.6s; }
  .stage-link:nth-child(6) b { animation-delay: 1.2s; }
}

@keyframes link-flow { from { transform: translateX(-100%); } to { transform: translateX(100%); } }

/* Example insights: amber tags say "example" before anything else does. */
.insights {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin-top: 56px;
  list-style: none;
}

.insight {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 22px 20px;
  border-top: 2px solid var(--blue);
  background: linear-gradient(180deg, rgba(0, 212, 224, 0.08), rgba(10, 26, 53, 0.6));
}

.tag {
  align-self: flex-start;
  padding: 3px 8px;
  font-size: 11px;
  font-weight: 600;
  color: #1a1400;
  background: var(--amber);
  border-radius: 3px;
}

.insight-figure {
  font-family: 'Bebas Neue', var(--font-fallback);
  font-size: 48px;
  font-weight: 400;
  line-height: 1;
  color: var(--white);
  font-variant-numeric: tabular-nums;
}

.insight-text { font-size: 15px; line-height: 1.45; color: var(--muted); }

/* Getting sharper over time. */
.horizon { margin-top: 96px; }

.horizon-title {
  font-family: 'Bebas Neue', var(--font-fallback);
  font-size: clamp(30px, 3.4vw, 44px);
  font-weight: 400;
  color: var(--white);
}

.horizon-chart {
  position: relative;
  margin-top: 24px;
  height: 160px;
  background: var(--dark2);
  border-radius: 6px;
  overflow: hidden;
}

.horizon-chart svg { display: block; width: 100%; height: 100%; }
.horizon-area { fill: rgba(0, 212, 224, 0.1); }
.horizon-line { fill: none; stroke: var(--blue); stroke-width: 2; vector-effect: non-scaling-stroke; }
.horizon-cover { fill: var(--dark2); display: none; }

.horizon-marks { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin-top: 20px; }
.horizon-marks dt { font-family: 'Bebas Neue', var(--font-fallback); font-size: 24px; color: var(--blue); }
.horizon-marks dd { margin-top: 4px; font-size: 15px; color: var(--muted); }

/* ---------------------------------------------------------- consulting -- */

.services {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 40px 48px;
  margin-top: 56px;
  list-style: none;
}

.services li { position: relative; padding-top: 20px; }

.services li::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 28px;
  height: 2px;
  background: var(--blue);
  box-shadow: 0 0 8px var(--blue);
  transform-origin: left;
  transition: transform 0.3s ease;
}

.services li:hover::before { transform: scaleX(2); }
.services h3 { font-size: 18px; font-weight: 500; color: var(--white); }
.services p { margin-top: 6px; font-size: 15px; color: var(--muted); }

/* ---------------------------------------------------------------- about -- */

.about { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: 72px; align-items: start; }

.about-portrait-frame { border-radius: 8px; overflow: hidden; background: var(--dark); }
.about-portrait img { display: block; width: 100%; height: auto; }

.about-name { margin-top: 18px; font-size: 16px; color: var(--blue); }

.about-certs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; list-style: none; }

.about-certs li {
  padding: 7px 12px;
  font-size: 13px;
  color: var(--white);
  background: rgba(0, 212, 224, 0.08);
  border: 1px solid rgba(0, 212, 224, 0.25);
  border-radius: 4px;
}

.principles { margin-top: 32px; list-style: none; display: flex; flex-direction: column; gap: 12px; }
.principles li { font-size: 16px; line-height: 1.55; color: var(--muted); }
.principles strong { font-weight: 500; color: var(--white); }

.more { margin-top: 28px; border-top: 1px solid rgba(0, 212, 224, 0.15); padding-top: 16px; }

.more summary {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  font-size: 15px;
  font-weight: 500;
  color: var(--blue);
  cursor: pointer;
  list-style: none;
}

.more summary::-webkit-details-marker { display: none; }

.more summary::before {
  content: '+';
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border: 1px solid rgba(0, 212, 224, 0.5);
  border-radius: 50%;
  font-size: 15px;
  transition: transform 0.25s ease;
}

.more[open] summary::before { transform: rotate(45deg); }
.more summary:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; border-radius: 2px; }
.more p { margin-top: 14px; max-width: 62ch; font-size: 16px; line-height: 1.75; color: var(--muted); }
.more strong { color: var(--white); font-weight: 500; }

/* ----------------------------------------------------------------- CTA -- */

.cta {
  position: relative;
  max-width: 1080px;
  margin-bottom: 100px;
  padding: 96px 60px;
  text-align: center;
  background:
    radial-gradient(ellipse 60% 70% at 50% 0%, rgba(0, 212, 224, 0.16), transparent 70%),
    rgba(10, 26, 53, 0.9);
  border: 1px solid rgba(0, 212, 224, 0.25);
  border-radius: 10px;
}

.cta-title {
  margin: 0 auto;
  max-width: 20ch;
  text-wrap: balance;
  font-family: 'Bebas Neue', var(--font-fallback);
  font-size: clamp(40px, 5.4vw, 72px);
  font-weight: 400;
  line-height: 0.95;
  color: var(--white);
}

.cta-line { margin: 18px auto 36px; max-width: 44ch; font-size: 17px; line-height: 1.6; color: var(--muted); }

.cta-details {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 20px 48px;
  margin-top: 48px;
  text-align: left;
}

.cta-details dt { font-size: 12px; color: var(--blue); }
.cta-details dd { margin-top: 4px; font-size: 15px; color: var(--white); }
.cta-details a { color: var(--white); text-decoration: none; }
.cta-details a:hover { color: var(--blue); }

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

footer {
  border-top: 1px solid rgba(255, 255, 255, 0.05);
  padding: 40px 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.footer-copy { font-size: 12px; color: var(--muted); letter-spacing: 0.05em; }

.footer-email {
  font-size: 12px;
  color: var(--blue);
  text-decoration: none;
  letter-spacing: 0.05em;
  opacity: 0.7;
  transition: opacity 0.3s;
}

.footer-email:hover { opacity: 1; }

/* ------------------------------------------------------------ entrances --
 *
 * Scroll entrances are gated twice: on `.js`, which site.js adds, and on the
 * visitor not having asked for reduced motion. Without either, nothing here
 * applies and every element is simply visible. site.js adds `is-active` to a
 * [data-animate] element once, when it first scrolls into view.
 */

@media (prefers-reduced-motion: no-preference) {
  .js .step-copy,
  .js .step-visual,
  .js .pipeline .stage,
  .js .insight {
    opacity: 0;
    transform: translateY(24px);
    transition: opacity 0.7s ease, transform 0.7s ease;
  }

  .js .is-active .step-copy,
  .js .is-active .step-visual,
  .js .is-active .stage,
  .js .is-active .insight { opacity: 1; transform: none; }

  .js .is-active .step-visual { transition-delay: 0.15s; }
  .js .is-active .stage:nth-child(3) { transition-delay: 0.2s; }
  .js .is-active .stage:nth-child(5) { transition-delay: 0.4s; }
  .js .is-active .stage:nth-child(7) { transition-delay: 0.6s; }
  .js .is-active .insight:nth-child(2) { transition-delay: 0.12s; }
  .js .is-active .insight:nth-child(3) { transition-delay: 0.24s; }
  .js .is-active .insight:nth-child(4) { transition-delay: 0.36s; }

  /* Step 2 and 3 items arrive one after another. */
  .js .actions li,
  .js .notice-body {
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 0.45s ease, transform 0.45s ease;
  }

  .js .is-active .actions li,
  .js .is-active .notice-body { opacity: 1; transform: none; }


  /* Step 1: the conversation plays out on the phone. The customer's texts
   * appear; before each Palmer AI reply, typing dots show where the reply
   * will land (its space is already reserved, so nothing moves). */
  .js .imsg-bubble,
  .js .ios-receipt {
    opacity: 0;
    transform: translateY(0.6em) scale(0.96);
    transition: opacity 0.35s ease, transform 0.35s ease;
  }

  .js .imsg--out .imsg-bubble { transform-origin: bottom right; }
  .js .imsg--in .imsg-bubble { transform-origin: bottom left; }
  .js .is-active .imsg-bubble,
  .js .is-active .ios-receipt { opacity: 1; transform: none; }
  .js .is-active .imsg-1 .imsg-bubble { transition-delay: 0.5s; }
  .js .is-active .imsg-2 .imsg-bubble { transition-delay: 2.4s; }
  .js .is-active .imsg-3 .imsg-bubble { transition-delay: 3.4s; }
  .js .is-active .imsg-4 .imsg-bubble { transition-delay: 5.2s; }
  .js .is-active .imsg-5 .imsg-bubble { transition-delay: 6.1s; }
  .js .is-active .ios-receipt { transition-delay: 6.5s; }

  .js .is-active .imsg-typing--1 { animation: typing-window 1.3s ease 1.1s both; }
  .js .is-active .imsg-typing--2 { animation: typing-window 1.3s ease 3.9s both; }
  .js .is-active .imsg-typing--1 i { animation: typing-dot 0.5s ease-in-out 1.2s 4 alternate; }
  .js .is-active .imsg-typing--2 i { animation: typing-dot 0.5s ease-in-out 4s 4 alternate; }
  .js .is-active .imsg-typing i:nth-child(2) { animation-delay: 1.35s; }
  .js .is-active .imsg-typing i:nth-child(3) { animation-delay: 1.5s; }
  .js .is-active .imsg-typing--2 i:nth-child(2) { animation-delay: 4.15s; }
  .js .is-active .imsg-typing--2 i:nth-child(3) { animation-delay: 4.3s; }
  .js .is-active .actions li:nth-child(1) { transition-delay: 0.4s; }
  .js .is-active .actions li:nth-child(2) { transition-delay: 0.8s; }
  .js .is-active .actions li:nth-child(3) { transition-delay: 1.2s; }
  .js .is-active .notice-body { transition-delay: 0.5s; }

  /* The pattern bars grow from the baseline. */
  .js .art-bars i { transform: scaleY(0); transition: transform 0.7s cubic-bezier(0.2, 0.8, 0.2, 1); }
  .js .is-active .art-bars i { transform: scaleY(1); }
  .js .is-active .art-bars i:nth-child(1) { transition-delay: 0.7s; }
  .js .is-active .art-bars i:nth-child(2) { transition-delay: 0.76s; }
  .js .is-active .art-bars i:nth-child(3) { transition-delay: 0.82s; }
  .js .is-active .art-bars i:nth-child(4) { transition-delay: 0.88s; }
  .js .is-active .art-bars i:nth-child(5) { transition-delay: 0.94s; }
  .js .is-active .art-bars i:nth-child(6) { transition-delay: 1s; }
  .js .is-active .art-bars i:nth-child(7) { transition-delay: 1.06s; }

  /* The growth line draws itself: a cover slides off it. */
  .js .horizon-cover { display: block; transition: transform 1.8s cubic-bezier(0.4, 0, 0.2, 1) 0.2s; }
  .js .horizon.is-active .horizon-cover { transform: translateX(600px); }
}

@keyframes typing-window { 0% { opacity: 0; } 12% { opacity: 1; } 88% { opacity: 1; } 100% { opacity: 0; } }
@keyframes typing-dot { from { transform: translateY(0); opacity: 0.5; } to { transform: translateY(-0.25em); opacity: 1; } }

@keyframes fadeUp {
  from { opacity: 0; transform: translateY(24px); }
  to { opacity: 1; transform: translateY(0); }
}

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

@media (max-width: 1080px) {
  .hero { grid-template-columns: 1fr; min-height: 0; gap: 56px; }
  .hero-copy { max-width: 720px; }
  .flow { max-width: 680px; }
  .insights { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 960px) {
  .nav-links { display: none; }

  /* The pipeline turns vertical, and so does the dot on each link. */
  .pipeline { grid-template-columns: 1fr; max-width: 420px; }
  .stage-link { justify-self: center; width: 2px; height: 36px; }
  .stage-link b::after { right: auto; left: -3px; top: auto; bottom: 0; }

  .step { grid-template-columns: 1fr; gap: 28px; }
  .stage-art { min-height: 0; }
  .services { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .about { grid-template-columns: 1fr; gap: 40px; }
  .about-portrait { max-width: 260px; }
}

@media (max-width: 960px) and (prefers-reduced-motion: no-preference) {
  .stage-link b { animation-name: link-flow-y; transform: translateY(-100%); }
}

@keyframes link-flow-y { from { transform: translateY(-100%); } to { transform: translateY(100%); } }

@media (max-width: 760px) {
  nav { padding: 16px 24px; }
  section { padding: 80px 24px; }
  .hero { padding-top: 112px; padding-bottom: 56px; }
  .hero-lede { font-size: 17px; }

  /* A phone gets its own diagram, not a shrunken one. */
  .flow-svg--wide { display: none; }
  .flow-svg--narrow { display: block; max-width: 400px; margin: 0 auto; }

  .steps { gap: 72px; margin-top: 44px; }
  .step-visual { min-height: 0; padding: 24px 18px; }
  .direction::before { inset: 40px 8px; }
  .horizon-marks { grid-template-columns: 1fr; gap: 14px; }
  .cta { margin: 0 16px 72px; padding: 64px 24px; }
  .cta-details { flex-direction: column; align-items: flex-start; gap: 16px; max-width: 320px; margin-left: auto; margin-right: auto; }
  footer { padding: 32px 24px; flex-direction: column; gap: 12px; text-align: center; }
}

@media (max-width: 520px) {
  nav { padding: 14px 16px; }
  .nav-logo img { height: 40px; }
  .nav-cta { padding: 7px 14px; font-size: 11px; letter-spacing: 0.1em; }
  section { padding: 72px 16px; }
  .hero { padding-top: 104px; }
  .hero-actions .btn-primary { width: 100%; text-align: center; }
  .services { grid-template-columns: 1fr; }
  .insight { padding: 18px 14px; }
  .insight-figure { font-size: 36px; }
}

/* Touch: 44px targets for every control a finger might aim at. */
@media (pointer: coarse) {
  .nav-cta,
  .btn-text { display: inline-flex; align-items: center; min-height: 44px; }
}

/* Honour a request for reduced motion everywhere. The looping diagram and
 * the entrances above already only run under `no-preference`; this stops
 * everything else, and lands every entrance on its final, visible state. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

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

  .hero-copy,
  .flow { opacity: 1; animation: none; }
}
