/* ==========================================================================
   Components — reusable across every page.
   Contents:
     1. Site header & navigation
     2. Motif (topographic texture)
     3. Section intro, rule
     4. Buttons: .btn, .tag-link, .cta-row
     5. Card grid, case card, frame card
     6. Conveyor
     7. Site footer & social links
   ========================================================================== */


/* 1. Site header & navigation
   ------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background: var(--color-header-bg);
  transition: box-shadow var(--dur-base) var(--ease-standard);
}
.site-header.is-scrolled { box-shadow: var(--shadow-header); }

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  height: var(--header-h);
}

.site-logo {
  display: block;
  flex-shrink: 0;
  line-height: 0;
}
.site-logo img {
  height: var(--logo-h);
  width: auto;
}

.site-nav__list {
  display: flex;
  margin-inline-end: calc(var(--nav-link-pad-x) * -1); /* optical: last label aligns to the container edge */
}

.site-nav__link {
  position: relative;
  display: block;
  padding: var(--space-3) var(--nav-link-pad-x);
  font-size: var(--text-nav);
  font-weight: var(--weight-bold);
  line-height: var(--leading-none);
  color: var(--color-nav);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-standard);
}
.site-nav__link::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: var(--nav-indicator-h);
  background: var(--color-accent);
  transform: scaleX(0);
  transition: transform var(--dur-base) var(--ease-out);
}
.site-nav__link:hover { color: var(--color-nav-hover); }
.site-nav__link[aria-current="page"] { color: var(--color-nav-active); }
.site-nav__link[aria-current="page"]::after { transform: scaleX(1); }

.site-nav__toggle { display: none; }

/* Mobile: menu button + drop-down panel (only when JS is available) */
@media (max-width: 47.99em) {
  .js .site-nav__toggle {
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    margin-inline-end: calc(var(--space-2) * -1);
    padding: 0;
    border: 0;
    background: none;
    color: var(--color-ink);
  }

  .site-nav__toggle-bars,
  .site-nav__toggle-bars::before,
  .site-nav__toggle-bars::after {
    display: block;
    width: 1.5rem;
    height: 2px;
    background: currentColor;
    transition: transform var(--dur-base) var(--ease-out), opacity var(--dur-fast) var(--ease-standard);
  }
  .site-nav__toggle-bars { position: relative; }
  .site-nav__toggle-bars::before,
  .site-nav__toggle-bars::after { content: ""; position: absolute; left: 0; }
  .site-nav__toggle-bars::before { transform: translateY(-7px); }
  .site-nav__toggle-bars::after  { transform: translateY(7px); }

  [aria-expanded="true"] .site-nav__toggle-bars { background: transparent; }
  [aria-expanded="true"] .site-nav__toggle-bars::before { transform: rotate(45deg); background: var(--color-ink); }
  [aria-expanded="true"] .site-nav__toggle-bars::after  { transform: rotate(-45deg); background: var(--color-ink); }

  .js .site-nav__list {
    position: absolute;
    inset: 100% 0 auto 0;
    z-index: var(--z-overlay);
    flex-direction: column;
    margin: 0;
    padding: var(--space-2) var(--gutter) var(--space-6);
    background: var(--color-header-bg);
    box-shadow: var(--shadow-header);
    visibility: hidden;
    opacity: 0;
    transform: translateY(calc(var(--space-2) * -1));
    transition:
      opacity var(--dur-base) var(--ease-out),
      transform var(--dur-base) var(--ease-out),
      visibility 0s linear var(--dur-base);
  }
  .js .site-nav[data-open] .site-nav__list {
    visibility: visible;
    opacity: 1;
    transform: none;
    transition-delay: 0s;
  }

  .js .site-nav__link {
    display: inline-block;
    padding: var(--space-4) 0;
    font-size: var(--text-lg);
  }

  /* No-JS fallback: links wrap under the logo */
  html:not(.js) .site-header__inner { height: auto; flex-wrap: wrap; padding-block: var(--space-4); }
  html:not(.js) .site-nav__list { flex-wrap: wrap; margin-inline-start: calc(var(--nav-link-pad-x) * -1); }
}


/* 2. Motif — topographic contour texture
   Applied as a mask so its colour is a token (--motif-color).
   ------------------------------------------------------------------------- */

.has-motif {
  position: relative;
  isolation: isolate;
}
.has-motif::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: var(--z-below);
  pointer-events: none;
  background-color: var(--motif-color, var(--color-motif));
  -webkit-mask-image: var(--motif-image);
          mask-image: var(--motif-image);
  -webkit-mask-size: var(--motif-size) auto;
          mask-size: var(--motif-size) auto;
  -webkit-mask-repeat: repeat;
          mask-repeat: repeat;
  -webkit-mask-position: var(--motif-position, 50% 0);
          mask-position: var(--motif-position, 50% 0);
}


/* Background video — the page backdrop: a constant ambient video fixed behind
   all content (see bg-video.js). Sections are transparent over it by default;
   .section--veil tints it, .section--solid covers it. */

.bg-video {
  position: fixed;
  inset: 0;
  z-index: var(--z-backdrop);
  overflow: hidden;
  pointer-events: none;
  background-color: var(--color-bg);
}
.bg-video video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity var(--_fade, 0s) linear;
}
.bg-video video.is-hidden { opacity: 0; }


/* 3. Section intro, rule
   ------------------------------------------------------------------------- */

.section-intro {
  max-width: var(--container-narrow);
  margin-inline: auto;
  text-align: center;
}
.section-intro > * + * { margin-block-start: var(--intro-gap); }
/* A section heading can open the page it introduces — same treatment as the
   card titles: no link colour, underline only on hover. */
.section-intro h2 a {
  color: inherit;
  text-decoration: none;
}
.section-intro h2 a:hover {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
.section-intro > p {
  max-width: var(--measure);
  margin-inline: auto;
  font-size: var(--text-lg);
}

.rule {
  width: min(100%, var(--container-narrow));
  height: var(--border-heavy);
  margin-inline: auto;
  border: 0;
  background: var(--color-rule);
}


/* 4. Buttons
   ------------------------------------------------------------------------- */

/* Solid rectangular button — primary action inside cards and forms */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0.95em 1.7em 0.85em;
  white-space: nowrap;
  border: 0;
  border-radius: var(--radius-control);
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font-family: var(--font-label);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-none);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  text-decoration: none;
  /* Lifted like the field tag, without its bevel. */
  box-shadow: var(--shadow-tag);
  transition:
    background-color var(--dur-fast) var(--ease-standard),
    transform var(--dur-instant) var(--ease-standard);
}
.btn:hover {
  background: var(--color-accent-deep);
  box-shadow: var(--shadow-tag-hover);
}
.btn:active { transform: translateY(1px); }

/* Tag link — the tilted 3D field tag. Signature CTA; use at most once per section. */
.tag-link {
  position: relative;
  display: inline-block;
  padding: 0.95em 1.7em 0.85em;
  border-radius: var(--radius-control);
  background: linear-gradient(175deg, var(--color-accent-light), var(--color-accent) 55%);
  color: var(--color-accent-contrast);
  font-family: var(--font-label);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-none);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  text-decoration: none;
  text-shadow: 0 1px 1px rgb(0 0 0 / 0.2);
  white-space: nowrap;
  transform:
    perspective(var(--tag-perspective))
    rotateX(var(--tag-rotate-x))
    rotateY(var(--tag-rotate-y))
    rotate(var(--tag-tilt));
  box-shadow:
    calc(var(--tag-thickness) * 0.4) var(--tag-thickness) 0 var(--color-accent-deep),
    var(--shadow-tag);
  transition:
    transform var(--dur-slow) var(--ease-out),
    box-shadow var(--dur-slow) var(--ease-out);
}
.tag-link:hover,
.tag-link:focus-visible {
  transform: perspective(var(--tag-perspective)) rotateX(0deg) rotateY(0deg) rotate(0deg) translateY(-2px);
  box-shadow:
    0 calc(var(--tag-thickness) * 0.6) 0 var(--color-accent-deep),
    var(--shadow-tag-hover);
}
.tag-link:active {
  transform: perspective(var(--tag-perspective)) translateY(1px);
  box-shadow: 0 1px 0 var(--color-accent-deep), var(--shadow-tag);
  transition-duration: var(--dur-instant);
}

/* A line of copy followed by a tag — "Begin the Discovery  [START MAPPING]" */
.cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-5) var(--space-6);
  text-align: center;
}
.cta-row > p { font-size: var(--text-lg); }


/* 5. Cards
   ------------------------------------------------------------------------- */

.card-grid {
  display: grid;
  gap: var(--grid-gap);
  max-width: 30rem;
  margin-inline: auto;
}
@media (min-width: 64em) {
  .card-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    max-width: none;
  }
}
@media (min-width: 64em) {
  .card-grid--two {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    max-width: 62rem;
  }
}

/* Case card — white surface, no border; logo, artwork and name all link */
.case-card {
  --card-gap: var(--space-6);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--card-gap);
  height: 100%;
  padding: var(--card-gap);
  border-radius: var(--radius-surface);
  background: var(--color-bg);
  text-align: center;
  transition:
    transform var(--dur-slow) var(--ease-out),
    box-shadow var(--dur-slow) var(--ease-out);
}
@media (hover: hover) {
  .case-card:hover { transform: translateY(-4px); }
}

.case-card__mark {
  width: auto;
  /* --mark-scale lets a card trim its logo when the artwork runs large. It
     scales what's drawn, not the box: the reserved height stays the same on
     every card so the mosaics below share one line. Scaling the height instead
     pulled everything under a trimmed logo upwards. */
  height: clamp(5.5rem, 4.5rem + 3vw, 7.5rem);
  transform: scale(var(--mark-scale, 1));
}
/* The mark, artwork and name all open the case study. */
.case-card__link {
  display: block;
  width: 100%;
  transition: opacity var(--dur-fast) var(--ease-standard);
}
.case-card__link > * { margin-inline: auto; }
.case-card__link:hover { opacity: 0.9; }

.case-card__title a {
  color: inherit;
  text-decoration: none;
}
.case-card__title a:hover {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* Feature variant — one full-width frame that crossfades to a second image on
   hover or keyboard focus, with the client mark plated into its corner. Every
   preview card on the site uses this; the modifier stays so .case-card keeps
   its plain form for anything added later. */
.case-card--feature { --card-gap: var(--space-4); }

.case-card__frame {
  display: block; /* aspect-ratio needs a block box */
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--radius-media);
  background: var(--color-surface-muted);
}
/* Direct children only — the logo plate below is nested, and must not be
   stretched to fill the frame the way the project images are. */
.case-card__frame > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* The second frame stacks on the first and fades in — one controlled
   transition on an explicit trigger, never an automatic slideshow. */
.case-card__frame > img + img {
  opacity: 0;
  transition: opacity 350ms var(--ease-standard);
}
/* Hover only where hovering exists... */
@media (hover: hover) and (pointer: fine) {
  .case-card--feature:hover .case-card__frame > img + img { opacity: 1; }
}
/* ...focus wherever a keyboard does, whatever the pointer. */
.case-card--feature:focus-within .case-card__frame > img + img { opacity: 1; }
/* Touch: the primary image stands alone, and the second never downloads. */
@media (hover: none) and (pointer: coarse) {
  .case-card__frame > img + img { display: none; }
}
/* Motion contract: no crossfade, just the primary frame. */
@media (prefers-reduced-motion: reduce) {
  .case-card__frame > img + img { display: none; }
}

/* Logo plate — a white square notched into the frame’s top-right corner. It
   sits above both project images and does not take part in the crossfade, so
   the client mark stays put while the work behind it changes.
   --plate-weight normalises the logos by how heavy they *look*, not by
   matching their rendered boxes: a ring reads lighter than a solid block at
   the same size. */
.case-card__plate {
  position: absolute;
  inset-block-start: 0;
  inset-inline-end: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 23.5%;
  aspect-ratio: 1;
  /* Percentage padding resolves against the containing block’s width — the
     frame — never the element’s own. 4.2% of the frame is ~18% of a plate that
     is 23.5% of it, so the clear space around the logo stays proportional at
     every card width. */
  padding: 4.2%;
  background: var(--color-bg);
  /* A soft fall to the left and below — no hairline, which read as a hard dark
     rule against the imagery. Two stacked blurs: a tight one to hold the edge
     against pale photography, a wider one to give it some lift. */
  box-shadow:
    -2px 2px 3px -1px rgb(16 24 40 / 0.14),
    -6px 6px 14px -4px rgb(16 24 40 / 0.16);
}
.case-card__plate img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  transform: scale(var(--plate-weight, 1));
}

.case-card__media {
  width: min(100%, 17rem);
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-media);
}
.case-card__summary {
  max-width: 13em;
  font-size: var(--text-lg);
  line-height: var(--leading-normal);
  color: var(--color-text);
  text-wrap: balance;
}

/* Frame card — inverse surface with an inset hairline frame */
.frame-card {
  padding:
    calc(var(--frame-inset) + var(--space-7))
    calc(var(--frame-inset) + var(--space-6));
  border-radius: var(--radius-surface);
  background: var(--color-surface-inverse);
  color: var(--color-on-inverse);
  outline: var(--border-frame) solid var(--color-frame-line);
  outline-offset: calc(var(--frame-inset) * -1);
}
.frame-card__title {
  color: inherit;
  font-size: var(--text-2xl);
  letter-spacing: 0.01em;
  text-align: center;
}
.frame-card__body {
  margin-block-start: var(--space-6);
  font-size: var(--text-md);
  line-height: var(--leading-snug);
}
.frame-card__body > * + * { margin-block-start: var(--space-5); }

@media (min-width: 64em) {
  .frame-card { aspect-ratio: 1; }
  .frame-card__title {
    display: grid;
    place-items: center;
    min-height: calc(2em * var(--leading-tight)); /* one- and two-line titles share a baseline for the body */
  }
}


/* Portal card — a preview of a sister Dispatch property: image, name, tagline, blurb.
   Structure is shared; each property brings its own imagery. */

.portal-card {
  display: flex;
  flex-direction: column;
  height: 100%;
}
.portal-card__media {
  width: 100%;
  /* 4:3 to match the supplied previews. At 16/10 the cover crop ate the bottom
     of each one — the Find Motion button, the Back/Next row, the entry cards. */
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-media);
  box-shadow: var(--shadow-media);
}
/* The preview and the name both open the project. */
.portal-card__link {
  display: block;
  width: 100%;
  transition: opacity var(--dur-fast) var(--ease-standard);
}
.portal-card__link:hover { opacity: 0.9; }
.portal-card__title a {
  color: inherit;
  text-decoration: none;
}
.portal-card__title a:hover {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
/* The panel absorbs the card's leftover height so its CTA can sit on the floor.
   Cards are grid items and stretch to the tallest, so with the panel filling each
   one the three buttons land on a single baseline however long the copy runs. */
.portal-card__text {
  display: flex;
  flex: 1;
  flex-direction: column;
  margin-block-start: var(--space-5);
}
.portal-card__text > :first-child { margin-block-start: 0; }

.portal-card__cta {
  /* Pushed to the bottom of the panel; the shrink-wrap keeps it button-sized
     rather than stretching across the column. */
  margin-block-start: auto;
  align-self: flex-start;
  padding-block-start: 0.8em;
  padding-block-end: 0.7em;
  font-size: var(--text-xs);
}
/* A floor on the gap: the auto margin above collapses to nothing on whichever
   card has the longest copy, and without this the button would touch it. */
.portal-card__body { margin-block-end: var(--space-5); }

.portal-card__title {
  margin-block-start: var(--space-6);
  font-size: var(--text-xl);
}
.portal-card__tagline {
  margin-block-start: var(--space-2);
  font-size: var(--text-lg);
  /* Normal-size text, so navy rather than tan. */
  color: var(--color-text);
}
.portal-card__body {
  margin-block-start: var(--space-4);
  font-size: var(--text-md);
  line-height: var(--leading-snug);
}

/* 6. Conveyor — a 3D ring of work turning behind the hero.
   Pure CSS: the track rotates, cards sit around the circumference facing out.
   --count on the track = number of cards; --i on each card = its position.
   ------------------------------------------------------------------------- */

.conveyor { position: relative; }

.conveyor__stage {
  display: grid;
  width: 100%;
  height: var(--conveyor-stage-h);
  overflow: hidden;
  perspective: var(--conveyor-perspective);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 var(--conveyor-fade), #000 calc(100% - var(--conveyor-fade)), transparent);
          mask-image: linear-gradient(90deg, transparent, #000 var(--conveyor-fade), #000 calc(100% - var(--conveyor-fade)), transparent);
}

.conveyor__track {
  display: grid;
  place-self: center;
  margin: 0;
  padding: 0;
  transform-style: preserve-3d;
  animation: conveyor-turn var(--conveyor-duration) var(--ease-linear) infinite;
}
@keyframes conveyor-turn { to { rotate: y 1turn; } }

.conveyor__item {
  --_angle: calc(1turn / var(--count));
  grid-area: 1 / 1;
  place-self: center;
  width: var(--conveyor-card-w);
  aspect-ratio: var(--conveyor-card-ratio);
  overflow: hidden;
  border-radius: var(--conveyor-card-radius);
  box-shadow: var(--shadow-media);
  backface-visibility: hidden;
  transform:
    rotateY(calc(var(--i) * var(--_angle)))
    translateZ(calc(-1 * (0.5 * var(--conveyor-card-w) + 0.5em) / tan(0.5 * var(--_angle))));
}
.conveyor__item img {
  width: 100%;
  height: 100%;
  object-fit: cover; /* every card the same shape — crop in rather than letterbox */
  border-radius: inherit;
}

/* Reduced motion: keep the ring, but barely moving. */
@media (prefers-reduced-motion: reduce) {
  /* Stopped, not slowed. With no animation the ring rests on its authored
     frame — cards spread evenly across the stage — so the composition still
     reads as a carousel without any movement. */
  .conveyor__track { animation: none; }
}

/* Form — labels sit above their control; one column, tokenised spacing.
   ------------------------------------------------------------------------- */

.form {
  display: grid;
  gap: var(--space-5);
}

.field label {
  display: block;
  margin-block-end: var(--space-2);
  font-size: var(--text-md);
}

.field :is(input, textarea) {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  border: var(--border-hairline) solid var(--color-field-border);
  border-radius: var(--radius-sm);
  background: var(--color-field-bg);
  color: var(--color-text);
  font: inherit;
  font-size: var(--text-md);
  transition: border-color var(--dur-fast) var(--ease-standard);
}
.field :is(input, textarea):hover { border-color: var(--color-ink); }
.field textarea {
  min-height: 8rem;
  resize: vertical;
}

.form .btn { justify-self: start; }

/* Panel — an opaque block that lifts text off the page backdrop (contour video),
   so body copy keeps full contrast wherever it lands.
   ------------------------------------------------------------------------- */

.panel {
  background: var(--color-bg);
  border-radius: var(--radius-surface);
  padding: clamp(var(--space-5), 3vw, var(--space-7));
}
/* The panel's padding shouldn't eat into the reading measure. */
.prose.panel { max-width: calc(70ch + 2 * clamp(var(--space-5), 3vw, var(--space-7))); }


/* Long-form article text — case studies and similar reading.
   ------------------------------------------------------------------------- */

.prose {
  max-width: 70ch;
  font-size: var(--text-md);
  line-height: var(--leading-relaxed);
}
.prose > * + * { margin-block-start: var(--space-5); }
.prose :is(h2, h3) {
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
}
.prose :is(h2, h3) + * { margin-block-start: var(--space-4); }
.prose ul {
  margin-inline-start: var(--space-5);
  list-style: disc;
}
.prose li + li { margin-block-start: var(--space-3); }
.prose li::marker { color: var(--color-accent); }


/* Media — a single frame or a row of them, used between text blocks.
   ------------------------------------------------------------------------- */

.media-figure { margin: 0; }
.media-figure img {
  width: 100%;
  border-radius: var(--radius-media);
}
.media-figure figcaption {
  margin-block-start: var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-text-subtle);
}

.media-row {
  display: grid;
  gap: var(--grid-gap);
  align-items: center;
}
@media (min-width: 48em) {
  .media-row--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Filmstrip — a flat looping row of photos. Distinct from .conveyor, which is the
   hero's 3D ring. One card on mobile, three from 48em. Pure CSS, no JS.
   The track holds the photos twice; sliding exactly one copy's width lands the
   duplicate where the original started, so the loop has no seam. The extra
   half-gap in the keyframe accounts for the gap the duplicate set adds.
   ------------------------------------------------------------------------- */

.filmstrip {
  --filmstrip-visible: 1;
  --filmstrip-gap: var(--grid-gap);
  --filmstrip-duration: 60s;
  /* Container units let an item be an exact fraction of the strip, which a
     percentage can't do here — the track is max-content, so % would be circular. */
  container-type: inline-size;
  overflow: hidden;
}
@media (min-width: 48em) {
  .filmstrip { --filmstrip-visible: 3; }
}

.filmstrip__track {
  display: flex;
  gap: var(--filmstrip-gap);
  width: max-content;
  margin: 0;
  padding: 0;
  list-style: none;
  animation: filmstrip-slide var(--filmstrip-duration) var(--ease-linear) infinite;
}
@keyframes filmstrip-slide {
  to { transform: translateX(calc(-50% - var(--filmstrip-gap) / 2)); }
}

.filmstrip__item {
  flex: 0 0 auto;
  width: calc(
    (100cqi - (var(--filmstrip-visible) - 1) * var(--filmstrip-gap)) / var(--filmstrip-visible)
  );
}
.filmstrip__item img {
  display: block;
  width: 100%;
  border-radius: var(--radius-media);
}

/* Matches the hero ring: keep it moving, just far slower. */
@media (prefers-reduced-motion: reduce) {
  /* Stopped. The strip rests on its first photos; the rest stay in the DOM and
     remain reachable, so no content is lost. */
  .filmstrip__track { animation: none; }
}

.media-frame {
  width: min(100%, var(--container-narrow));
  margin-inline: auto;
}
.media-frame--tight { width: min(100%, 38rem); }

.media-frame :is(img, video) {
  width: 100%;
  border-radius: var(--radius-media);
  background: var(--color-surface-muted);
}
/* Stills keep their own proportions; film sits in a 16:9 window. */
.media-frame img { height: auto; }
.media-frame video { aspect-ratio: 16 / 9; object-fit: cover; }


/* Sketch/finished reveal — scroll wipes the finished work over the rough;
   dragging takes over. Geometry and colours ported from the original.
   ------------------------------------------------------------------------- */

.reveal {
  --pos: 0%;
  display: flex;
  justify-content: center;
  /* No padding of its own — the surrounding section sets the page rhythm. */
}
.reveal__frame {
  position: relative;
  width: 520px;
  max-width: 100%;
  overflow: hidden;
  cursor: ew-resize;
  touch-action: pan-y;
}
.reveal__base {
  display: block;
  width: 100%;
  height: auto;
  user-select: none;
}
.reveal__clip {
  position: absolute;
  inset: 0;
  overflow: hidden;
  clip-path: inset(0 calc(100% - var(--pos)) 0 0);
}
.reveal__clip img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  user-select: none;
}
.reveal__divider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--pos);
  width: 1px;
  background: rgb(255 255 255 / 0.6);
  transform: translateX(-50%);
  pointer-events: none;
}
.reveal__handle {
  position: absolute;
  top: 50%;
  left: 50%;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-round);
  background: #fff;
  transform: translate(-50%, -50%);
}
.reveal__range {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: ew-resize;
}
.reveal__frame:focus-within {
  outline: var(--focus-ring-width) solid var(--color-focus);
  outline-offset: var(--focus-ring-offset);
}

/* Scroll-flipped card — turns in 3D as its section passes through the viewport.
   Geometry, tones and breakpoints ported from the original.
   ------------------------------------------------------------------------- */

.card3d {
  --card-w: 360px;
  --card-h: 209px;
  position: relative;
  width: 100%;
  background: #c8c8c8;
}
.card3d__stage {
  display: flex;
  align-items: center;
  justify-content: center;
  padding-block: clamp(60px, 8vw, 120px);
}
.card3d__scene {
  position: relative;
  width: var(--card-w);
  height: var(--card-h);
}
.card3d__face {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  background: #000;
  backface-visibility: hidden;
  will-change: transform;
}
.card3d__face img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.card3d__shadow {
  position: absolute;
  inset: auto 5% -24px 5%;
  z-index: 0;
  height: 40px;
  border-radius: 50%;
  background: rgb(0 0 0 / 0.7);
  filter: blur(18px);
  transform-origin: center;
  will-change: transform, opacity;
  pointer-events: none;
}
@media (max-width: 48em) {
  .card3d {
    --card-w: calc(100vw - 80px);
    --card-h: calc((100vw - 80px) * 0.581);
  }
}
@media (max-width: 30em) {
  .card3d {
    --card-w: calc(100vw - 120px);
    --card-h: calc((100vw - 120px) * 0.581);
  }
}

/* A line of credit under a piece of media. */
.media-caption {
  margin-block-start: var(--space-5);
  font-size: var(--text-md);
  color: var(--color-text-subtle);
  text-align: center;
}


/* Pull quote with a portrait — client or founder testimonial.
   ------------------------------------------------------------------------- */

.quote {
  display: grid;
  gap: var(--space-6);
  justify-items: center;
  text-align: center;
}
@media (min-width: 48em) {
  .quote {
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: clamp(2rem, 5vw, 4rem);
    align-items: start;
    justify-items: start;
    text-align: start;
  }
}
.quote__portrait {
  width: clamp(6rem, 10vw, 9rem);
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--radius-round);
  background: var(--color-bg);
  border: var(--border-hairline) solid var(--color-hairline);
}
.quote__body { max-width: 60ch; }
.quote__body > * + * { margin-block-start: var(--space-5); }
.quote__body blockquote {
  margin: 0;
  font-size: var(--text-md);
  line-height: var(--leading-relaxed);
}
.quote__attribution { font-size: var(--text-md); }


/* Breathing word — one word in a heading swells and settles, golden-ratio sized.
   ------------------------------------------------------------------------- */

.brand-header {
  font-size: var(--text-3xl);
  font-weight: var(--weight-semibold);
  line-height: 1.25;
  text-align: center;
  text-wrap: initial; /* the line break is authored, not balanced */
}
.breathe {
  display: inline-block;
  line-height: 1;
  animation: breathe 4.8s infinite ease-in-out;
}
@keyframes breathe {
  0%, 100% { font-size: 1em; }
  50% { font-size: 1.618em; }
}


/* Phone mockup — app icons carrying the brand marks. Ported from the original;
   fixed geometry, so it keeps its proportions wherever it sits.
   ------------------------------------------------------------------------- */

.phone {
  position: relative;
  width: 185px;
  height: 350px;
  border-radius: 20px;
  background-color: #000;
  /* The tag shadow's tint and softness, doubled and thrown left — see
     --shadow-phone. Keeps the buttons' lighting without their small scale. */
  box-shadow: var(--shadow-phone);
  transform: rotate(-4deg);
}
/* Ground shadow */
.phone::before {
  content: "";
  position: absolute;
  bottom: -20px;
  left: 50%;
  width: 120px;
  height: 8px;
  background: radial-gradient(ellipse, rgb(0 0 0 / 0.25) 0%, rgb(0 0 0 / 0) 70%);
  filter: blur(6px);
  transform: translateX(-50%);
  pointer-events: none;
}
/* Left bezel shine */
.phone::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 3px;
  width: 4px;
  border-radius: 20px;
  background: linear-gradient(to bottom, rgb(255 255 255 / 0.18), rgb(255 255 255 / 0.02));
  pointer-events: none;
}

.phone__screen {
  position: absolute;
  inset: 4px 2px 2px 2px;
  border-radius: 20px;
  background: linear-gradient(167deg,
    rgb(246 239 230) 10%,
    rgb(22 49 88) 20%,
    rgb(22 49 88) 48%,
    rgb(210 176 129) 69%,
    rgb(246 239 230) 88%);
  box-shadow: inset 0 0 12px rgb(0 0 0 / 0.25);
}
/* Glass reflection */
.phone__screen::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 20px;
  background: linear-gradient(135deg, rgb(255 255 255 / 0.08) 0%, rgb(255 255 255 / 0) 40%);
  pointer-events: none;
}

.phone__camera {
  position: absolute;
  top: 4%;
  right: 50%;
  width: 80px;
  height: 20px;
  border-radius: 25px;
  background-color: rgb(22 49 88);
  transform: translate(50%, -50%);
  animation: phone-pulse 1s infinite ease-in-out;
}
.phone__camera::before {
  content: "";
  position: absolute;
  top: 2px;
  left: 5px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background-color: rgb(22 49 88);
}
.phone__camera::after {
  content: "";
  position: absolute;
  top: 6px;
  right: 5px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background-color: rgb(210 176 129);
}
@keyframes phone-pulse {
  0% { width: 80px; background-color: rgb(22 49 88); }
  10% { width: 55px; background-color: rgb(9 22 35); }
  25%, 100% { width: 80px; background-color: rgb(22 49 88); }
}

.phone__inner {
  position: absolute;
  top: 40%;
  right: 50%;
  margin-top: 10px;
  transform: translate(50%, -50%);
}
.phone__time {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 170px;
  height: 80px;
  font-size: 36px;
  font-weight: var(--weight-semibold);
  color: #fff;
  text-shadow: 0 2px 6px rgb(0 0 0 / 0.35);
}
.phone__apps {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  margin-top: 15px;
  margin-left: 5px;
}
.phone__app,
.phone__dock-app {
  position: relative;
  width: 35px;
  height: 35px;
  background-color: #fff;
}
/* The artwork sits on a layer of its own so --icon-scale can resize it without
   touching the white tile. Scaling the drawn image (rather than background-size)
   keeps `contain` doing the fitting, so marks that are taller than they are wide
   scale the same way as square ones. --icon-scale echoes --mark-scale above. */
.phone__app::before,
.phone__dock-app::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--icon);
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  /* Opaque artwork (the dock is all JPEG) would otherwise paint a hard square
     over the tile's rounded corners — transparent PNGs just never showed it. */
  border-radius: inherit;
  transform: scale(var(--icon-scale, 1));
}
.phone__app { margin-top: 14px; border-radius: 8px; }
.phone__dock-app { margin-top: 10px; border-radius: 8px; }
.phone__dock {
  position: absolute;
  bottom: -60px;
  display: flex;
  gap: 10px;
}
/* Page dots */
.phone__dock::before {
  content: "\25CF \25CF \25CF";
  position: absolute;
  top: -8px;
  right: 50%;
  font-size: 8px;
  color: #fff;
  transform: translateX(50%);
}

@media (prefers-reduced-motion: reduce) {
  .breathe, .phone__camera { animation: none; }
}

/* Stacking cards — each step sticks at the top of the stack as you scroll,
   the next sliding over it. Ported from the original; square corners here.
   ------------------------------------------------------------------------- */

.cards-stack { padding-block: 15dvh 0; }

.cards-stack__list {
  --stack-top: calc(50dvh - 20em);
  --sliver: 2.5em; /* how much of each card below stays visible */
  display: flex;
  flex-flow: column;
  align-items: center;
  justify-content: center;
  gap: 5em;
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}

.cards-stack__item {
  position: sticky;
  top: var(--stack-top);
  flex: none;
  width: 100%;
  max-width: 60em;
}
.cards-stack__item:nth-child(2) { top: calc(var(--stack-top) + var(--sliver)); }
.cards-stack__item:nth-child(3) { top: calc(var(--stack-top) + (var(--sliver) * 2)); }
.cards-stack__item:nth-child(4) { top: calc(var(--stack-top) + (var(--sliver) * 3)); }
.cards-stack__item:nth-child(5) { top: calc(var(--stack-top) + (var(--sliver) * 4)); }

.cards-stack-card {
  display: flex;
  flex-flow: column;
  gap: 2em;
  width: 100%;
  padding: 2.5em;
  border-radius: var(--radius-surface);
  background-color: var(--color-bg);
  color: #fff;
}
.cards-stack-card.is--ridge { background-color: #6c7d96; }
.cards-stack-card.is--brass { background-color: #d2b081; }
.cards-stack-card.is--navy { background-color: #163158; }
.cards-stack-card.is--sentinel { background-color: #8a896a; }
.cards-stack-card.is--midnight { background-color: #091623; }

.cards-stack-card__start {
  display: flex;
  align-items: baseline;
  gap: 0.75em;
}
.cards-stack-card__number {
  font-size: 3.15em;
  font-weight: var(--weight-medium);
  line-height: 1.1;
}
.cards-stack-card__h {
  margin: 0;
  font-size: 3.15em;
  font-weight: var(--weight-semibold);
  line-height: 1.1;
  letter-spacing: -0.04em;
  color: inherit;
}

.cards-stack-card__end {
  display: flex;
  flex-flow: column;
  gap: 1.5em;
}
.cards-stack-card__media-row {
  display: flex;
  align-items: center;
  justify-content: space-evenly;
}
.cards-stack-card__media {
  flex: 0 0 34%;
  min-width: 0;
  aspect-ratio: 4 / 3;
}
.cards-stack-card__media-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--radius-media);
}
.cards-stack-card__media-img.is--crop-right { object-position: right center; }

.cards-stack-card__services-p {
  margin: 0;
  font-size: 1.125em;
  font-weight: var(--weight-medium);
  line-height: 1.4;
  letter-spacing: -0.01em;
}

@media (max-width: 47.99em) {
  .cards-stack__list {
    --stack-top: calc(50dvh - 17em);
    --sliver: 2em;
  }
  .cards-stack__item { max-width: 25em; }
  .cards-stack-card { font-size: 0.8em; }
  .cards-stack-card__number,
  .cards-stack-card__h { font-size: 2.36em; }
  .cards-stack-card__media { flex-basis: 70%; }
  .cards-stack-card__media.is--mobile-hide { display: none; }
}


/* Pillar — a short film with a caption under it (the four brand pillars).
   ------------------------------------------------------------------------- */

.pillar { margin: 0; }
.pillar :is(video, img) {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--radius-media);
  background: var(--color-surface-muted);
}
.pillar figcaption {
  margin-block-start: var(--space-4);
  font-size: var(--text-md);
  /* Normal-size text, so navy rather than tan. */
  color: var(--color-text);
  text-align: center;
}

/* 7. Site footer & social links
   ------------------------------------------------------------------------- */

.site-footer {
  /* Half the old --space-7; the footer reads compact rather than as a band. */
  padding-block: var(--space-5);
  background: var(--color-bg);
}

.site-footer__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-6);
  text-align: center;
}
@media (min-width: 48em) {
  .site-footer__inner {
    flex-direction: row;
    justify-content: space-between;
    text-align: end;
  }
}

.site-footer__legal {
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  color: var(--color-text-subtle);
}

.social-links {
  display: flex;
  gap: var(--space-4);
}
.social-links a {
  display: grid;
  place-items: center;
  width: var(--social-size);
  height: var(--social-size);
  border-radius: var(--radius-round);
  background: var(--color-surface-inverse);
  color: var(--color-on-inverse);
  transition:
    background-color var(--dur-fast) var(--ease-standard),
    transform var(--dur-base) var(--ease-out);
}
.social-links a:hover {
  background: var(--color-accent);
  transform: translateY(-2px);
}
.social-links svg { width: var(--social-glyph); height: var(--social-glyph); }
