/* Home page sections. Loaded only by index.html. */

/* ============================= HERO ============================= */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding-block: clamp(7rem, 14vh, 10rem) var(--space-4);
  overflow: hidden;
}

.hero__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
}

/* Vignette so the particle field fades out behind the type instead of competing with it. */
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(ellipse 90% 65% at 50% 45%, transparent 25%, rgba(5, 5, 16, 0.82) 100%),
    linear-gradient(180deg, transparent 60%, var(--bg) 100%);
}

.hero__inner {
  position: relative;
  z-index: 2;
  width: var(--container);
  margin-inline: auto;
}

.hero h1 {
  max-width: 16ch;
  margin-bottom: var(--space-3);
}

/* Line masks. Each .line clips its .line__inner, which rises into place. */
.line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.06em; /* room for descenders inside the mask */
}

.line__inner {
  display: block;
  will-change: transform;
}

.hero__sub {
  font-size: var(--fs-lead);
  color: var(--text-dim);
  max-width: 44ch;
  margin-bottom: var(--space-3);
}

.hero__actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

/* Scroll hint at the bottom of the hero. */
.hero__hint {
  position: absolute;
  left: 50%;
  bottom: var(--space-3);
  z-index: 2;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.hero__hint-line {
  width: 1px;
  height: 46px;
  background: linear-gradient(180deg, var(--glass-border-lit), transparent);
  position: relative;
  overflow: hidden;
}

/* A short bright segment falls down the line, on a loop. */
.hero__hint-line::after {
  content: "";
  position: absolute;
  top: -50%;
  left: 0;
  width: 100%;
  height: 50%;
  background: linear-gradient(180deg, transparent, var(--accent));
  animation: hint-fall 2.2s var(--ease-in-out) infinite;
}

@keyframes hint-fall {
  0% { transform: translateY(0); opacity: 0; }
  30% { opacity: 1; }
  100% { transform: translateY(300%); opacity: 0; }
}

@media (max-width: 700px) {
  .hero__hint { display: none; }
  .hero__actions .btn { flex: 1 1 auto; justify-content: center; }
}

/* ============================= HANDOFF ============================= */

/* Full screen, both halves visible together. No pin, no scrub, the comparison IS the
   explanation, and you can only compare things you can see at the same time. */
.handoff {
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding-block: var(--space-5);
  /* No bottom border: the next .section draws the boundary. Both together rendered 2px. */
}

.handoff__inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.handoff__head {
  max-width: 60ch;
}

.handoff__head h2 {
  margin-bottom: var(--space-2);
}

.handoff__blurb {
  color: var(--text-dim);
  font-size: var(--fs-lead);
  max-width: 54ch;
}

.swap {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: var(--space-3);
  align-items: center;
}

.swap__side {
  margin: 0;
  min-width: 0;
}

.swap__label {
  display: block;
  margin-bottom: 0.85rem;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.swap__label--out {
  color: var(--accent);
}

/* The arrow carries the whole "and then" of the section, so it gets a drawn line either side. */
.swap__arrow {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--accent);
}

.swap__arrow svg {
  width: 20px;
  height: 20px;
  flex: none;
}

.swap__line {
  width: clamp(1rem, 3vw, 3rem);
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent-dim));
}

.handoff__foot {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  flex-wrap: wrap;
  color: var(--text-dim);
}

/* ---------- the two windows ---------- */

.win {
  position: relative;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  background: rgba(10, 11, 28, 0.9);
  overflow: hidden;
}

/* Unfinished: sits back, dashed edge. Tone does the work, not colour. */
.win--raw {
  border-style: dashed;
  background: rgba(255, 255, 255, 0.015);
}

.win--done {
  border-color: var(--accent-dim);
  box-shadow: var(--shadow-panel);
}

.win__glow {
  position: absolute;
  inset: -1px;
  z-index: 0;
  border-radius: inherit;
  background: var(--accent-soft);
  pointer-events: none;
}

.win__bar {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.8rem 1rem;
  border-bottom: 1px solid var(--glass-border);
  background: rgba(255, 255, 255, 0.02);
}

.win__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--glass-border-lit);
  flex: none;
}

.win__file {
  margin-left: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--text-faint);
}

.win__tag {
  margin-left: auto;
  padding: 0.2rem 0.6rem;
  border-radius: var(--radius-pill);
  border: 1px solid var(--accent-dim);
  background: var(--accent-soft);
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

.win__body {
  position: relative;
  z-index: 1;
  min-height: 15rem;
  padding: 1.2rem 1.3rem;
  display: flex;
  flex-direction: column;
}

/* Each .cl is its own block, so the container must NOT preserve the newlines between them, in a <pre> those render as extra blank line boxes and double the spacing. */
.code {
  font-family: var(--font-mono);
  font-size: clamp(0.6rem, 0.7vw, 0.75rem);
  line-height: 1.9;
  color: var(--text-faint);
  white-space: normal;
  margin: 0;
}

.cl {
  display: block;
  white-space: pre;
}

/* The lines a model got wrong. Dashed underline, no colour needed. */
.cl.bad {
  color: var(--text-dim);
  text-decoration: underline dashed var(--text-faint);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.win__toast {
  margin-top: auto;
  padding-top: 1rem;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  color: var(--text-dim);
}

.win__toast::before {
  content: "! ";
  color: var(--text);
  font-weight: 600;
}

/* ---------- the finished interface ---------- */

.ui {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  height: 100%;
}

.ui__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.ui__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
}

.ui__secure {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}

.ui__secure svg {
  width: 11px;
  height: 13px;
}

.ui__rows {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  font-size: 0.82rem;
  color: var(--text-dim);
}

.ui__row {
  display: flex;
  justify-content: space-between;
}

.ui__row--total {
  padding-top: 0.55rem;
  border-top: 1px solid var(--glass-border);
  color: var(--text);
  font-weight: 600;
}

.ui__btn {
  margin-top: auto;
  padding: 0.7rem;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: #0a1230;
  font-size: 0.85rem;
  font-weight: 600;
  text-align: center;
}

@media (max-width: 900px) {
  .handoff {
    min-height: 0;
  }

  .swap {
    grid-template-columns: 1fr;
    gap: var(--space-2);
  }

  /* Pointing down, not across, once the panels stack. */
  .swap__arrow {
    justify-content: center;
    transform: rotate(90deg);
  }
}

/* ============================= SERVICES (bento) ============================= */

/* Each tile shows a small diagram of the actual work. Only the flagship animates on its own;
   the other five play on hover or keyboard focus via `.is-playing` (see services.js), so one
   thing moves when the section arrives instead of six. Monochrome throughout. Before/after is
   carried by tone, never by a second hue. */

.services {
  position: relative;
  /* Keeps the decorative orb inside the viewport. Without this it widens the document. */
  overflow: hidden;
}

.services .container {
  position: relative;
  z-index: 1;
}

.bento {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: minmax(11.5rem, auto);
  gap: 0.85rem;
}

.tile {
  display: flex;
  flex-direction: column;
  padding: var(--space-3);
  overflow: hidden;
}

/* Title leads, arrow closes the line. No index number: these six are a menu, not a sequence. */
.tile__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.55rem;
}

.tile__go {
  flex: none;
  font-size: 1.05rem;
  line-height: 1;
  color: var(--accent);
  transition: transform var(--dur) var(--ease-out);
}

.tile:hover .tile__go {
  transform: translateX(6px);
}

.tile__title {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 1vw + 0.85rem, 1.4rem);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.tile__text {
  color: var(--text-dim);
  font-size: 0.93rem;
  line-height: 1.55;
  max-width: 38ch;
}

/* The diagram always sits at the bottom of the tile. */
.viz {
  position: relative;
  margin-top: auto;
  padding-top: 1.5rem;
}

/* ---------- placement ---------- */

.tile--launch   { grid-column: 1 / 3; grid-row: 1 / 3; }
.tile--rescue   { grid-column: 3 / 5; grid-row: 1 / 2; }
.tile--security { grid-column: 3 / 4; grid-row: 2 / 3; }
.tile--uiux     { grid-column: 4 / 5; grid-row: 2 / 3; }
.tile--qa       { grid-column: 1 / 3; grid-row: 3 / 4; }
.tile--deploy   { grid-column: 3 / 5; grid-row: 3 / 4; }

/* ---------- flagship ---------- */

.tile--launch {
  background: var(--accent-soft);
  border-color: var(--accent-dim);
}

.tile--launch .tile__title {
  font-size: clamp(1.5rem, 1.6vw + 0.9rem, 2.1rem);
}

.tile--launch .tile__text {
  font-size: 1rem;
  max-width: 34ch;
}

/* Two rows tall, so pinning the diagram to the bottom leaves a dead void in the middle.
   Auto margins centre it in whatever space is left over instead. */
.tile--launch .viz {
  margin-block: auto;
  padding-top: var(--space-3);
}

/* Flagship diagram: repo in, five stages, product out. The two end cards do the explaining, a bare list of stages shows there are five of them but never what you walk away with. */
.viz--launch {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.lcard {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.02em;
  color: var(--text-dim);
}

.lcard svg {
  flex: none;
  width: 15px;
  height: 15px;
}

.lcard svg circle,
.lcard svg path {
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.lcard__tag {
  margin-left: auto;
  padding: 0.2rem 0.55rem;
  border-radius: var(--radius-pill);
  font-size: 0.55rem;
  font-style: normal;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* Unfinished: dashed and set back. Tone, not colour. */
.lcard--in {
  border-style: dashed;
}

/* --text-dim, not --text-faint. These labels sit on the flagship tile's accent-tinted ground,
   which lifts the background and cost --text-faint about a point of contrast: "Prototype" measured
   3.57:1 here against 5.0:1 on plain --bg. The card is still the set-back one, it is dashed and it
   carries no accent, so the before/after reading survives the brighter ink. */
.lcard--in .lcard__tag {
  background: rgba(255, 255, 255, 0.07);
  color: var(--text-dim);
}

.lcard--out {
  border-color: var(--accent-dim);
  background: var(--accent-soft);
  color: var(--text);
}

/* Accent on accent-soft was 4.11:1: too close to its own ground. Deepening the pill instead of
   changing the ink keeps "Live" reading as the accent state, which is what the accent means. */
.lcard--out .lcard__tag {
  background: rgba(5, 5, 16, 0.5);
  color: var(--accent);
}

.lsteps {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding-block: 0.15rem;
}

.lrail {
  position: absolute;
  left: 0.65rem;
  top: 0.9rem;
  bottom: 0.9rem;
  width: 1px;
  margin-left: -0.5px;
  background: var(--glass-border);
}

.lrail i {
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform: scaleY(0);
  transform-origin: top;
}

/* Two columns: the numbered badge sits on the rail, the label beside it. */
.lstep {
  display: grid;
  grid-template-columns: 1.3rem 1fr;
  gap: 0.75rem;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: var(--text-dim);
}

.lstep b {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 1.3rem;
  height: 1.3rem;
  border-radius: 50%;
  border: 1px solid var(--glass-border-lit);
  background: var(--bg-elev);
  font-size: 0.6rem;
  font-weight: 500;
  color: var(--text-faint);
}

/* ---------- 01 code rescue: broken lines resolve as a scan passes ---------- */

.viz--rescue {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.vline {
  position: relative;
  height: 7px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.09);
  overflow: hidden;
}

.vline:nth-child(1) { width: 82%; }
.vline:nth-child(2) { width: 64%; }
.vline:nth-child(3) { width: 91%; }

.vline::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 4px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
}

.is-playing .vline::after {
  animation: heal 5s var(--ease-out) infinite;
}

.is-playing .vline:nth-child(1)::after { animation-delay: 0.25s; }
.is-playing .vline:nth-child(2)::after { animation-delay: 0.45s; }
.is-playing .vline:nth-child(3)::after { animation-delay: 0.65s; }

@keyframes heal {
  0%, 8% { transform: scaleX(0); }
  38%, 76% { transform: scaleX(1); }
  90%, 100% { transform: scaleX(0); }
}

.vscan {
  position: absolute;
  top: 1.5rem;
  bottom: 0;
  left: 0;
  width: 34%;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--accent-glow), transparent);
  opacity: 0;
}

.is-playing .vscan {
  animation: scan-across 5s var(--ease-in-out) infinite;
}

@keyframes scan-across {
  0% { transform: translateX(-120%); opacity: 0; }
  10% { opacity: 1; }
  45% { transform: translateX(320%); opacity: 1; }
  55%, 100% { transform: translateX(320%); opacity: 0; }
}

/* ---------- 02 security: shield draws, then the check lands ---------- */

.viz--security {
  display: flex;
  justify-content: center;
  overflow: hidden;
}

.viz--security svg {
  width: 64px;
  height: 66px;
  color: var(--accent);
}

.shield {
  stroke-dasharray: 190;
  stroke-dashoffset: 0;
}

.tick {
  stroke: var(--accent);
  stroke-dasharray: 30;
  stroke-dashoffset: 0;
  opacity: 1;
}

.is-playing .shield { animation: draw-shield 5s var(--ease-out) infinite; }
.is-playing .tick { animation: draw-tick 5s var(--ease-out) infinite; }

@keyframes draw-shield {
  0%, 4% { stroke-dashoffset: 190; }
  40%, 100% { stroke-dashoffset: 0; }
}

@keyframes draw-tick {
  0%, 42% { stroke-dashoffset: 30; opacity: 0; }
  50% { opacity: 1; }
  66%, 100% { stroke-dashoffset: 0; opacity: 1; }
}

/* Kept to roughly the shield's own width. Full-bleed it reads as a band across the tile. */
.viz--security .sweep {
  position: absolute;
  left: 50%;
  margin-left: -44px;
  width: 88px;
  top: 1.5rem;
  height: 30%;
  pointer-events: none;
  background: linear-gradient(180deg, transparent, var(--accent-glow), transparent);
  opacity: 0;
}

.is-playing .viz--security .sweep {
  animation: sweep-down 5s var(--ease-in-out) infinite;
}

@keyframes sweep-down {
  0%, 30% { transform: translateY(-100%); opacity: 0; }
  40% { opacity: 1; }
  70%, 100% { transform: translateY(180%); opacity: 0; }
}

/* ---------- 03 ui/ux: a messy layout snaps into alignment ---------- */

.viz--uiux {
  height: 5.5rem;
}

.viz--uiux b {
  position: absolute;
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid var(--glass-border);
}

.viz--uiux b:nth-child(1) { left: 0; top: 1.5rem; width: 40%; height: 14px; }
.viz--uiux b:nth-child(2) { left: 0; top: 2.9rem; width: 62%; height: 10px; }
.viz--uiux b:nth-child(3) { left: 0; top: 4.1rem; width: 48%; height: 10px; }
.viz--uiux b:nth-child(4) { right: 0; top: 1.5rem; width: 26%; height: 34px; background: var(--accent-soft); }

.is-playing .viz--uiux b {
  animation: snap 5s var(--ease-out) infinite;
}

.is-playing .viz--uiux b:nth-child(1) { animation-delay: 0.1s; }
.is-playing .viz--uiux b:nth-child(2) { animation-delay: 0.2s; }
.is-playing .viz--uiux b:nth-child(3) { animation-delay: 0.3s; }
.is-playing .viz--uiux b:nth-child(4) { animation-delay: 0.4s; }

@keyframes snap {
  0%, 6% { transform: translate(9px, 5px) rotate(-2.2deg); opacity: 0.45; }
  34%, 80% { transform: none; opacity: 1; }
  94%, 100% { transform: translate(9px, 5px) rotate(-2.2deg); opacity: 0.45; }
}

/* ---------- 04 QA: checks tick through, one fails then passes ---------- */

.viz--qa {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.qrow {
  display: flex;
  align-items: center;
  gap: 0.65rem;
}

.qrow i {
  flex: none;
  width: 13px;
  height: 13px;
  border-radius: 4px;
  border: 1px solid var(--glass-border-lit);
  background: transparent;
}

.qrow em {
  height: 6px;
  border-radius: 3px;
  background: var(--glass-border);
}

.qrow:nth-child(1) em { width: 58%; }
.qrow:nth-child(2) em { width: 74%; }
.qrow:nth-child(3) em { width: 46%; }
.qrow:nth-child(4) em { width: 66%; }

.is-playing .qrow i {
  animation: check-on 5s var(--ease-out) infinite;
}

.is-playing .qrow:nth-child(1) i { animation-delay: 0.15s; }
.is-playing .qrow:nth-child(2) i { animation-delay: 0.5s; }
.is-playing .qrow:nth-child(3) i { animation-delay: 0.85s; }
.is-playing .qrow:nth-child(4) i { animation-delay: 1.2s; }

@keyframes check-on {
  0%, 6% { background: transparent; border-color: var(--glass-border-lit); }
  16%, 80% { background: var(--accent); border-color: var(--accent); }
  92%, 100% { background: transparent; border-color: var(--glass-border-lit); }
}

/* The third is the bug we caught: it sits back first, then resolves. */
.is-playing .qrow--fail i {
  animation: check-fail 5s var(--ease-out) infinite;
  animation-delay: 0.85s;
}

@keyframes check-fail {
  0%, 6% { background: transparent; border-color: var(--glass-border-lit); }
  16%, 44% { background: var(--text-faint); border-color: var(--text-faint); }
  56%, 80% { background: var(--accent); border-color: var(--accent); }
  92%, 100% { background: transparent; border-color: var(--glass-border-lit); }
}

/* ---------- 05 deployment: it moves down the pipeline and goes live ---------- */

.viz--deploy {
  height: 3.5rem;
}

.dtrack {
  position: absolute;
  top: 2.6rem;
  left: 6%;
  right: 6%;
  height: 2px;
  background: var(--glass-border);
  border-radius: 2px;
  overflow: hidden;
}

.dtrack i {
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
}

.is-playing .dtrack i {
  animation: track-fill 5s var(--ease-out) infinite;
}

@keyframes track-fill {
  0%, 12% { transform: scaleX(0); }
  58%, 78% { transform: scaleX(1); }
  90%, 100% { transform: scaleX(0); }
}

/* Position and delay both come from --i on the element. These used to use :nth-of-type, which
   counts <span> siblings rather than .dnode. .dtrack is a span too, so every node was off by
   one and the third fell back to left:0, stacked at the far left. */
.dnode {
  position: absolute;
  top: 2.6rem;
  left: calc(6% + var(--i, 0) * 44%);
  width: 13px;
  height: 13px;
  margin: -5.5px 0 0 -6.5px;
  border-radius: 50%;
  border: 1px solid var(--glass-border-lit);
  background: var(--bg-elev);
}

.is-playing .dnode {
  animation: node-on 5s var(--ease-out) infinite;
  animation-delay: calc(0.3s + var(--i, 0) * 0.8s);
}

@keyframes node-on {
  0%, 8% { border-color: var(--glass-border-lit); background: var(--bg-elev); transform: scale(1); }
  18% { transform: scale(1.35); }
  26%, 78% { border-color: var(--accent); background: var(--accent); transform: scale(1); }
  90%, 100% { border-color: var(--glass-border-lit); background: var(--bg-elev); transform: scale(1); }
}

/* ---------- responsive ---------- */

@media (max-width: 1000px) {
  .bento {
    grid-template-columns: repeat(2, 1fr);
  }

  .tile--launch   { grid-column: 1 / 3; grid-row: auto; }
  .tile--rescue   { grid-column: 1 / 3; grid-row: auto; }
  .tile--security { grid-column: 1 / 2; grid-row: auto; }
  .tile--uiux     { grid-column: 2 / 3; grid-row: auto; }
  .tile--qa       { grid-column: 1 / 3; grid-row: auto; }
  .tile--deploy   { grid-column: 1 / 3; grid-row: auto; }
}

@media (max-width: 620px) {
  .bento {
    grid-template-columns: 1fr;
    grid-auto-rows: auto;
  }

  .tile,
  .tile--launch,
  .tile--rescue,
  .tile--security,
  .tile--uiux,
  .tile--qa,
  .tile--deploy {
    grid-column: 1 / -1;
  }
}

/* Reduced motion: paint every diagram in its finished state.
   services.js returns early, so `.is-playing` is never added and no animation starts. */
@media (prefers-reduced-motion: reduce) {
  .lrail i { transform: scaleY(1); }
  .dtrack i { transform: scaleX(1); }
  .vline::after { transform: scaleX(0.72); }
  .vscan,
  .viz--security .sweep { opacity: 0; }
  .lstep { color: var(--text); }
  .lstep b { background: var(--accent); border-color: var(--accent); color: #0a1230; }
  .qrow i { background: var(--accent); border-color: var(--accent); }
  .dnode { background: var(--accent); border-color: var(--accent); }
}

/* ============================= INDUSTRIES BAND ============================= */

/* A slim ticker under the hero. Monochrome: ink, hairlines, and the accent only on hover, where
   it means "this is a link you can follow". */
.industries-band {
  position: relative;
  border-block: 1px solid var(--glass-border);
  background: var(--bg-elev);
}

.band {
  position: relative;
  overflow: hidden;
  padding-block: 1.1rem;
  /* Items fade in and out at the edges instead of being chopped off by the container. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.band__track {
  display: flex;
  align-items: center;
  gap: clamp(2rem, 4vw, 3.5rem);
  width: max-content;
  will-change: transform;
}

.band__item {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  white-space: nowrap;
  font-family: var(--font-display);
  font-size: clamp(0.95rem, 0.5vw + 0.85rem, 1.1rem);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text-dim);
  transition: color var(--dur) var(--ease-out);
}

.band__item:hover {
  color: var(--accent);
}

.band__icon {
  width: 20px;
  height: 20px;
  flex: none;
  color: var(--text-faint);
  transition: color var(--dur) var(--ease-out);
}

.band__icon path,
.band__icon rect,
.band__icon circle {
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.band__item:hover .band__icon {
  color: var(--accent);
}

/* No pointer to hover with, and no drift either (see band.js), so it becomes a swipe row and
   every item has to be reachable by dragging. */
@media (max-width: 768px), (prefers-reduced-motion: reduce) {
  .band {
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }

  .band::-webkit-scrollbar {
    display: none;
  }

  .band__track {
    transform: none !important;
    padding-inline: 6vw;
  }
}

/* ============================= WORK (home teaser) ============================= */

/* Monochrome throughout: ink palette, hairlines, and greyscaled thumbnails. The only thing that
   changes on hover is tone and a small lift, no colour is introduced anywhere. */
.work__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-3);
}

.wcard {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.wcard__shot {
  display: block;
  aspect-ratio: 16 / 10;
  margin-bottom: 0.5rem;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  background: var(--bg-elev);
  overflow: hidden;
  transition: border-color var(--dur) var(--ease-out);
}

.wcard__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Top-left so each thumbnail shows the product's masthead, the recognisable part. */
  object-position: left top;
  filter: grayscale(1) contrast(1.02) brightness(0.92);
  transition: filter var(--dur) var(--ease-out), transform var(--dur-slow) var(--ease-out);
}

.wcard:hover .wcard__shot {
  border-color: var(--glass-border-lit);
}

.wcard:hover .wcard__shot img {
  filter: grayscale(1) contrast(1.02) brightness(1.08);
  transform: scale(1.04);
}

.wcard__name {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  transition: color var(--dur) var(--ease-out);
}

.wcard__line {
  color: var(--text-dim);
  font-size: 0.95rem;
  line-height: 1.55;
}

.wcard__meta {
  margin-top: auto;
  padding-top: 0.35rem;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.work__all {
  display: inline-flex;
  margin-top: var(--space-3);
  color: var(--text);
}

@media (max-width: 900px) {
  .work__grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 620px) {
  .work__grid { grid-template-columns: 1fr; }
}

/* ============================= PROOF ============================= */

.proof__stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-3);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--glass-border);
}

.stat {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.stat__num {
  font-family: var(--font-display);
  font-size: clamp(2.75rem, 5vw + 1rem, 5rem);
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1;
  background: var(--accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-variant-numeric: tabular-nums;
}

.stat__label {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* Client quotes, a one-and-a-half slide carousel.
   Built on native scroll-snap rather than a JS slider: touch swipe, trackpad, shift-scroll and
   keyboard all work for free, and it degrades to a plain scroll row if the JS never runs.
   Monochrome, like the rest of the page, the accent appears only on the active dot. */
.carousel {
  margin-top: var(--space-4);
}

.carousel__track {
  display: flex;
  gap: var(--space-3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  /* Room so a focus ring on a slide isn't clipped by the scroll container. */
  padding: 0.25rem;
  margin: -0.25rem;
}

.carousel__track::-webkit-scrollbar {
  display: none;
}

/* 62% leaves a clear half-slide peeking, which is the whole point. It tells you there is more
   without needing an arrow or a label to say so. */
.quote {
  flex: 0 0 62%;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-3);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  background: var(--glass);
}

.quote blockquote {
  margin: 0;
}

.quote blockquote p {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 0.9vw + 0.9rem, 1.5rem);
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: -0.015em;
  text-wrap: pretty;
}

/* The quote marks sit back so the words read first. */
.quote blockquote p::before {
  content: "\201C";
  color: var(--text-faint);
}

.quote blockquote p::after {
  content: "\201D";
  color: var(--text-faint);
}

.quote__by {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  margin-top: auto;
  padding-top: var(--space-2);
  border-top: 1px solid var(--glass-border);
}

.quote__name {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--text);
}

.quote__role {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  color: var(--text-faint);
}

/* ---- dots ---- */

.carousel__dots {
  display: flex;
  justify-content: center;
  gap: 0.35rem;
  margin-top: var(--space-3);
}

/* The button is a proper 32px target; the visible dot is drawn inside it. */
.dot {
  position: relative;
  width: 32px;
  height: 32px;
  border-radius: 50%;
}

.dot::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 7px;
  height: 7px;
  margin: -3.5px 0 0 -3.5px;
  border-radius: 50%;
  background: var(--glass-border-lit);
  transition: background var(--dur) var(--ease-out), transform var(--dur) var(--ease-out);
}

.dot:hover::before {
  background: var(--text-dim);
}

.dot[aria-current="true"]::before {
  background: var(--accent);
  transform: scale(1.45);
}

@media (max-width: 780px) {
  /* Still a peek, just a narrower one, the slide has to stay readable. */
  .quote {
    flex: 0 0 86%;
  }
}

@media (max-width: 780px) {
  .proof__stats { grid-template-columns: 1fr; gap: var(--space-3); }
}

/* ============================= CONTACT ============================= */

.contact {
  position: relative;
  overflow: hidden;
}

.contact__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  opacity: 0.6;
}

.contact::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(ellipse 80% 70% at 50% 50%, transparent 20%, rgba(5, 5, 16, 0.75) 100%);
}

.contact__inner {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: var(--space-4);
  align-items: start;
}

.contact__copy h2 {
  margin-block: var(--space-2) var(--space-2);
  max-width: 12ch;
}

.contact__meta {
  margin-top: var(--space-3);
  font-family: var(--font-mono);
  font-size: 0.85rem;
}

.contact__meta a {
  color: var(--accent);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur) var(--ease-out);
}

.contact__meta a:hover {
  border-color: currentColor;
}

.contact__note {
  margin-top: var(--space-2);
  color: var(--text-dim);
  max-width: 38ch;
}

/* WhatsApp is now the only way in from this page, so the card is mostly one large target with
   just enough copy around it to say what to send. It is a card but must not carry the service
   cards' pointer-glow hover. */
.wa {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-3);
}

.wa::before {
  display: none;
}

/* Bigger than a standard .btn: it is the only call to action left in the section, and on a phone
   this is the thing a thumb is aiming for. */
.wa__cta {
  padding: 1.05rem 1.9rem;
  font-size: 1.05rem;
  width: 100%;
  justify-content: center;
}

/* The WhatsApp glyph, drawn in currentColor so it takes the button's ink like every other icon
   here. Deliberately NOT WhatsApp green: one accent is the site's rule, and a green pill would be
   the only other hue on the page. The glyph shape carries the recognition on its own. */
.wa__glyph {
  width: 20px;
  height: 20px;
  flex: none;
}

.wa__points {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  margin-top: var(--space-1);
  color: var(--text-dim);
  font-size: 0.95rem;
}

.wa__points li {
  position: relative;
  padding-left: 1.1rem;
}

.wa__points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
}

@media (max-width: 900px) {
  .contact__inner { grid-template-columns: 1fr; }
}

/* ============================= ENGAGEMENT ============================= */

/* The last thing read before the form, so it is built to remove objections rather than to recite
   terms. The pitch and the call to action sit on the left; the terms sit on the right as one
   bordered object that reads like a short agreement. Something you could hold someone to.
   The previous version was six equal blocks of grey body text with no entry point, which is what
   fine print looks like. */
.engagement__grid {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: var(--space-4);
  align-items: center;
}

.engagement__pitch h2 {
  max-width: 12ch;
  margin-bottom: var(--space-2);
}

.engagement__note {
  color: var(--text-dim);
  font-size: var(--fs-lead);
  max-width: 34ch;
  margin-bottom: var(--space-3);
}

.terms-card {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  background: var(--glass);
}

.terms {
  display: flex;
  flex-direction: column;
  margin: 0;
}

/* One line each, ruled apart. Short enough to scan in a few seconds, which is all this gets. */
.term {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.9rem;
  align-items: baseline;
  padding-block: var(--space-2);
  border-top: 1px solid var(--glass-border);
  color: var(--text);
  font-size: 1rem;
  line-height: 1.55;
}

.term:first-child {
  border-top: 0;
}

.term__tick {
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--accent);
  transform: translateY(0.2em);
}

.term__tick path {
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@media (max-width: 900px) {
  .engagement__grid {
    grid-template-columns: 1fr;
    gap: var(--space-3);
  }

  .engagement__pitch h2 {
    max-width: none;
  }
}

