@import url('fonts.css');

/* ---------------------------------------------------------------
   NX app development. One world: navy ground, Nx Blue as the only
   accent, Anton in capitals for display, Poppins for body.
   --------------------------------------------------------------- */

:root {
  --navy: #0a1826;
  --navy-deep: #06111c;
  --navy-lift: #0e2133;
  --blue: #42b5f7;
  --blue-dark: #2e9be0;
  --blue-deep: #1a6fae;
  --white: #ffffff;
  --mist: #c9dcea;   /* body text on navy, 11.4:1 */
  --mist-dim: #9ab6cc; /* secondary on navy, 7.2:1 */
  --rule: rgba(201, 220, 234, 0.18);

  --gutter: clamp(20px, 3.4vw, 48px);
  --radius-screen: 22px;
  --radius-pill: 999px;

  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
}

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

html {
  scrollbar-color: var(--blue-deep) var(--navy-deep);
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--navy);
  color: var(--white);
  font-family: 'Poppins', system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

::selection { background: var(--blue); color: var(--navy-deep); }

:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
  border-radius: 4px;
}

::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--navy-deep); }
::-webkit-scrollbar-thumb {
  background: var(--blue-deep);
  border-radius: var(--radius-pill);
  border: 3px solid var(--navy-deep);
}
::-webkit-scrollbar-thumb:hover { background: var(--blue-dark); }

img { max-width: 100%; display: block; }

a { color: inherit; text-decoration: none; }

h1, h2, h3 {
  font-family: 'Anton', 'Poppins', sans-serif;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: -0.012em;
  margin: 0;
  text-wrap: balance;
}

p { margin: 0; }

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 50;
  background: var(--blue);
  color: var(--navy-deep);
  padding: 12px 20px;
  font-weight: 600;
  border-radius: 0 0 8px 0;
}
.skip:focus { left: 0; }

/* ----------------------------- navigation ----------------------------- */

.nav {
  position: fixed;
  inset: 0 0 auto 0;
  height: 72px;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 0 var(--gutter);
  background: linear-gradient(var(--navy) 42%, rgba(10, 24, 38, 0));
}

.nav__mark { display: flex; align-items: center; gap: 10px; min-height: 44px; }
.nav__mark img { width: 30px; height: auto; }
.nav__mark span {
  font-family: 'Anton', sans-serif;
  font-size: 19px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.nav__links {
  display: flex;
  gap: 30px;
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 14.5px;
  color: var(--mist);
}
.nav__links a {
  position: relative;
  display: inline-block;
  padding: 6px 0;
  transition: color 220ms ease;
}
.nav__links a::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--blue);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 220ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .nav__links a:hover { color: var(--white); }
  .nav__links a:hover::after { transform: scaleX(1); }
}
.nav__links a:focus-visible::after { transform: scaleX(1); }

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  white-space: nowrap;
  border: 0;
  border-radius: var(--radius-pill);
  padding: 16px 32px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.005em;
  cursor: pointer;
  background: var(--blue);
  color: var(--navy-deep);
  transition: transform 160ms var(--ease-out), background-color 200ms ease;
}
.btn--small { padding: 11px 24px; font-size: 13.5px; }
.btn--big {
  padding: 21px 42px;
  font-size: 17px;
  letter-spacing: 0.002em;
}
.btn--squish {
  transition:
    transform 420ms cubic-bezier(0.34, 1.56, 0.64, 1),
    background-color 200ms ease,
    box-shadow 300ms var(--ease-out);
  box-shadow: 0 10px 26px rgba(2, 8, 14, 0.4);
  will-change: transform;
}
@media (hover: hover) and (pointer: fine) {
  .btn--squish:hover {
    transform: scale(1.03);
    box-shadow: 0 16px 38px rgba(2, 8, 14, 0.5);
  }
}
/* the press itself is quick and does not overshoot; only the release springs.
   Scoped tighter than `.btn:active`, which sits further down the file. */
.btn.btn--squish:active {
  transform: scale(0.93);
  transition: transform 110ms var(--ease-out);
  box-shadow: 0 4px 14px rgba(2, 8, 14, 0.45);
}
@media (prefers-reduced-motion: reduce) {
  .btn--squish,
  .btn--squish:hover,
  .btn.btn--squish:active { transition: none; transform: none; }
}
@media (hover: hover) and (pointer: fine) {
  .btn:hover { background: var(--blue-dark); }
}
.btn:active { transform: scale(0.97); }

/* ------------------------------- layout ------------------------------- */

.shell { max-width: 1680px; margin: 0 auto; }

section { position: relative; }

.band {
  padding: clamp(84px, 11vh, 132px) var(--gutter);
}

.lede {
  font-size: clamp(17px, 1.3vw, 19.5px);
  line-height: 1.62;
  color: var(--mist);
  max-width: 62ch;
}

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

.hero {
  min-height: 100dvh;
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(260px, 26vw, 400px);
  align-items: center;
  align-content: center;
  gap: clamp(28px, 3vw, 56px);
  padding: 112px var(--gutter) 72px;
}

.hero .reel {
  height: min(80vh, 800px);
  grid-template-columns: minmax(0, 1fr);
}

/* The hero sits on a plate built from the real app screens, tilted and sunk under
   a navy wash. tools/hero-bg.html is the source; render it with
   E:\playwright\appdev-hero-bg.mjs. */
.hero { position: relative; isolation: isolate; }
.hero::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    /* keeps the headline side safe and lands the plate back into the navy */
    linear-gradient(0deg, var(--navy) 0%, rgba(10, 24, 38, 0) 20%),
    linear-gradient(100deg,
      rgba(10, 24, 38, 0.94) 0%,
      rgba(10, 24, 38, 0.9) 30%,
      rgba(10, 24, 38, 0.6) 47%,
      rgba(10, 24, 38, 0.12) 64%,
      rgba(10, 24, 38, 0) 76%),
    url('../img/hero-bg.webp');
  background-size: cover, cover, cover;
  background-position: center, center, 58% center;
  background-repeat: no-repeat;
}

.hero__copy { max-width: 760px; }

.hero h1 {
  font-size: clamp(42px, 6.3vw, 92px);
  line-height: 0.93;
}
.hero h1 em { font-style: normal; color: var(--blue); }
.hero h1 { text-wrap: nowrap; }

.hero__sub {
  margin-top: clamp(22px, 2.4vw, 30px);
  font-size: clamp(17px, 1.32vw, 20px);
  line-height: 1.58;
  color: var(--white);
  max-width: 34ch;
}

.hero__cta {
  margin-top: clamp(30px, 3.4vw, 42px);
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}

/* --------------------------------- reel -------------------------------- */

.reel {
  position: relative;
  overflow: hidden;
  display: grid;
  gap: 22px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* a long fade at both ends so the column dissolves into the navy rather than
     reading as a framed panel */
  mask-image: linear-gradient(transparent 0, #000 24%, #000 80%, transparent 100%);
  -webkit-mask-image: linear-gradient(transparent 0, #000 24%, #000 80%, transparent 100%);
}

.reel__track {
  display: flex;
  flex-direction: column;
  gap: 22px;
  will-change: transform;
  animation: reel-up 96s linear infinite;
}
.reel__track--down { animation-name: reel-down; animation-duration: 112s; }

@keyframes reel-up {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, -50%, 0); }
}
@keyframes reel-down {
  from { transform: translate3d(0, -50%, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

.reel:hover .reel__track { animation-play-state: paused; }

.screen {
  flex: 0 0 auto;
  border-radius: var(--radius-screen);
  overflow: hidden;
  background: var(--navy-lift);
  box-shadow: 0 22px 54px rgba(3, 10, 18, 0.55);
  transition: transform 260ms var(--ease-out);
}
.screen img { width: 100%; height: auto; }
@media (hover: hover) and (pointer: fine) {
  .screen:hover { transform: translateY(-6px); }
}

/* ------------------------------- method -------------------------------- */

.method {
  display: grid;
  grid-template-columns: clamp(300px, 33vw, 486px) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 92px);
  align-items: center;
}
.method__reel { order: -1; }

.method h2 {
  font-size: clamp(34px, 4.4vw, 64px);
  line-height: 0.96;
}
.method h2 em { font-style: normal; color: var(--blue); }

.stage {
  padding: 30px 0;
  border-top: 1px solid var(--rule);
  display: grid;
  grid-template-columns: minmax(0, 210px) minmax(0, 1fr);
  gap: clamp(16px, 2.6vw, 44px);
  align-items: start;
}
.stage:last-child { border-bottom: 1px solid var(--rule); }
.stage h3 {
  font-size: clamp(26px, 2.5vw, 36px);
  line-height: 1;
  color: var(--white);
}
.stage p { color: var(--mist); max-width: 54ch; }

.method__reel { height: clamp(460px, 72vh, 740px); }

/* -------------------------------- work --------------------------------- */

.work__head {
  padding: 0 var(--gutter) clamp(34px, 4vw, 56px);
  display: grid;
  gap: 20px;
  max-width: 1100px;
}
.work__head h2 { font-size: clamp(34px, 5.2vw, 76px); line-height: 0.95; }
.work__head h2 em { font-style: normal; color: var(--blue); }

/* ------------------------------ deliverables ---------------------------- */

.gives {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: clamp(30px, 4.6vw, 84px);
  align-items: center;
}
.gives > :first-child { max-width: 440px; }
.gives h2 { font-size: clamp(32px, 4.2vw, 60px); line-height: 0.96; }
.gives h2 em { font-style: normal; color: var(--blue); }

.gives__list { display: grid; gap: 0; }
.gives__item {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr);
  gap: 18px;
  padding: 22px 0;
  border-bottom: 1px solid var(--rule);
  align-items: start;
}
/* the first one is the whole point of the stage, so it is not the same size */
.gives__item:first-child { border-top: 1px solid var(--rule); padding: 30px 0 32px; }
.gives__item:first-child h3 { font-size: clamp(24px, 2.1vw, 30px); }
.gives__item:first-child p { font-size: 17px; max-width: 46ch; }
.gives__item:first-child svg { width: 32px; height: 32px; }
.gives__item svg { width: 26px; height: 26px; stroke: var(--blue); fill: none;
  stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.gives__item h3 { font-size: 20px; line-height: 1.25; letter-spacing: 0; }
.gives__item p { color: var(--mist); font-size: 15.5px; margin-top: 4px; max-width: 52ch; }

/* -------------------------------- close -------------------------------- */

.close {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(300px, 33vw, 486px);
  gap: clamp(32px, 5vw, 80px);
  align-items: center;
}
.close h2 { font-size: clamp(38px, 5.6vw, 84px); line-height: 0.93; }
.close h2 em { font-style: normal; color: var(--blue); }

/* A sentence rather than a three line statement, so it sets a step smaller and lets
   the browser even out the lines instead of being broken by hand. */
.close h2.close__long {
  font-size: clamp(32px, 4.2vw, 62px);
  line-height: 0.98;
  text-wrap: balance;
  max-width: 24ch;
}
.close__reel { height: clamp(360px, 54vh, 560px); }

footer {
  padding: 30px var(--gutter) 44px;
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  gap: 10px 26px;
  justify-content: space-between;
  font-size: 14px;
  color: var(--mist-dim);
}

/* ------------------------------- reveals ------------------------------- */

.rise {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition: opacity 620ms var(--ease-out), transform 620ms var(--ease-out);
}
.rise.is-in { opacity: 1; transform: none; }
.rise:nth-child(2) { transition-delay: 60ms; }
.rise:nth-child(3) { transition-delay: 120ms; }
.rise:nth-child(4) { transition-delay: 180ms; }

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

@media (max-width: 1080px) {
  .method, .gives, .close { grid-template-columns: minmax(0, 1fr); }
  .method__reel, .close__reel { height: 420px; order: -1; }
}

@media (max-width: 860px) {
  .nav__links { display: none; }
  .hero {
    grid-template-columns: minmax(0, 1fr);
    min-height: auto;
    padding-top: 104px;
    padding-bottom: 0;
    gap: 40px;
  }
  .hero__sub { max-width: 38ch; }
  .reel { height: 460px; }
  /* the copy runs the full width here, so the plate goes lighter and quieter */
  .hero::before {
    background-image:
      linear-gradient(0deg, var(--navy) 0%, rgba(10, 24, 38, 0) 24%),
      linear-gradient(180deg,
        rgba(10, 24, 38, 0.92) 0%,
        rgba(10, 24, 38, 0.86) 52%,
        rgba(10, 24, 38, 0.62) 100%),
      url('../img/hero-bg-small.webp');
    background-position: center, center, 62% center;
  }
  /* stacked and left aligned, two different button widths read as an accident */
  .hero__cta { flex-direction: column; align-items: stretch; }
  .hero__cta .btn { width: 100%; max-width: 320px; }
  .stage { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .gives__item { grid-template-columns: 22px minmax(0, 1fr); gap: 14px; }
  footer { flex-direction: column; }
}

@media (prefers-reduced-motion: reduce) {
  .reel__track { animation: none; }
  .rise { opacity: 1; transform: none; transition: none; }
  .screen, .btn { transition: none; }
}

/* ===================================================================
   Apps page (apps.html). The staggered card grid, the chips sitting on
   the image and the counter all come from the appro.digital structure
   Bradley pinned as the reference for this page.
   =================================================================== */

.page-hero {
  position: relative;
  isolation: isolate;
  display: grid;
  gap: clamp(34px, 4.4vw, 64px);
  padding-top: clamp(132px, 16vh, 188px);
}
/* the same plate as the hero page, so the three openings belong together */
.page-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    /* the fact row at the foot has to sit on clean navy, not on the plate */
    linear-gradient(0deg, var(--navy) 0%, var(--navy) 9%, rgba(10, 24, 38, 0) 38%),
    linear-gradient(100deg,
      rgba(10, 24, 38, 0.94) 0%,
      rgba(10, 24, 38, 0.88) 34%,
      rgba(10, 24, 38, 0.55) 56%,
      rgba(10, 24, 38, 0.3) 78%,
      rgba(10, 24, 38, 0.26) 100%),
    url('../img/hero-bg.webp');
  background-size: cover, cover, cover;
  background-position: center, center, 60% center;
  background-repeat: no-repeat;
}
@media (max-width: 860px) {
  .page-hero::before {
    background-image:
      linear-gradient(0deg, var(--navy) 0%, var(--navy) 8%, rgba(10, 24, 38, 0) 34%),
      linear-gradient(180deg,
        rgba(10, 24, 38, 0.92) 0%,
        rgba(10, 24, 38, 0.86) 55%,
        rgba(10, 24, 38, 0.64) 100%),
      url('../img/hero-bg-small.webp');
    background-position: center, center, 62% center;
  }
}
.page-hero h1 {
  font-size: clamp(42px, 6.6vw, 96px);
  line-height: 0.93;
}
.page-hero h1 em { font-style: normal; color: var(--blue); }

/* This headline is meant to hold at two lines at every width. Below about 460px the
   42px floor is wider than the viewport can take, so down there the size follows the
   viewport instead of the floor. It picks up exactly where the floor leaves off, so
   there is no step at the breakpoint. */
@media (max-width: 459px) {
  .page-hero h1.h1--hold-two { font-size: 9.1vw; }
}
.page-hero__copy .lede {
  margin-top: clamp(22px, 2.4vw, 30px);
  max-width: 48ch;
  color: var(--white);
}
.page-hero .hero__cta { margin-top: clamp(28px, 3.2vw, 40px); }

/* ------------------------------ the cards ------------------------------ */

.cards {
  padding: 0 var(--gutter) clamp(40px, 5vw, 72px);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(36px, 4.6vw, 80px) clamp(28px, 3.4vw, 56px);
  align-items: start;
}
/* the right column drops, so the pair reads as a stagger rather than a table */
.cards > :nth-child(even) { margin-top: clamp(40px, 7vw, 130px); }

.card { --accent: var(--blue); }

.card__media {
  position: relative;
  border-radius: 20px;
  overflow: hidden;
  background: var(--navy-lift);
  box-shadow: 0 28px 64px rgba(2, 8, 14, 0.5);
}
.card__media img {
  width: 100%;
  height: auto;
  transition: transform 520ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .card:hover .card__media img { transform: scale(1.03); }
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border-radius: var(--radius-pill);
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--white);
  background: rgba(6, 17, 28, 0.85);
  box-shadow: inset 0 0 0 1px rgba(201, 220, 234, 0.2);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.chip--status {
  position: absolute;
  left: 16px;
  top: 16px;
  color: var(--navy-deep);
  background: var(--accent);
  box-shadow: none;
}
.chip--status::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--navy-deep);
  opacity: 0.55;
}
.chip-row {
  position: absolute;
  right: 16px;
  bottom: 16px;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
  max-width: calc(100% - 32px);
}

.card__meta {
  margin-top: 22px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mist-dim);
}

.card h3 {
  margin-top: 12px;
  font-size: clamp(28px, 2.9vw, 42px);
  line-height: 1;
}
.card__line { margin-top: 14px; color: var(--mist); max-width: 44ch; }


/* --------------------------- seeing one yourself ------------------------ */

.seeing {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(30px, 4.6vw, 84px);
  align-items: center;
}
.seeing h2 { font-size: clamp(32px, 4.2vw, 60px); line-height: 0.96; }
.seeing h2 em { font-style: normal; color: var(--blue); }

.steps { list-style: none; margin: 0; padding: 0; counter-reset: step; }
.steps li {
  counter-increment: step;
  display: grid;
  grid-template-columns: minmax(0, 46px) minmax(0, 1fr);
  gap: 20px;
  padding: 24px 0;
  border-bottom: 1px solid var(--rule);
}
.steps li:first-child { border-top: 1px solid var(--rule); }
.steps li::before {
  content: counter(step, decimal-leading-zero);
  font-family: 'Anton', sans-serif;
  font-size: 22px;
  line-height: 1.1;
  color: var(--blue);
}
.steps h3 { grid-column: 2; font-size: 21px; line-height: 1.2; letter-spacing: 0; }
.steps p { grid-column: 2; margin-top: 6px; color: var(--mist);
  font-size: 15.5px; max-width: 52ch; }

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

@media (max-width: 1080px) {
  .seeing { grid-template-columns: minmax(0, 1fr); }
  .cards { grid-template-columns: minmax(0, 1fr); }
  .cards > :nth-child(even) { margin-top: 0; }
}

@media (max-width: 860px) {
  .page-hero { padding-top: 112px; }
  .chip-row { position: static; margin: 0; padding: 14px 16px 16px; justify-content: flex-start; }
  .card__media { display: flex; flex-direction: column; }
  .steps li { grid-template-columns: minmax(0, 34px) minmax(0, 1fr); gap: 14px; }
}

/* ===================================================================
   How a build runs (how.html). The stage track, the outline pills and
   the stack grid follow the kijo.london/apps structure Bradley pinned
   as the reference for this page.
   =================================================================== */

/* The four stages are contained blocks, roughly two thirds of the column wide with
   the picture about a third, stepping left to right down the page. They reveal in
   reading order as you reach them. */
.cascade {
  overflow-x: clip;
  overflow-y: visible;
  padding: 0 var(--gutter) clamp(40px, 5vw, 80px);
  display: grid;
  gap: clamp(40px, 5vw, 76px);
}

.cascade__item {
  --panel: min(100%, 82%);
  --free: calc(100% - var(--panel));
  width: var(--panel);
  display: grid;
  grid-template-columns: minmax(0, 56%) minmax(0, 1fr);
  gap: clamp(26px, 3vw, 52px);
  align-items: center;
}

/* The cascade itself: each block starts further right than the one above it, stepped
   across whatever room is actually left over, so the last one can never run past the
   edge however narrow the window gets. */
.cascade__item:nth-child(1) { margin-left: 0; }
.cascade__item:nth-child(2) { margin-left: calc(var(--free) * 0.334); }
.cascade__item:nth-child(3) { margin-left: calc(var(--free) * 0.667); }
.cascade__item:nth-child(4) { margin-left: var(--free); }

.cascade__shot { margin: 0; }
.cascade__shot img {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 16px;
  background: var(--navy-lift);
  box-shadow: 0 22px 50px rgba(2, 8, 14, 0.45);
}
/* a stock photograph on a page about our own work has to say so */
.cascade__shot figcaption {
  margin-top: 13px;
  font-size: 16px;
  color: var(--white);
  opacity: 0.72;
}

.cascade__copy {
  color: var(--white);
  text-shadow: 0 2px 20px rgba(2, 8, 14, 0.6), 0 1px 3px rgba(2, 8, 14, 0.4);
}
.cascade__num {
  font-family: 'Anton', sans-serif;
  font-size: 21px;
  letter-spacing: 0.1em;
  color: var(--blue);
}
.cascade__item h3 {
  margin-top: 15px;
  font-size: clamp(38px, 4vw, 64px);
  line-height: 1;
}
.cascade__copy > p:not(.cascade__num) {
  margin-top: 18px;
  color: var(--white);
  font-size: 20px;
  line-height: 1.58;
}

.pills {
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.pills li {
  border-radius: var(--radius-pill);
  padding: 10px 21px;
  font-size: 17px;
  color: var(--white);
  box-shadow: inset 0 0 0 1px rgba(201, 220, 234, 0.3);
  transition: box-shadow 220ms var(--ease-out), transform 220ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .pills li:hover {
    box-shadow: inset 0 0 0 1px var(--blue);
    transform: translateY(-2px);
  }
}

/* The entrance: each stage arrives as you reach it, so the order you read them in is
   the order of the build. The picture settles, then the copy comes up line by line. */
.cascade__item.rise .cascade__shot {
  opacity: 0;
  transform: translate3d(0, 34px, 0);
  transition: opacity 700ms var(--ease-out), transform 700ms var(--ease-out);
}
.cascade__item.rise .cascade__shot img {
  transform: scale(1.05);
  transition: transform 1100ms var(--ease-out);
}
/* The copy enters on a keyframe rather than a transition, so the stagger delays stay
   out of the way of the hover response below. */
.cascade__item.rise:not(.is-in) .cascade__copy > * { opacity: 0; }
.cascade__item.rise.is-in .cascade__copy > * {
  animation: copy-in 620ms var(--ease-out) both;
}
.cascade__item.rise.is-in .cascade__copy > :nth-child(1) { animation-delay: 150ms; }
.cascade__item.rise.is-in .cascade__copy > :nth-child(2) { animation-delay: 230ms; }
.cascade__item.rise.is-in .cascade__copy > :nth-child(3) { animation-delay: 310ms; }
.cascade__item.rise.is-in .cascade__copy > :nth-child(4) { animation-delay: 390ms; }
@keyframes copy-in {
  from { opacity: 0; transform: translate3d(0, 26px, 0); }
  to   { opacity: 1; transform: none; }
}

.cascade__item.rise.is-in .cascade__shot { opacity: 1; transform: none; }
.cascade__item.rise.is-in .cascade__shot img { transform: none; }

/* The response to a pointer. `translate` and `scale` are used rather than `transform`
   so they compose with the drift and the entrance instead of fighting them: lift under
   the cursor, press in on the click, and the parts answer a beat apart so it reads as
   something physical rather than a state swap. */
.cascade__copy > * { transition: translate 190ms var(--ease-out), scale 190ms var(--ease-out); }
.cascade__copy { transition: translate 220ms var(--ease-out), text-shadow 260ms ease; }

@media (hover: hover) and (pointer: fine) {
  .cascade__copy:hover {
    translate: 0 -6px;
    text-shadow: 0 10px 34px rgba(2, 8, 14, 0.75), 0 1px 3px rgba(2, 8, 14, 0.5);
  }
  .cascade__copy:hover .cascade__num { translate: 5px 0; }
  .cascade__copy:hover h3 { scale: 1.015; transition-delay: 40ms; }
  .cascade__copy:hover > p:not(.cascade__num) { translate: 0 -2px; transition-delay: 70ms; }
  .cascade__copy:hover .pills li { translate: 0 -2px; }
  .cascade__copy:hover .pills li:nth-child(2) { transition-delay: 40ms; }
  .cascade__copy:hover .pills li:nth-child(3) { transition-delay: 80ms; }
  .cascade__copy:hover .pills li:nth-child(4) { transition-delay: 120ms; }
  .cascade__copy:hover .pills li:nth-child(5) { transition-delay: 160ms; }
  .cascade__copy:active { translate: 0 -1px; scale: 0.994; }
  .cascade__copy:active h3 { scale: 1; }
}
.cascade__copy .pills li { transition: box-shadow 220ms var(--ease-out), translate 190ms var(--ease-out); }

/* And it keeps hovering: the copy drifts against the picture as the block crosses the
   viewport, so it reads as floating rather than pinned to it. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .cascade__copy {
      will-change: transform;
      animation: copy-hover linear both;
      animation-timeline: view();
      animation-range: entry 10% exit 90%;
    }
    @keyframes copy-hover {
      from { transform: translate3d(0, 34px, 0); }
      to   { transform: translate3d(0, -34px, 0); }
    }
    /* the drift owns the transform once the entrance has finished with it */
    .cascade__item.rise.is-in .cascade__copy > * { transform: none; }
  }
}

@media (prefers-reduced-motion: reduce) {
  .cascade__item.rise .cascade__shot,
  .cascade__item.rise .cascade__shot img,
  .cascade__item.rise .cascade__copy,
  .cascade__item.rise .cascade__copy > *,
  .cascade__item.rise.is-in .cascade__copy > * {
    opacity: 1;
    transform: none;
    translate: none;
    scale: none;
    transition: none;
    animation: none;
  }
}

@media (max-width: 1080px) {
  .cascade__item { width: 100%; grid-template-columns: minmax(0, 1fr); }
  .cascade__item:nth-child(n) { margin-left: 0; }
}

/* ------------------------------ the stack ------------------------------ */

.stack-band .work__head { max-width: 860px; }
.stack-band .work__head h2 { font-size: clamp(34px, 4.6vw, 68px); }
.stack-band .work__head h2 em { font-style: normal; color: var(--blue); }

.stack {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(24px, 3vw, 52px) clamp(28px, 4vw, 72px);
  align-items: start;
}
.stack__group:first-child { grid-row: span 2; }
.stack__group h3 {
  padding-bottom: 16px;
  border-bottom: 1px solid var(--rule);
  font-size: 17px;
  letter-spacing: 0.14em;
  color: var(--mist-dim);
}
.stack__group ul { margin: 0; padding: 0; list-style: none; }

/* A row is the mark and the name only. What the tool is for sits beside it and
   arrives when the row is hovered or focused, so the list reads as a list first. */
.stack__group li {
  display: flex;
  align-items: center;
  gap: clamp(13px, 1.5vw, 24px);
  padding: 20px 0;
  border-bottom: 1px solid var(--rule);
  border-radius: 10px;
  transition: background-color 240ms ease;
}
.stack__group li > .logo,
.stack__group li > .logo-pair { flex: 0 0 auto; }
.stack__group b {
  flex: 0 0 auto;
  font-family: 'Anton', sans-serif;
  font-weight: 400;
  font-size: clamp(32px, 3.2vw, 48px);
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: -0.005em;
  color: var(--white);
}
.stack__why {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--mist);
  font-size: 18px;
  line-height: 1.5;
  opacity: 0;
  translate: -10px 0;
  transition: opacity 280ms var(--ease-out), translate 280ms var(--ease-out);
}

.stack__group li:hover,
.stack__group li:focus-visible {
  background-color: rgba(201, 220, 234, 0.04);
}
.stack__group li:hover .stack__why,
.stack__group li:focus-visible .stack__why {
  opacity: 1;
  translate: 0 0;
}
.stack__group li:focus-visible { outline: 2px solid var(--blue); outline-offset: 4px; }

/* no pointer to hover with, so the descriptions simply stay */
@media (hover: none) {
  .stack__why { opacity: 1; translate: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .stack__why { transition: none; translate: 0 0; }
}

/* ---------------------------- in every build --------------------------- */

.features {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: clamp(30px, 4.6vw, 84px);
  align-items: start;
}
.features h2 { font-size: clamp(32px, 4.2vw, 60px); line-height: 0.96; }
.features h2 em { font-style: normal; color: var(--blue); }

.feature-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 clamp(24px, 3vw, 48px);
}
.feature-list li {
  padding: 24px 0;
  border-top: 1px solid var(--rule);
}
.feature-list h3 { font-size: 19px; line-height: 1.25; letter-spacing: 0; }
.feature-list p { margin-top: 8px; color: var(--mist); font-size: 15.5px; }

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

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

@media (max-width: 860px) {
  .feature-list { grid-template-columns: minmax(0, 1fr); }
}

/* --------------------- how page: shots and tech marks ------------------- */

/* The marks are vendored SVGs in src/img/logos, drawn as masks so they take the
   page's own colour rather than five competing brand colours. */
.logo,
.logo-pair { display: inline-flex; align-items: center; gap: 8px; }
.logo {
  width: 44px;
  height: 44px;
  background-color: var(--mist);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  transition: transform 220ms var(--ease-out);
}
/* Each mark in its own brand colour, Bradley's call. Apple's is black, which cannot
   sit on navy, so it takes the white its own guidance allows on a dark ground. */
.logo--swift {
  -webkit-mask-image: url('../img/logos/swift.svg');
  mask-image: url('../img/logos/swift.svg');
  background-color: #f05138;
}
.logo--react {
  -webkit-mask-image: url('../img/logos/react.svg');
  mask-image: url('../img/logos/react.svg');
  background-color: #61dafb;
}
.logo--laravel {
  -webkit-mask-image: url('../img/logos/laravel.svg');
  mask-image: url('../img/logos/laravel.svg');
  background-color: #ff2d20;
}
.logo--apple {
  -webkit-mask-image: url('../img/logos/apple.svg');
  mask-image: url('../img/logos/apple.svg');
  background-color: var(--white);
}
.logo--android {
  -webkit-mask-image: url('../img/logos/android.svg');
  mask-image: url('../img/logos/android.svg');
  background-color: #3ddc84;
}
.logo--expo {
  -webkit-mask-image: url('../img/logos/expo.svg');
  mask-image: url('../img/logos/expo.svg');
  /* Expo's mark is near black, so it takes white on a dark ground, as Apple's does */
  background-color: var(--white);
}
.logo--vercel {
  -webkit-mask-image: url('../img/logos/vercel.svg');
  mask-image: url('../img/logos/vercel.svg');
  background-color: var(--white);
}
.logo--supabase {
  -webkit-mask-image: url('../img/logos/supabase.svg');
  mask-image: url('../img/logos/supabase.svg');
  background-color: #3fcf8e;
}

.stack__group li { grid-template-columns: minmax(0, 1fr); }
.stack__group li > .logo,
.stack__group li > .logo-pair { margin-bottom: 2px; }
@media (hover: hover) and (pointer: fine) {
  .stack__group li:hover .logo { transform: scale(1.08); }
}

.features__shot { margin: clamp(28px, 3.4vw, 46px) 0 0; }
.features__shot img {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 16px;
}
.features__shot figcaption {
  margin-top: 10px;
  font-size: 13px;
  color: var(--mist-dim);
}

/* ---------------------- apps page: the demo player --------------------- */

/* the name and its button share a line, and wrap onto two when they must */
.card__title {
  margin-top: 12px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 18px;
}
.card__title h3 { margin-top: 0; }

.btn--watch {
  padding: 12px 24px;
  font-size: 14.5px;
  background: transparent;
  color: var(--white);
  box-shadow: inset 0 0 0 1px rgba(201, 220, 234, 0.34), 0 8px 20px rgba(2, 8, 14, 0.3);
}
.btn--watch::before {
  content: '';
  width: 0;
  height: 0;
  border-left: 9px solid var(--accent, var(--blue));
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  margin-right: 2px;
}
@media (hover: hover) and (pointer: fine) {
  .btn--watch:hover {
    background: transparent;
    box-shadow: inset 0 0 0 1px var(--accent, var(--blue)), 0 14px 30px rgba(2, 8, 14, 0.4);
  }
}

/* the dialog is sized from the video's own aspect, so the frame hugs it and there are
   no black bars either side of a portrait recording */
.player {
  width: min(94vw, calc(74dvh * 540 / 1168), 440px);
  max-height: 94dvh;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
}
.player::backdrop {
  background: rgba(4, 12, 20, 0.82);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.player__frame {
  display: grid;
  gap: 14px;
  color: var(--white);
}
.player__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.player__name {
  font-family: 'Anton', sans-serif;
  font-size: 22px;
  text-transform: uppercase;
  letter-spacing: 0.01em;
}
.player__close {
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  background: rgba(201, 220, 234, 0.12);
  box-shadow: inset 0 0 0 1px rgba(201, 220, 234, 0.26);
  transition: transform 190ms var(--ease-out), background-color 200ms ease;
}
.player__close svg {
  width: 18px;
  height: 18px;
  stroke: var(--white);
  fill: none;
  stroke-width: 1.8;
  stroke-linecap: round;
}
@media (hover: hover) and (pointer: fine) {
  .player__close:hover { background: rgba(201, 220, 234, 0.2); }
}
.player__close:active { transform: scale(0.93); }

.player__video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 540 / 1168;
  border-radius: 20px;
  background: #000;
  box-shadow: 0 40px 90px rgba(0, 0, 0, 0.6);
}
.player__note {
  font-size: 13.5px;
  color: var(--mist-dim);
}

/* it arrives rather than appearing, unless the viewer has asked it not to */
@media (prefers-reduced-motion: no-preference) {
  .player[open] { animation: player-in 280ms var(--ease-out) both; }
  @keyframes player-in {
    from { opacity: 0; transform: scale(0.97) translateY(8px); }
    to   { opacity: 1; transform: none; }
  }
}

@media (max-width: 860px) {
  .card__title { gap: 10px 14px; }
  .btn--watch { padding: 11px 20px; font-size: 14px; }
  .player { width: min(94vw, calc(68dvh * 540 / 1168)); }
  .player__name { font-size: 19px; }
}

/* ========================= the enquiry panel ==========================
   Opened by any "Let's build your app" button. It drops from under the
   fixed nav, so it is in reach wherever the reader has got to.
   ===================================================================== */

.enquiry {
  position: fixed;
  inset: 72px 0 auto 0;
  z-index: 19;
  max-height: calc(100dvh - 72px);
  overflow-y: auto;
  background: var(--navy-deep);
  box-shadow: 0 30px 70px rgba(2, 8, 14, 0.6);
  border-bottom: 1px solid var(--rule);
}
.enquiry[hidden] { display: none; }

@media (prefers-reduced-motion: no-preference) {
  .enquiry:not([hidden]) { animation: enquiry-drop 300ms var(--ease-out) both; }
  @keyframes enquiry-drop {
    from { opacity: 0; transform: translateY(-14px); }
    to   { opacity: 1; transform: none; }
  }
}

.enquiry__inner {
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(22px, 2.6vw, 34px) var(--gutter) clamp(24px, 3vw, 38px);
}
.enquiry__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: clamp(16px, 2vw, 26px);
}
.enquiry__head h2 {
  font-size: clamp(26px, 3vw, 42px);
  line-height: 1;
}
.enquiry__close {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  background: rgba(201, 220, 234, 0.12);
  box-shadow: inset 0 0 0 1px rgba(201, 220, 234, 0.26);
  transition: transform 190ms var(--ease-out), background-color 200ms ease;
}
.enquiry__close svg {
  width: 18px; height: 18px;
  stroke: var(--white); fill: none; stroke-width: 1.8; stroke-linecap: round;
}
@media (hover: hover) and (pointer: fine) {
  .enquiry__close:hover { background: rgba(201, 220, 234, 0.2); }
}
.enquiry__close:active { transform: scale(0.93); }

.enquiry__form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(14px, 1.7vw, 22px) clamp(20px, 2.6vw, 36px);
}

/* label above the input, hint and error below it: never a placeholder as a label */
.field { display: grid; gap: 8px; margin: 0; }
.field--wide { grid-column: 1 / -1; }
.field label {
  font-size: 14.5px;
  font-weight: 500;
  color: var(--white);
}
.field input,
.field textarea,
.field select {
  width: 100%;
  padding: 13px 16px;
  font-family: inherit;
  font-size: 16px;
  color: var(--white);
  background: rgba(201, 220, 234, 0.06);
  border: 0;
  border-radius: 12px;
  box-shadow: inset 0 0 0 1px rgba(201, 220, 234, 0.3);
  transition: box-shadow 200ms var(--ease-out), background-color 200ms ease;
}
.field textarea { resize: vertical; min-height: 96px; line-height: 1.5; }
.field select { appearance: none; cursor: pointer; }
.field input:hover,
.field textarea:hover,
.field select:hover { background: rgba(201, 220, 234, 0.09); }
.field input:focus-visible,
.field textarea:focus-visible,
.field select:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
  box-shadow: inset 0 0 0 1px var(--blue);
}
.field__hint { font-size: 13.5px; color: var(--mist); }
.field__error {
  font-size: 13.5px;
  color: #ff8d7a;
  min-height: 0;
}
.field__error:empty { display: none; }
.field[data-invalid] input,
.field[data-invalid] textarea,
.field[data-invalid] select { box-shadow: inset 0 0 0 1px #ff8d7a; }

.enquiry__foot {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 24px;
  margin-top: 6px;
}
.enquiry__state {
  font-size: 14.5px;
  color: var(--mist);
  max-width: 48ch;
}
.enquiry__state:empty { display: none; }
.enquiry__state[data-tone="warn"],
.enquiry__state[data-tone="good"] {
  color: var(--white);
  padding: 12px 16px;
  border-radius: 10px;
}
.enquiry__state[data-tone="warn"] {
  background: rgba(255, 141, 122, 0.12);
  box-shadow: inset 0 0 0 1px rgba(255, 141, 122, 0.45);
}
.enquiry__state[data-tone="good"] {
  background: rgba(66, 181, 247, 0.12);
  box-shadow: inset 0 0 0 1px rgba(66, 181, 247, 0.45);
}
.btn[disabled] { opacity: 0.6; cursor: default; }

@media (max-width: 760px) {
  .enquiry__form { grid-template-columns: minmax(0, 1fr); }
  .enquiry { inset: 72px 0 auto 0; }
}

/* the honeypot: a field only a bot fills in, kept out of sight and out of the tab order */
.enquiry__trap {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.enquiry__state a {
  color: var(--white);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
@media (hover: hover) and (pointer: fine) {
  .enquiry__state a:hover { text-decoration-thickness: 2px; }
}
