/* VissionLink Lab page sections only.
   Shared chrome (nav, footer, buttons, tokens, CTA, status pills, reveal)
   comes from styles.css. Nothing here is used by the home page. */

.duo-grid > *,
.track-grid > *,
.flow-lanes > *,
.service-grid > * { min-width: 0; }

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

/* The drawn schematic ground came first and still carries the hero; the
   photograph sits UNDER it as texture, not as a subject. That ordering is the
   point: a stock lab picture presented as our own would imply equipment and
   finished products that do not exist yet, so every photograph on this page is
   an abstract macro, heavily scrimmed, never captioned as ours and never
   showing a branded machine. Replace them the moment there is a real photo of
   the Lab's own work. Still no video here: the home hero owns that treatment. */
.lab-hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  padding: 168px 0 104px;
  border-bottom: 1px solid var(--line-soft);
}

/* z-index -3 puts it beneath the grid (-2) and the glow (-1). */
.lab-hero-photo {
  position: absolute;
  inset: 0;
  z-index: -3;
  background: url('../assets/img/lab-hero.jpg') center 62% / cover no-repeat;
  /* Desaturated hard: the shot has warm flex-cable orange in it, and the theme
     is a locked dark with exactly one accent. */
  filter: saturate(0.45) brightness(0.8);
}
/* Two scrims: one across, keeping the left column dark under the copy, and one
   down, so the photograph ends before the section border instead of being cut. */
.lab-hero-photo::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(96deg, var(--bg) 4%, rgba(11, 14, 19, 0.9) 38%, rgba(11, 14, 19, 0.34) 100%),
    linear-gradient(to bottom, transparent 30%, var(--bg) 98%);
}

.lab-hero-grid {
  position: absolute;
  inset: -20% 0 0;
  z-index: -2;
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, 0.055) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.055) 1px, transparent 1px);
  background-size: 68px 68px;
  /* Fades out before the copy so the grid never fights the text. */
  mask-image: radial-gradient(120% 90% at 74% 22%, #000 0%, transparent 72%);
  -webkit-mask-image: radial-gradient(120% 90% at 74% 22%, #000 0%, transparent 72%);
}

.lab-hero-glow {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(680px 420px at 78% 18%, rgba(74, 144, 232, 0.20), transparent 68%),
    radial-gradient(520px 360px at 6% 96%, rgba(74, 144, 232, 0.09), transparent 70%);
  pointer-events: none;
}

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .lab-hero-grid {
      animation: grid-drift linear both;
      animation-timeline: scroll(root);
      animation-range: 0 100vh;
    }
    .lab-hero-photo {
      animation: hero-photo-drift linear both;
      animation-timeline: scroll(root);
      animation-range: 0 100vh;
    }
  }
}

@keyframes grid-drift {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(0, 68px, 0); }
}
/* Scaled up so the parallax shift never exposes an edge. */
@keyframes hero-photo-drift {
  from { transform: scale(1.08) translate3d(0, 0, 0); }
  to { transform: scale(1.08) translate3d(0, 46px, 0); }
}

.lab-hero-copy { max-width: 760px; }

.lab-hero h1 {
  font-size: clamp(34px, 5vw, 58px);
  line-height: 1.1;
  max-width: 15ch;
}
.lab-hero-lede {
  margin-top: 24px;
  font-size: 17.5px;
  color: var(--ink-2);
  max-width: 56ch;
}

.lab-hero-actions {
  margin-top: 36px;
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

@media (prefers-reduced-motion: no-preference) {
  .lab-hero .eyebrow,
  .lab-hero h1,
  .lab-hero-lede,
  .lab-hero-actions {
    animation: hero-rise 900ms var(--ease-out) both;
  }
  .lab-hero h1 { animation-name: hero-wipe; animation-delay: 100ms; }
  .lab-hero-lede { animation-delay: 260ms; }
  .lab-hero-actions { animation-delay: 380ms; }
}

/* Duplicated from home.css rather than promoted to styles.css: only these two
   heroes use them, and a shared file that holds one caller's animation is how
   a shared file turns into a junk drawer. Keep them in sync if either moves. */
@keyframes hero-wipe {
  from { opacity: 0; transform: translateY(26px); clip-path: inset(0 0 100% 0); }
  to { opacity: 1; transform: none; clip-path: inset(0 0 -12% 0); }
}
@keyframes hero-rise {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: none; }
}

@media (max-width: 900px) {
  .lab-hero { padding: 128px 0 76px; }
  .lab-hero h1 { max-width: none; }
}

/* ------------------------------------------------------- the two houses */

.duo {
  padding: 104px 0;
  background: var(--bg-2);
  border-bottom: 1px solid var(--line-soft);
}

.duo-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  gap: 28px;
  align-items: stretch;
}

.house {
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  background:
    linear-gradient(180deg, rgba(74, 144, 232, 0.07), transparent 52%),
    var(--bg);
  padding: 34px 32px 36px;
}
.house h3 {
  font-size: 24px;
  margin-bottom: 6px;
}
.house .house-role {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.house > p {
  margin-top: 16px;
  color: var(--ink-2);
  font-size: 15px;
}

/* The join between the two houses, drawn rather than written. */
.duo-join {
  align-self: center;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 999px;
  border: 1px solid rgba(74, 144, 232, 0.4);
  background: rgba(74, 144, 232, 0.08);
  color: var(--accent);
  font-family: var(--display);
  font-size: 20px;
  line-height: 1;
  flex: none;
}

.duo-note {
  margin-top: 30px;
  max-width: 74ch;
  font-size: 14px;
  color: var(--ink-3);
}

@media (max-width: 900px) {
  .duo { padding: 76px 0; }
  .duo-grid { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .duo-join { justify-self: center; }
}

/* --------------------------------------------------------- three tracks */

.tracks { padding: 112px 0; }

.track-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
}

.track {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 32px 30px 34px;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  background: var(--bg-2);
  overflow: hidden;
  transition: transform 260ms var(--ease-out), border-color 260ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .track:hover {
    transform: translateY(-4px);
    border-color: rgba(74, 144, 232, 0.4);
  }
}

/* A full-bleed cap on the card: the negative margins pull it back out of the
   card's padding, and .track already clips with overflow: hidden, so the top
   corners follow the radius. */
.track-shot {
  position: relative;
  margin: -32px -30px 24px;
  aspect-ratio: 16 / 10;
  background: var(--bg-3);
}
.track-shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.72) contrast(1.04);
}
/* Fades into the card colour so the photo reads as part of the card rather
   than a rectangle stuck on top of one. */
.track-shot::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(11, 14, 19, 0.28) 0%, rgba(16, 20, 28, 0.1) 38%, var(--bg-2) 97%);
}

/* Track index, set in the markup so the number survives with CSS disabled. */
.track-index {
  font-family: var(--display);
  font-size: 13px;
  letter-spacing: 0.16em;
  color: var(--accent);
  margin-bottom: 18px;
}

.track h3 {
  font-size: 23px;
  line-height: 1.2;
  margin-bottom: 12px;
}
.track > p {
  color: var(--ink-2);
  font-size: 14.5px;
}
.track .ticks { margin-bottom: 0; }

.track-icon {
  width: 34px;
  height: 34px;
  color: var(--accent);
  margin-bottom: 18px;
  flex: none;
}

@media (max-width: 980px) {
  .tracks { padding: 80px 0; }
  .track-grid { grid-template-columns: minmax(0, 1fr); }
  /* One column makes the card full width, and a 16:10 cap on a 900px card is a
     wall of photograph. Flatten it. */
  .track-shot { aspect-ratio: 21 / 8; }
}
@media (max-width: 620px) {
  .track-shot { aspect-ratio: 16 / 9; }
}

/* ------------------------------------------------------- process flow */

.flow-section {
  padding: 112px 0;
  background: var(--bg-2);
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
}

.flow {
  position: relative;
  display: grid;
  gap: 0;
}

/* The spine runs behind the step numbers and draws itself as the section
   scrolls past, so the flow reads as a sequence rather than five cards. */
.flow::before {
  content: '';
  position: absolute;
  left: 23px;
  top: 24px;
  bottom: 24px;
  width: 1px;
  background: linear-gradient(180deg, rgba(74, 144, 232, 0.55), rgba(74, 144, 232, 0.12));
  transform: scaleY(0);
  transform-origin: top;
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .flow::before {
      animation: spine-draw linear both;
      animation-timeline: view();
      animation-range: entry 30% cover 62%;
    }
  }
}
/* Browsers without a view timeline get the spine drawn, not missing. */
@supports not (animation-timeline: view()) {
  .flow::before { transform: scaleY(1); }
}

@keyframes spine-draw {
  from { transform: scaleY(0); }
  to { transform: scaleY(1); }
}

.step {
  position: relative;
  display: grid;
  grid-template-columns: 48px minmax(0, 5fr) minmax(0, 6fr);
  gap: 28px;
  padding: 30px 0;
  border-top: 1px solid var(--line-soft);
}
.step:first-child { border-top: 0; }

.step-num {
  position: relative;
  z-index: 1;
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border-radius: 999px;
  border: 1px solid rgba(74, 144, 232, 0.4);
  background: var(--bg);
  color: var(--accent);
  font-family: var(--display);
  font-size: 18px;
  line-height: 1;
}

.step-body h3 {
  font-size: 21px;
  margin-bottom: 8px;
}
.step-body p {
  color: var(--ink-2);
  font-size: 14.5px;
}

.flow-lanes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
  align-content: start;
}
.lane {
  padding: 16px 18px;
  border-radius: 10px;
  border: 1px solid var(--line-soft);
  background: var(--bg);
}
.lane h4 {
  margin: 0 0 6px;
  font-family: var(--body);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.lane p {
  font-size: 13.5px;
  color: var(--ink-2);
}
/* Hardware is the newer half of the practice, so it carries the accent tick. */
.lane[data-lane='hardware'] { border-color: rgba(74, 144, 232, 0.22); }

/* .shot-wide carries a bottom margin because the home page leads with it;
   here it closes the flow, so the margin moves to the top. */
.flow-shot {
  margin-top: 48px;
  margin-bottom: 0;
}
/* Toned to the same level as the track caps. Untouched, this frame is the
   brightest thing on the page by a wide margin and pulls the eye off the flow
   it is supposed to be closing. Scoped here, not on .shot, because the home
   page's photographs are set on lighter sections and do not need it. */
.flow-shot img { filter: saturate(0.72) brightness(0.66); }

.flow-note {
  margin-top: 34px;
  max-width: 68ch;
  font-size: 14px;
  color: var(--ink-3);
}

@media (max-width: 980px) {
  .flow-section { padding: 80px 0; }
  .step {
    grid-template-columns: 40px minmax(0, 1fr);
    gap: 18px 20px;
  }
  .step-num { width: 40px; height: 40px; font-size: 16px; }
  .flow-lanes { grid-column: 2; }
  .flow::before { left: 19px; }
}
@media (max-width: 620px) {
  .flow-lanes { grid-template-columns: minmax(0, 1fr); gap: 12px; }
}

/* ---------------------------------------------------------- track status */

.roster { padding: 112px 0; }

.roster-list {
  display: grid;
  gap: 0;
}
.roster-row {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 6fr) auto;
  gap: 24px;
  align-items: baseline;
  padding: 22px 0;
  border-top: 1px solid var(--line-soft);
}
.roster-row:last-child { border-bottom: 1px solid var(--line-soft); }
.roster-row h3 { font-size: 18px; }
.roster-row p {
  color: var(--ink-2);
  font-size: 14px;
}
.roster-row .stage-status { justify-self: end; }

.roster-note {
  margin-top: 30px;
  max-width: 68ch;
  font-size: 14px;
  color: var(--ink-3);
}

@media (max-width: 820px) {
  .roster { padding: 80px 0; }
  .roster-row {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 8px 16px;
    align-items: start;
  }
  .roster-row p { grid-column: 1 / -1; }
}

/* ------------------------------------------------------ lab for clients */

.services {
  padding: 112px 0;
  background: var(--bg-2);
  border-top: 1px solid var(--line-soft);
}

.service-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 44px 40px;
}
.service {
  position: relative;
  padding-top: 20px;
}
.service::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: rgba(255, 255, 255, 0.14);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 900ms var(--ease-out);
  transition-delay: var(--enter-delay, 0ms);
}
.service.is-in::before { transform: scaleX(1); }
.service h3 {
  font-size: 19px;
  margin-bottom: 8px;
}
.service p {
  color: var(--ink-2);
  font-size: 14.5px;
}

@media (max-width: 900px) {
  .services { padding: 80px 0; }
  .service-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 34px 28px; }
}
@media (max-width: 560px) {
  .service-grid { grid-template-columns: minmax(0, 1fr); }
}

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

@media (prefers-reduced-motion: reduce) {
  .flow::before { transform: scaleY(1); }
  .service::before { transform: none; transition: none; }
  .track { transition: none; }
}
