/* ==========================================================================
   LOST — site styles
   Palette and type sampled directly from NewLostLogo1 / NewLostLogo2.
     acid green  #74F947   (logo field)
     ink         #1A1A1A   (logo letterforms)
   Signature device: the horizontal scanline / venetian-blind cut from logo 2.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Fonts — self-hosted so the site never depends on a third party being up
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Archivo Black";
  src: url("assets/fonts/archivo-black-latin.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* Variable Archivo covers 100–900 from a single 35 KB file */
@font-face {
  font-family: "Archivo";
  src: url("assets/fonts/archivo-var-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  /* brand */
  --ink: #1a1a1a;          /* exact logo dark — the page ground */
  --ink-soft: #202020;
  --card: #242424;
  --line: #313131;
  --green: #74f947;        /* exact logo green */
  --green-deep: #55ab38;
  --white: #f5f5f5;
  --grey: #9d9d9d;
  /* lifted from #6b6b6b: at 10–11px the old value only cleared 3.3:1 on ink,
     which fails AA for small text. This measures 4.8:1. */
  --grey-dim: #868686;

  /* scanline device: pitch and bar thickness, in em so they scale with type */
  --sl-pitch: 0.055em;
  --sl-bar: 0.035em;

  --max: 1320px;
  --gut: clamp(20px, 5vw, 64px);

  --display: "Archivo Black", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font: "Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

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

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--white);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }
img, svg { display: block; max-width: 100%; }

::selection { background: var(--green); color: var(--ink); }

.wrap {
  width: 100%;
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--gut);
}

/* --------------------------------------------------------------------------
   THE SCANLINE DEVICE — lifted from logo 2
   --------------------------------------------------------------------------
   .blind slices horizontal bars out of the glyphs with a mask, so whatever
   sits behind the type shows through the gaps. On the flat ink ground that
   reproduces the logo exactly; over the hero footage the video reads through
   the slots. Mask units are em, so the rhythm holds at every size.

   Only ever put .blind on large display type. Below roughly 40px the pitch
   falls under two pixels and turns to moire.
   -------------------------------------------------------------------------- */

.blind {
  -webkit-mask-image: repeating-linear-gradient(
    to bottom,
    #000 0, #000 var(--sl-bar),
    transparent var(--sl-bar), transparent var(--sl-pitch)
  );
  mask-image: repeating-linear-gradient(
    to bottom,
    #000 0, #000 var(--sl-bar),
    transparent var(--sl-bar), transparent var(--sl-pitch)
  );
}

/* Pitch is derived from logo 2: bars sit at 0.073 of the cap height with a
   64% duty cycle. Archivo Black's cap height is ~0.72em, hence these values. */

/* --------------------------------------------------------------------------
   THE DISC — the O in the LOST wordmark is a solid circle, not a letter O
   --------------------------------------------------------------------------
   This is the mark's signature move and no typeface will give it to us, so
   the O is set as an empty inline-block instead. An inline-block sitting on
   the baseline at exactly cap height fills the cap band precisely, which
   makes the trick independent of the font's own metrics.

   Only for the wordmark. Everywhere else an O is just an O.

   In the logo the disc's diameter is exactly the cap height — 158px against
   a 158px cap, measured off the source file, no optical overshoot. Archivo
   Black's cap height measures 0.704em, so that is the disc.

   The margins are not decoration: the wordmark runs at -0.045em tracking,
   which would otherwise jam the disc into the L. They restore a gap matching
   the other letter pairs. Being em-based, all of it scales.
   -------------------------------------------------------------------------- */

.disc {
  display: inline-block;
  width: 0.704em;
  height: 0.704em;
  margin-left: 0.045em;
  margin-right: 0.015em;
  border-radius: 50%;
  background: currentColor;
  /* an inline-block's baseline is its bottom margin edge, so a 0.69em box
     sitting on the baseline fills the cap band exactly, whatever the font */
  vertical-align: baseline;
}

/* Inside a display heading the keyword must not pick up a synthetic bold —
   Archivo Black ships one weight only. */
h1 .gw, h2 .gw, h3 .gw, .kinetic .gw { font-weight: inherit; }

@media (max-width: 620px) {
  /* fewer, chunkier bars where the type is physically smaller */
  .blind,
  .mark-bars { --sl-pitch: 0.075em; --sl-bar: 0.048em; }

  /* A pill cannot wrap away from the word it follows, so on narrow screens the
     word-plus-pill is the widest unbreakable unit in the statement. Trimming
     the pill keeps that unit inside the column. */
  .pill { width: 1.5em; }
}

/* --------------------------------------------------------------------------
   Scan keyword — the inline version, for keywords inside body copy.
   --------------------------------------------------------------------------
   Body-size text is far too small for an em-based blind, so instead the word
   sits solid green and a coarse pixel-pitch blind flashes across it once when
   it scrolls into view, and again on hover. Same language, legible at 20px.
   -------------------------------------------------------------------------- */

.gw {
  position: relative;
  display: inline-block;
  white-space: nowrap;
  color: var(--green);
  font-weight: 700;
}

.gw::before,
.gw::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
}

/* the bar layer: the word cut into slices and shunted sideways */
.gw::before {
  color: var(--green);
  -webkit-mask-image: repeating-linear-gradient(to bottom, #000 0 3px, transparent 3px 5px);
  mask-image: repeating-linear-gradient(to bottom, #000 0 3px, transparent 3px 5px);
}

/* the ink layer: knocks bars out of the solid word as the scan passes */
.gw::after {
  color: var(--ink);
  -webkit-mask-image: repeating-linear-gradient(to bottom, #000 0 2px, transparent 2px 5px);
  mask-image: repeating-linear-gradient(to bottom, #000 0 2px, transparent 2px 5px);
}

.gw:hover::before,
.gw.is-hit::before { animation: scan-bars 0.62s steps(1, end) 1; }

.gw:hover::after,
.gw.is-hit::after { animation: scan-knock 0.62s steps(1, end) 1; }

@keyframes scan-bars {
  0%        { opacity: 1; transform: translate3d(-0.06em, 0, 0); }
  30%       { opacity: 1; transform: translate3d(0.05em, 0, 0); }
  60%       { opacity: 1; transform: translate3d(-0.03em, 0, 0); }
  75%, 100% { opacity: 0; transform: none; }
}

@keyframes scan-knock {
  0%        { opacity: 1; -webkit-mask-position: 0 0;   mask-position: 0 0; }
  30%       { opacity: 1; -webkit-mask-position: 0 2px; mask-position: 0 2px; }
  60%       { opacity: 1; -webkit-mask-position: 0 4px; mask-position: 0 4px; }
  75%, 100% { opacity: 0; }
}

/* a keyword sitting on a different panel needs that panel's colour to knock */
.strip .gw::after { color: var(--green); }
.diff-item:hover .gw::after { color: var(--ink-soft); }

@media (prefers-reduced-motion: reduce) {
  .gw::before, .gw::after { display: none; }
}

/* .gw is an inline-block, so a line can break straight after it and orphan
   the punctuation that follows. Wrap the pair in this to keep them together. */
.nb { white-space: nowrap; }

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */

.site-head {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  background: rgba(26, 26, 26, 0.8);
  backdrop-filter: saturate(130%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s ease, background 0.3s ease;
}

.site-head.is-scrolled { border-bottom-color: var(--line); }

.site-head .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 74px;
  gap: 20px;
}

/* the header carries the real stacked lockup rather than set type */
.brand {
  display: block;
  flex: none;
  width: 42px;
  height: 42px;
  transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.brand img { width: 100%; height: 100%; }
.brand:hover { transform: scale(1.06) rotate(-2deg); }

/* --------------------------------------------------------------------------
   Nav
   --------------------------------------------------------------------------
   The spacing here is a ratio problem, not a gap problem. At 0.16em the
   tracking inflated the word spaces inside each label to 8.4px against a 34px
   gap between items — barely 4:1 — so "WHAT WE DO" read as three loose chunks
   and the four items ran together into one undifferentiated line.

   Tracking alone doesn't fix it. In a monospace face the space character is a
   full letter-width and doesn't shrink with letter-spacing, so dropping the
   tracking only moved the ratio from 4:1 to 5:1. The negative word-spacing is
   what actually closes the gaps inside each label. Together they get it to
   about 8:1, at which point the grouping is unambiguous.

   Type is a point larger because tracked-out mono at 11px was leaning on the
   spacing to stay readable.
   -------------------------------------------------------------------------- */

.nav {
  display: flex;
  align-items: center;
  gap: clamp(16px, 2.8vw, 40px);
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.nav::-webkit-scrollbar { display: none; }

.nav a {
  position: relative;
  flex: none;
  padding: 6px 0;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.07em;
  word-spacing: -0.26em;
  text-transform: uppercase;
  color: var(--grey);
  white-space: nowrap;
  transition: color 0.2s ease;
}

/* green underline that grows in on hover / when the section is on screen */
.nav a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 100%;
  background: var(--green);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.28s ease;
}

.nav a:hover { color: var(--white); }
.nav a:hover::after { transform: scaleX(1); }

.nav a.is-current { color: var(--green); }
.nav a.is-current::after { transform: scaleX(1); }

/* --------------------------------------------------------------------------
   Nav tab — for links that leave the page rather than jump to a section
   --------------------------------------------------------------------------
   Selector is .nav a.nav-tab, not .nav-tab: ".nav a" already sets colour and
   padding at (0,1,1), so a bare class would lose the cascade and need
   !important to win. Raising the specificity is the honest fix.

   The pill also solves a layout problem. The mobile nav was already at
   capacity with four items, and a fifth plain link overflowed. Bordered, it
   reads as a destination rather than a section jump, which earns its width.
   -------------------------------------------------------------------------- */

.nav a.nav-tab {
  padding: 7px 14px;
  border: 1px solid var(--green);
  color: var(--green);
  transition: background 0.22s ease, color 0.22s ease;
}

.nav a.nav-tab::after { display: none; }     /* has a border, needs no underline */

/* The Clips pill pairs the Lost Clips mark with the word. The mark is inlined
   rather than an <img> so it takes currentColor and flips to ink on hover with
   the type, instead of staying green against the filled pill. */
.nav a.nav-clips {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.nav a.nav-clips .clips-mark {
  width: 15px;
  height: 15px;
  flex: none;
  color: inherit;
}

.nav a.nav-tab:hover,
.nav a.nav-tab.is-current {
  background: var(--green);
  color: var(--ink);
}

@media (max-width: 620px) {
  .nav a.nav-tab { padding: 6px 10px; }
}

/* Below about 500px the five items need 386px against 294px of space, and no
   amount of shaving type gets that back — the pill alone is 96px. So on phones
   the in-page anchors drop out and only the pill remains.

   That's the right thing to lose. Anchor links are low value on a phone, where
   people scroll anyway, and the logo still goes home. The pill is the only item
   that leads somewhere else, so it's the only one that has to survive. */
@media (max-width: 500px) {
  .nav a:not(.nav-tab) { display: none; }
  .nav { gap: 0; }
}

/* --------------------------------------------------------------------------
   Section furniture
   -------------------------------------------------------------------------- */

section {
  position: relative;
  /* clears the fixed header when a nav link jumps to a section */
  scroll-margin-top: 74px;
}

.eyebrow {
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--green);
  margin: 0 0 34px;
}

/* the rule after an eyebrow is itself a run of scanline bars */
.eyebrow::after {
  content: "";
  flex: 1;
  height: 9px;
  background: repeating-linear-gradient(to bottom, var(--line) 0 2px, transparent 2px 5px);
}

h1, h2, h3 {
  margin: 0;
  font-family: var(--display);
  font-weight: 400;             /* Archivo Black is a single heavy weight */
  letter-spacing: -0.03em;
  line-height: 0.95;
  text-transform: uppercase;
}

.rule { height: 1px; background: var(--line); border: 0; margin: 0; }

/* --------------------------------------------------------------------------
   THE WORDMARK — solid block at rest, lines only while it glitches
   --------------------------------------------------------------------------
   The mark sits as a solid block of green and stays that way. The scanlines
   are not its resting state; they are what you catch when it glitches.

   It is built from two stacked copies of the word, a solid one and a barred
   one, cutting between each other on hard steps. steps(1, end) is what keeps
   it a cut rather than a fade, which is the difference between a glitch and a
   dissolve.

   ONE CLOCK, NOT TWO. The obvious way to do this is to animate each copy's
   opacity separately, and it visibly breaks: an opacity-only animation gets
   promoted to the compositor thread, while the barred copy also animates
   mask-position, which cannot be composited and so runs on the main thread.
   The two clocks drift, and at every burst boundary there are frames where
   the solid copy has already dropped to 0 before the barred copy has come up
   — the mark flashes out of existence entirely.

   So a single animation on the parent drives one inherited custom property,
   and both copies derive their opacity from it. They resolve in the same
   style recalculation off the same value, and because they are 1 - g and g
   they always sum to exactly 1. A gap is now arithmetically impossible.
   -------------------------------------------------------------------------- */

@property --glitch {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;      /* 0 = solid, 1 = barred */
}

@property --sl-shift {
  syntax: "<length>";
  inherits: true;
  initial-value: 0px;    /* how far the bars have travelled mid-burst */
}

.mark {
  position: relative;
  display: inline-block;
  font-family: var(--display);
  letter-spacing: -0.045em;
  text-transform: uppercase;
  color: var(--green);
  --glitch: 0;
  --sl-shift: 0px;
  animation: mark-glitch 5.2s steps(1, end) infinite;
}

.mark-solid,
.mark-bars { display: block; white-space: nowrap; }

/* the var() fallbacks matter: without @property support the custom property
   would be invalid at computed-value time, opacity would fall back to its
   initial 1, and the barred copy would sit visible forever */
.mark-solid { opacity: calc(1 - var(--glitch, 0)); }

/* the barred copy sits exactly on top. Its gaps are fully transparent, so
   over the hero footage the video reads through them. */
.mark-bars {
  position: absolute;
  top: 0;
  left: 0;
  opacity: var(--glitch, 0);
  -webkit-mask-image: repeating-linear-gradient(
    to bottom, #000 0 var(--sl-bar), transparent var(--sl-bar) var(--sl-pitch));
  mask-image: repeating-linear-gradient(
    to bottom, #000 0 var(--sl-bar), transparent var(--sl-bar) var(--sl-pitch));
  -webkit-mask-position: 0 var(--sl-shift, 0px);
  mask-position: 0 var(--sl-shift, 0px);
}

/* Default cadence: two bursts per cycle. --sl-shift walks the bars through the
   letterforms so the lines travel instead of sitting still, and the transform
   kicks the whole mark sideways. All three on one timeline. */
@keyframes mark-glitch {
  0%   { --glitch: 0; --sl-shift: 0em;     transform: translate3d(0, 0, 0); }
  14%  { --glitch: 1; --sl-shift: 0em;     transform: translate3d(-0.022em, 0, 0); }
  16%  { --glitch: 1; --sl-shift: 0.14em;  transform: translate3d(0.018em, 0, 0); }
  18%  { --glitch: 1; --sl-shift: -0.09em; transform: translate3d(-0.011em, 0, 0); }
  20%  { --glitch: 1; --sl-shift: 0.22em;  transform: translate3d(0.014em, 0, 0); }
  21%  { --glitch: 0; --sl-shift: 0em;     transform: translate3d(0, 0, 0); }
  58%  { --glitch: 1; --sl-shift: 0.05em;  transform: translate3d(0.017em, 0, 0); }
  60%  { --glitch: 1; --sl-shift: -0.16em; transform: translate3d(-0.013em, 0, 0); }
  62%  { --glitch: 1; --sl-shift: 0.3em;   transform: translate3d(0.009em, 0, 0); }
  63%  { --glitch: 0; --sl-shift: 0em;     transform: translate3d(0, 0, 0); }
  100% { --glitch: 0; --sl-shift: 0em;     transform: translate3d(0, 0, 0); }
}

/* Reduced motion for the mark is handled at the very end of this file — it has
   to cascade after the .hero-mark and .loader-mark overrides below. */

/* --------------------------------------------------------------------------
   Splash gate — the wordmark locks in out of scanline bars, then holds
   -------------------------------------------------------------------------- */

/* scroll is locked only while the splash is up, and only when JS is running */
body.splash-open { overflow: hidden; }

.loader {
  position: fixed;
  inset: 0;
  z-index: 999;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(28px, 5vh, 60px);
  width: 100%;
  border: 0;
  padding: 0;
  background: var(--ink);
  color: var(--green);
  font-family: var(--font);
  cursor: pointer;
  transition: opacity 0.7s ease, visibility 0.7s ease;
}

/* faint green bloom so the mark sits in the middle of something */
.loader::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(closest-side, rgba(116, 249, 71, 0.10), transparent 70%);
  pointer-events: none;
}

.loader.is-done { opacity: 0; visibility: hidden; }

/* The splash mark is the shared .mark component at splash scale. It glitches
   a little harder here than in the hero, since holding the gate is the whole
   job of this screen. */
.loader-mark {
  font-size: clamp(64px, 17vw, 200px);
  line-height: 1;
  animation-duration: 3.4s;
}

/* a green band scans the full frame, over a static bar texture */
.loader::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(to bottom,
      rgba(116, 249, 71, 0) 44%,
      rgba(116, 249, 71, 0.13) 50%,
      rgba(116, 249, 71, 0) 56%) no-repeat,
    repeating-linear-gradient(to bottom,
      rgba(116, 249, 71, 0.035) 0 1px,
      transparent 1px 3px);
  background-size: 100% 220%, 100% 100%;
  animation: sweep-band 3.6s linear infinite;
}

@keyframes sweep-band {
  from { background-position: 0 -120%, 0 0; }
  to   { background-position: 0 120%,  0 0; }
}

/* click affordance */
.loader-enter {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--grey);
  opacity: 0;
  animation: enter-in 0.8s ease 1.1s forwards;
  transition: color 0.25s ease;
}

.loader:hover .loader-enter { color: var(--green); }

/* square, not round — the brand has no curves outside the O */
.loader-enter::before {
  content: "";
  width: 7px;
  height: 7px;
  background: var(--green);
  animation: pulse 1.8s ease-in-out infinite;
}

@keyframes enter-in { to { opacity: 1; } }

@keyframes pulse {
  0%, 100% { opacity: 1;    transform: scale(1); }
  50%      { opacity: 0.25; transform: scale(0.6); }
}

@media (prefers-reduced-motion: reduce) {
  .loader-mark { animation: none; }
  .loader::after { animation: none; background-position: 0 200%, 0 0; }
  .loader-enter { opacity: 1; animation: none; }
  .loader-enter::before { animation: none; }
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */

.hero {
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  padding: 150px 0 clamp(80px, 10vh, 130px);
  overflow: hidden;
}

/* Video bed. Sits behind everything; falls back to a drifting colour field. */
.hero-bed {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.hero-bed video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* pushed right so the subject clears the left-aligned wordmark */
  object-position: 68% center;
  filter: grayscale(100%) contrast(1.16) brightness(0.46);
}

@media (max-width: 900px) {
  .hero-bed video { object-position: 60% center; }
}

/* fallback field, revealed when no video file is present */
.hero-bed::before {
  content: "";
  position: absolute;
  inset: -20%;
  background:
    radial-gradient(closest-side, rgba(116, 249, 71, 0.20), transparent 70%) 26% 28% / 64% 64% no-repeat,
    radial-gradient(closest-side, rgba(85, 171, 56, 0.22), transparent 70%) 74% 46% / 58% 58% no-repeat,
    radial-gradient(closest-side, rgba(116, 249, 71, 0.08), transparent 70%) 50% 80% / 52% 52% no-repeat;
  opacity: 0;
  animation: drift 22s ease-in-out infinite alternate;
}

/* Fails safe: the colour field shows until a real video actually loads. */
.hero-bed::before { opacity: 1; }
.hero-bed video { display: none; }

.hero-bed.has-video::before { opacity: 0; }
.hero-bed.has-video video { display: block; }

/* scrim so type always reads over footage, plus a faint green cast */
.hero-bed::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(26,26,26,0.52) 0%, rgba(26,26,26,0.34) 45%, var(--ink) 100%),
    linear-gradient(180deg, rgba(116,249,71,0.06), rgba(116,249,71,0.06));
}

@keyframes drift {
  from { transform: translate3d(-3%, -2%, 0) scale(1); }
  to   { transform: translate3d(3%, 2%, 0) scale(1.08); }
}

@media (prefers-reduced-motion: reduce) {
  .hero-bed::before { animation: none; }
}

.hero .wrap { position: relative; z-index: 1; width: 100%; }

/* A solid block of green that tears into scanlines on the bursts. Because the
   barred copy's gaps are transparent rather than filled, the footage behind
   reads straight through the letterforms for those few frames. */
.hero-mark {
  font-size: clamp(88px, 22vw, 320px);
  line-height: 0.82;
  margin: 0 0 clamp(28px, 4vw, 48px);
  /* Two bursts every 4s. It ran at one burst per 11s and read as broken rather
     than restless — you could sit on the page and miss it entirely. */
  animation-duration: 4s;
}

/* On short laptop screens the second hero paragraph pushes the block past the
   fold, so the wordmark gives up some height rather than the copy. */
@media (min-width: 900px) and (max-height: 820px) {
  .hero { padding-top: 124px; }
  .hero-mark { font-size: clamp(72px, 15vw, 210px); }
}

.hero-line {
  margin: 0;
  max-width: 900px;
  font-size: clamp(19px, 2.3vw, 32px);
  line-height: 1.3;
  letter-spacing: -0.015em;
  font-weight: 500;
  color: #ededed;
}

.hero-line em { font-style: normal; color: var(--green); font-weight: 700; }

/* The brands proposition is a second audience, not a continuation of the
   first sentence, so it sits a level down rather than running on. Set at the
   same weight it would read as one four-line slab and "For brands" would land
   mid-line, immediately after a full stop. */
.hero-sub {
  margin: clamp(14px, 1.6vw, 22px) 0 0;
  max-width: 780px;
  font-size: clamp(15px, 1.35vw, 20px);
  line-height: 1.55;
  color: var(--grey);
}

.hero-sub em { font-style: normal; color: var(--green); font-weight: 600; }

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-top: clamp(30px, 4vw, 46px);
  padding: 17px 32px;
  background: var(--green);
  border: 2px solid var(--green);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink);
  transition: background 0.25s ease, color 0.25s ease;
}

.btn:hover { background: transparent; color: var(--green); }

.scroll-hint {
  position: absolute;
  bottom: 34px;
  right: var(--gut);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--grey-dim);
}

/* --------------------------------------------------------------------------
   Marquee strip — green band, ink type. The one big colour inversion.
   -------------------------------------------------------------------------- */

.strip {
  padding: 18px 0;
  overflow: hidden;
  background: var(--green);
  color: var(--ink);
}

.strip-track {
  display: flex;
  gap: 52px;
  width: max-content;
  animation: slide 34s linear infinite;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  white-space: nowrap;
}

.strip-track span { display: flex; align-items: center; gap: 52px; }

/* the separator is a stack of scanline bars rather than a glyph */
.strip-track span::after {
  content: "";
  width: 16px;
  height: 11px;
  background: repeating-linear-gradient(to bottom, var(--ink) 0 2px, transparent 2px 4px);
}

@keyframes slide {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .strip-track { animation: none; }
}

/* --------------------------------------------------------------------------
   Kinetic statement — big type with video pills set mid-sentence
   -------------------------------------------------------------------------- */

.kinetic {
  font-family: var(--display);
  /* Capped at 64px so every .kl holds one line on desktop: the longest is
     "and turns their audiences" plus its pill at 18.2em of Archivo Black caps,
     against 1192px of usable width once .wrap hits its max. The 4.6vw keeps
     that one-line-per-row promise down to roughly 660px, below which the rows
     wrap, which is intended. */
  font-size: clamp(25px, 4.6vw, 64px);
  letter-spacing: -0.035em;
  line-height: 1.06;
  margin: 0;
  text-transform: uppercase;
  text-wrap: balance;
}

.kinetic .kl { display: block; }

/* the pill: a video set inline, sized to the cap height of the type */
.pill {
  display: inline-block;
  vertical-align: -0.09em;
  width: 1.75em;
  height: 0.78em;
  margin: 0 0.1em;
  border-radius: 999px;
  overflow: hidden;
  background: var(--card);
  position: relative;
}

.pill video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* fallback: a green scanline sweep, so the pill still reads as "motion here" */
.pill::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    repeating-linear-gradient(to bottom, rgba(26,26,26,0.55) 0 2px, transparent 2px 5px),
    linear-gradient(100deg, var(--green-deep), var(--green), var(--green-deep));
  background-size: 100% 100%, 300% 100%;
  animation: sweep 6s linear infinite;
}

.pill video { display: none; }

.pill.has-video::after { opacity: 0; }
.pill.has-video video { display: block; }

@keyframes sweep {
  from { background-position: 0 0, 0% 50%; }
  to   { background-position: 0 0, 300% 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .pill::after { animation: none; }
}

/* --------------------------------------------------------------------------
   Giant repeating CTA band — wears the blind, snaps solid on hover
   -------------------------------------------------------------------------- */

.cta-band {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: clamp(26px, 4vw, 46px) 0;
  overflow: hidden;
  display: block;
  color: var(--green);
}

.cta-track {
  display: flex;
  gap: 0.4em;
  width: max-content;
  animation: slide 26s linear infinite;
  font-family: var(--display);
  font-size: clamp(46px, 11vw, 150px);
  letter-spacing: -0.04em;
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
  transition: -webkit-mask-image 0.3s ease;
}

.cta-track span { display: flex; align-items: center; gap: 0.4em; }

/* arrow built from bars, keeping the device consistent */
.cta-track span::after {
  content: "";
  width: 0.42em;
  height: 0.3em;
  background: repeating-linear-gradient(to bottom, currentColor 0 0.03em, transparent 0.03em 0.055em);
}

.cta-band:hover .cta-track {
  -webkit-mask-image: none;
  mask-image: none;
}

@media (prefers-reduced-motion: reduce) {
  .cta-track { animation: none; }
}

/* --------------------------------------------------------------------------
   Blocks
   -------------------------------------------------------------------------- */

/* Section rhythm. This padding is doubled wherever two blocks meet, so the
   figure here is half the gap you actually see: at 160px the content-to-content
   gap ran to 318px, close to a third of a 900px viewport. At 100px it lands
   near 200px, which still reads as a deliberate break but stops the page
   feeling like it has holes in it.

   Keep this comfortably larger than the 82px .diff / .ops margins below it —
   items inside a section have to sit closer together than the sections do. */
.block { padding: clamp(56px, 7vw, 104px) 0; }
.block + .block { border-top: 1px solid var(--line); }

/* The heading takes the wider column: Archivo Black caps are broad, and a
   single long keyword like INFRASTRUCTURE cannot be broken, since .gw's
   overlay layers only register on an unwrapped word. */
.block-head {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: clamp(28px, 6vw, 90px);
  align-items: start;
}

/* Capped at 56px: INFRASTRUCTURE measures 9.84em in Archivo Black caps, and
   the column tops out at 589px once .wrap hits its 1320px max. 9.84 x 56 =
   551px, which clears it. Raising this cap will collide with the lede. */
.block-head h2 {
  font-size: clamp(30px, 3.9vw, 56px);
}

.block-head .lede {
  margin: 0;
  font-size: clamp(16px, 1.5vw, 20px);
  line-height: 1.65;
  color: var(--grey);
}

.block-head .lede strong { color: var(--white); font-weight: 600; }

/* --------------------------------------------------------------------------
   Numbered difference list
   -------------------------------------------------------------------------- */

.diff {
  margin-top: clamp(48px, 6vw, 82px);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}

.diff-item {
  position: relative;
  background: var(--ink);
  padding: 34px 28px 40px;
  transition: background 0.25s ease;
  overflow: hidden;
}

.diff-item:hover { background: var(--ink-soft); }

/* a block of green bars slides up from the base edge on hover */
.diff-item::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 12px;
  background: repeating-linear-gradient(to bottom, var(--green) 0 2px, transparent 2px 5px);
  transform: translateY(100%);
  transition: transform 0.32s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.diff-item:hover::after { transform: none; }

.diff-item .n {
  font-family: var(--display);
  font-size: 13px;
  letter-spacing: 0.12em;
  color: var(--green);
  display: block;
  margin-bottom: 22px;
}

.diff-item h3 {
  font-size: 20px;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin-bottom: 12px;
}

/* inside a heavy heading the keyword inherits the display face */
.diff-item h3 .gw { font-weight: inherit; }

.diff-item p {
  margin: 0;
  font-size: 15px;
  line-height: 1.6;
  color: var(--grey);
}

/* --------------------------------------------------------------------------
   Product — audience columns
   -------------------------------------------------------------------------- */

.aud {
  margin-top: clamp(48px, 6vw, 82px);
  display: grid;
  gap: 0;
}

.aud-row {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr) minmax(0, 1.1fr);
  gap: clamp(18px, 4vw, 54px);
  padding: 34px 0;
  border-top: 1px solid var(--line);
  align-items: baseline;
}

.aud-row:last-child { border-bottom: 1px solid var(--line); }

.aud-who {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--green);
}

.aud-hero {
  margin: 0;
  font-size: clamp(19px, 2.1vw, 27px);
  line-height: 1.25;
  letter-spacing: -0.02em;
  font-weight: 600;
}

.aud-detail {
  margin: 0;
  font-size: 15px;
  line-height: 1.65;
  color: var(--grey);
}

/* --------------------------------------------------------------------------
   Contact
   -------------------------------------------------------------------------- */

.contact { border-top: 1px solid var(--line); }

.contact-h {
  font-size: clamp(30px, 4.4vw, 56px);
  margin-bottom: clamp(20px, 3vw, 34px);
}

.contact-mail {
  display: inline-block;
  font-family: var(--display);
  font-size: clamp(20px, 4.4vw, 56px);
  letter-spacing: -0.03em;
  line-height: 1.05;
  color: var(--green);
  border-bottom: 3px solid transparent;
  transition: color 0.25s ease, border-color 0.25s ease;
  word-break: break-word;
}

.contact-mail:hover {
  color: var(--white);
  border-bottom-color: var(--green);
}

/* --------------------------------------------------------------------------
   Operators
   -------------------------------------------------------------------------- */

.ops {
  margin-top: clamp(48px, 6vw, 82px);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
}

.op {
  background: var(--card);
  padding: 18px 18px 26px;
  display: flex;
  flex-direction: column;
  border-top: 3px solid transparent;
  transition: border-color 0.3s ease, background 0.3s ease;
}

.op:hover { border-top-color: var(--green); background: var(--ink-soft); }

/* --------------------------------------------------------------------------
   Portraits — barred and glitching, full colour on hover
   --------------------------------------------------------------------------
   The bars alone were static, which reads as a texture rather than a fault.
   Three things move on each burst: the bars roll, they thicken, and the image
   itself takes a horizontal kick — that last one is what sells it as a broken
   signal instead of a screen door.

   Same one-clock discipline as the wordmark: a single animation on .op-photo
   drives inherited custom properties, and the overlay and the image both read
   from them. Two animations would drift, and here that would show up as the
   bars and the kick firing at visibly different moments.
   -------------------------------------------------------------------------- */

@property --ph-roll { syntax: "<length>"; inherits: true; initial-value: 0px; }
@property --ph-bar  { syntax: "<length>"; inherits: true; initial-value: 2px; }
@property --ph-kick { syntax: "<length>"; inherits: true; initial-value: 0px; }

.op-photo {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: #2c2c2c;
  margin-bottom: 22px;
  --ph-roll: 0px;
  --ph-bar: 2px;
  --ph-kick: 0px;
  animation: photo-glitch 7s steps(1, end) infinite;
}

/* Staggered with negative delays so the row never glitches in unison — five
   faces breaking up on the same frame looks like a rendering bug.

   These values are not evenly spaced on purpose. There are two bursts per
   cycle, 2.87s and 4.13s apart, so an even 1.4s stagger puts one card's second
   burst within 70ms of another card's first and they read as simultaneous.
   Solved for maximum separation instead: the ten events now sit at least 530ms
   apart across the cycle. */
.op:nth-child(1) .op-photo { animation-delay: -0.0s; }
.op:nth-child(2) .op-photo { animation-delay: -0.6s; }
.op:nth-child(3) .op-photo { animation-delay: -1.2s; }
.op:nth-child(4) .op-photo { animation-delay: -2.3s; }
.op:nth-child(5) .op-photo { animation-delay: -5.9s; }

.op-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(100%) contrast(1.05);
  transform: translate3d(var(--ph-kick, 0px), 0, 0);
  transition: filter 0.4s ease;
}

.op-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    to bottom,
    rgba(26, 26, 26, 0.45) 0 var(--ph-bar, 2px),
    transparent var(--ph-bar, 2px) 6px);
  background-position: 0 var(--ph-roll, 0px);
  opacity: 1;
  transition: opacity 0.4s ease;
  pointer-events: none;
}

@keyframes photo-glitch {
  0%    { --ph-roll: 0px;  --ph-bar: 2px;   --ph-kick: 0px; }
  30%   { --ph-roll: 3px;  --ph-bar: 3.5px; --ph-kick: 3px; }
  30.7% { --ph-roll: -2px; --ph-bar: 2px;   --ph-kick: -4px; }
  31.4% { --ph-roll: 5px;  --ph-bar: 3px;   --ph-kick: 2px; }
  32%   { --ph-roll: 0px;  --ph-bar: 2px;   --ph-kick: 0px; }
  71%   { --ph-roll: -3px; --ph-bar: 3.5px; --ph-kick: -3px; }
  71.7% { --ph-roll: 4px;  --ph-bar: 2.5px; --ph-kick: 4px; }
  72.4% { --ph-roll: 0px;  --ph-bar: 2px;   --ph-kick: 0px; }
  100%  { --ph-roll: 0px;  --ph-bar: 2px;   --ph-kick: 0px; }
}

/* Hover settles it completely: bars off, glitch paused, full colour. The point
   of contact is the reward, so nothing should still be twitching. */
.op:hover .op-photo {
  animation-play-state: paused;
  --ph-roll: 0px;
  --ph-bar: 2px;
  --ph-kick: 0px;
}

.op:hover .op-photo::after { opacity: 0; }

.op:hover .op-photo img {
  filter: grayscale(0%) contrast(1);
  transform: scale(1.04);
  transition: filter 0.4s ease, transform 0.6s ease;
}

@media (prefers-reduced-motion: reduce) {
  .op-photo { animation: none; }
}

/* Two lines are reserved so a long name like Mustafa Contractor doesn't push
   its role and bio out of step with the rest of the row. */
.op h3 {
  font-size: 19px;
  letter-spacing: -0.02em;
  color: var(--green);
  line-height: 1.1;
  min-height: 2.2em;
}

.op .role {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--white);
  margin: 8px 0 18px;
}

.op p.bio {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.55;
  color: #dcdcdc;
}

/* --------------------------------------------------------------------------
   LinkedIn links — shared by the operator cards and the footer
   -------------------------------------------------------------------------- */

.li-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey);
  transition: color 0.22s ease;
}

.li-link svg {
  width: 15px;
  height: 15px;
  fill: currentColor;
  flex: none;
}

.li-link:hover,
.li-link:focus-visible { color: var(--green); }

/* On a card, margin-top:auto pins it to the base so the links line up across
   the row regardless of how long each bio runs. */
.op-li {
  align-self: flex-start;
  margin-top: auto;
  padding-top: 20px;
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.site-foot {
  border-top: 1px solid var(--line);
  padding: 46px 0 54px;
}

.site-foot .wrap {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 26px;
  flex-wrap: wrap;
}

/* logo and the company LinkedIn link travel together as one group */
.foot-left {
  display: flex;
  align-items: center;
  gap: clamp(18px, 2.5vw, 28px);
}

.foot-mark {
  display: block;
  width: 64px;
  height: 64px;
  flex: none;
}

.foot-mark img { width: 100%; height: 100%; }

.foot-meta {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--grey-dim);
  text-align: right;
}

.foot-meta a { color: var(--grey); }
.foot-meta a:hover { color: var(--green); }

/* --------------------------------------------------------------------------
   Reveal on scroll
   -------------------------------------------------------------------------- */

.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}

.reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* --------------------------------------------------------------------------
   Responsive
   -------------------------------------------------------------------------- */

@media (max-width: 1080px) {
  .ops { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  .block-head { grid-template-columns: 1fr; }
  .aud-row { grid-template-columns: 1fr; gap: 12px; }
}

@media (max-width: 620px) {
  .ops { grid-template-columns: 1fr; }
  .brand { width: 36px; height: 36px; }

  /* all four nav items have to fit the space left after the lockup, otherwise
     Contact sits off-screen behind a scroll with no affordance */
  .nav { gap: 12px; }
  .nav a { font-size: 10px; letter-spacing: 0.07em; }
}

@media (max-width: 389px) {
  .nav { gap: 8px; }
  .nav a { font-size: 9px; letter-spacing: 0.02em; }
  .scroll-hint { display: none; }
  .site-foot .wrap { align-items: flex-start; }
  .foot-meta { text-align: left; }
  .foot-mark { width: 52px; height: 52px; }
}

/* --------------------------------------------------------------------------
   Reduced motion — the wordmark
   --------------------------------------------------------------------------
   Deliberately last in the file. Two things make this fragile:

   1. .hero-mark and .loader-mark both set animation-name, and both appear
      after the wordmark section. A reduced-motion rule placed up there loses
      the cascade to them and the glitch simply keeps running.

   2. It sets animation-name, not the animation shorthand. The shorthand would
      also reset timing-function to ease and iteration-count to 1. Combined
      with .hero-mark re-setting only name and duration, that left the hero
      running a single 11s pass with ease easing — the custom property
      interpolating smoothly instead of stepping, so the mark sat frozen
      part-way through a glitch. Worse than no handling at all.

   With the animation off, --glitch holds its initial 0, so the solid copy
   stays at opacity 1 and the barred copy at 0. Nothing else to undo.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .mark,
  .hero-mark,
  .loader-mark { animation-name: none; }
}
