/* ============================================================
   shared.css — site chrome used by every page
   Tokens, reset, globals, navigation, layout scaffolding, footer.
   Values transcribed from the published Webflow stylesheet.
   ============================================================ */

:root {
  --black: black;
  --white: white;
  --gray-50-2: #fafafa;
  --gray-100: whitesmoke;
  --gray-200: #eee;
  --gray-300: #e0e0e0;
  --gray-400: #bdbdbd;
  --gray-500: #9e9e9e;
  --gray-600: #757575;
  --gray-700: #616161;
  --gray-800: #424242;
  --gray-900: #212121;
  --text--primary: #f5f5f7;
  --text--secondary: #8a8f98;
  --text--tertiary: #62666d;
  --highlight: #ff5a00;

  /* Measure: how wide a line of body copy is allowed to get, expressed in
     characters rather than pixels — so it holds at every type size.

     Inter's average prose character is 0.4745em, measured over 5,824
     characters of this site's own copy, so ~70 characters is 33.2em and
     34em is the round number just above it. Note this is NOT 70ch: the `ch`
     unit is the width of "0", which in Inter is 0.631em — a third wider than
     an average letter — so `max-width: 70ch` would set lines of about 93
     characters and miss the target entirely.

     Lines come out at 66 median, 73 at the 90th percentile and 76 at the
     longest, measured over 109 real line boxes. They run under the nominal
     70 because ragged-right wrapping never fills the last word in; a mean of
     70 would need the longest lines at ~80, which is WCAG 1.4.8's limit. */
  --measure: 34em;
}

/* ── Reset / base ─────────────────────────────────────────── */

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

html {
  height: 100%;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%;
}

body {
  min-height: 100%;
  margin: 0;
  background-color: #fff;
  color: #1a1b1f;
  font-family: Geist, sans-serif;
  font-size: 16px;
  font-weight: 400;
  line-height: 28px;
}

img {
  display: block;
  vertical-align: middle;
  max-width: 100%;
  border: 0;
}

strong { font-weight: bold; }

/* Webflow's base typography reset. Without these, browser defaults leak
   through — notably p's 1em top margin, which component classes only ever
   override the bottom of. */
h1, h2, h3, h4, h5, h6 { margin-bottom: 10px; font-weight: bold; }
h1 { margin-top: 20px; margin-bottom: 15px; font-size: 44px; font-weight: 400; line-height: 62px; }
h2 { margin-top: 10px; font-size: 36px; font-weight: 400; line-height: 50px; }
h3 { margin-top: 10px; font-size: 30px; font-weight: 400; line-height: 46px; }
h4 { margin-top: 10px; font-size: 24px; font-weight: 400; line-height: 38px; }
h5 { margin-top: 10px; font-size: 20px; font-weight: 500; line-height: 34px; }
h6 { margin-top: 10px; font-size: 16px; font-weight: 500; line-height: 28px; }
p { margin-top: 0; margin-bottom: 10px; }
ul { margin-top: 20px; margin-bottom: 20px; padding-left: 40px; list-style-type: disc; }
li { margin-bottom: 10px; }
blockquote {
  margin-top: 25px;
  margin-bottom: 25px;
  padding: 15px 30px;
  border-left: 5px solid #e2e2e2;
  font-size: 20px;
  line-height: 34px;
}
figure { margin-top: 25px; padding-bottom: 20px; }

a {
  display: inline-block;
  background-color: #0000;
  color: #1a1b1f;
  text-decoration: underline;
  transition: opacity .2s;
}
a:hover { color: #32343a; }
a:active { color: #43464d; }
a:active,
a:hover { outline: 0; }

/* External links get a trailing icon, as on the published site. */
a[target="_blank"]::after {
  content: '';
  display: inline-block;
  width: 1.1em;
  height: 1.1em;
  margin: -0.3em -0.2em -0.25em 0.05em;
  background-color: currentColor;
  -webkit-mask: url(../assets/external-link.svg) no-repeat 50% 50%;
  mask: url(../assets/external-link.svg) no-repeat 50% 50%;
  -webkit-mask-size: contain;
  mask-size: contain;
}
a.no-arrow[target="_blank"]::after,
figure a[target="_blank"]::after { content: none; }

.arrow-after::after {
  content: '';
  display: inline-block;
  width: 0.75em;
  height: 0.68em;
  margin: 0.1em 0 0 0.3em;
  background-color: currentColor;
  -webkit-mask: url(../assets/arrow-right.svg) no-repeat 50% 50%;
  mask: url(../assets/arrow-right.svg) no-repeat 50% 50%;
  -webkit-mask-size: contain;
  mask-size: contain;
}

/* ── Page transitions ─────────────────────────────────────────
   Home and a project page are separate documents, so the move between
   them was a hard cut. A cross-document view transition softens it in
   browsers that support one; the rest navigate as before.

   Timing measured from the reference recording (Stripe, 2026-09-27),
   frame by frame at 55fps: the incoming view takes ~360ms on a strongly
   decelerating curve — half the change in the first fifth of the time,
   then a long settle. The reference's upward travel is not used; see
   below.
   ──────────────────────────────────────────────────────────── */

@view-transition { navigation: auto; }

/* ── One picture per page, dissolved in place ──────────────────
   Each page is carried across as a single snapshot — header, band, pill,
   close button and page, all in one image — and the new one is dissolved
   in over the old one without moving.

   Why nothing is captured separately. For four rounds the header was lifted
   out of the page and carried on its own (first as nine parts, then as one
   band), and each round produced a new artefact at the edge of a separate
   capture: a frosted square behind the close button, tinted boxes around
   each part, and finally a white strip below the header. They share one
   cause. A snapshot taken from the outgoing page bakes whatever was behind
   the element — the frosted page — across its whole capture rectangle, and
   that rectangle never matches the element exactly: it is square where the
   element is round, and it reaches as far as the pill's shadow, 28px below
   the band, where the real band stops. The strip was LG's white page baked
   into that overflow, lingering over Nexus's black one until the old header
   faded out. The page's own snapshot has none of this. It holds the header
   AND everything behind it, so it is simply a faithful picture of the
   screen.

   Why the old one is held. The new page fades up over the old at full
   opacity, so every frame is exactly mix(old, new, α): nothing dims,
   nothing shows through, and the last frame is the new page itself. Where
   the two pages agree — the header between two projects in the same
   palette — the pixels are identical and do not change at all; where they
   differ, they dissolve.

   Why it no longer rises. The reference transition had the incoming page
   travel ~75px upward. With the header part of the page's picture, moving
   the page would move the header too, and pinning the header while the page
   moves is precisely what needed it carried separately. A dissolve on the
   same 360ms decelerating curve keeps the timing: most of the change in the
   first ~80ms, then a long settle. That curve also crosses the midpoint
   quickly, which matters between palettes: black becoming white is grey at
   exactly halfway, and the less time spent there the better. */

::view-transition-image-pair(root) { isolation: auto; }
::view-transition-old(root) {
  animation: none;
  mix-blend-mode: normal;
}
::view-transition-new(root) {
  animation: 360ms cubic-bezier(.2, .7, .2, 1) both page-enter;
  mix-blend-mode: normal;
}

@keyframes page-enter {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

/* Present to screen readers, absent to everyone else. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── Theme ────────────────────────────────────────────────────
   Webflow reuses the class name `.body` both as a text style on the
   home page AND on the <body> element of dark case studies, where
   `body.dark` inverts the page. Shared because both need it.
   ──────────────────────────────────────────────────────────── */

.body {
  width: 100%;
  margin-left: auto;
  margin-right: auto;
  color: var(--black);
  font-family: Geist, sans-serif;
  line-height: 170%;
}

body.dark {
  background-color: var(--black);
  color: var(--text--tertiary);
}

/* ── Navigation ───────────────────────────────────────────── */

.navigation {
  z-index: 1000;
  clear: none;
  display: flex;
  align-items: center;
  position: sticky;
  inset: 0 0% auto;
  margin-bottom: 0;
  padding: 30px 50px;
  color: var(--black);
}

/* The header's background: a progressive blur, no bar and no edge. What
   scrolls under the header is blurred and tinted most at the top of the
   window, and both fall away to nothing a little below the header's own
   line, so the page dissolves into it rather than meeting it. Two layers
   do it — a heavy blur that is gone by the middle, a light one that lasts
   to the bottom — because one blur can't change strength down its height;
   each is cut off by a gradient mask, and the tint fades with them.

   Both live on pseudo-elements behind the header's contents, not on the
   header itself. An element with a backdrop filter is a "backdrop root":
   any glass inside it — the section capsule and the menu that drops from
   it (css/glass-nav.css) — could then only blur the header's own layer,
   never the page, and the menu would show the text beneath it sharp. */
.navigation::before,
.navigation::after {
  content: "";
  position: absolute;
  inset: 0 0 -28px;
  z-index: -1;
  pointer-events: none;
}
.navigation::before {
  background: linear-gradient(to bottom, rgba(255, 255, 255, .45), rgba(255, 255, 255, 0));
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 45%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 45%, transparent 100%);
}
.navigation::after {
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 30%, transparent 70%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 30%, transparent 70%);
}

.navigation-items {
  flex: 1;
  display: flex;
  justify-content: space-between;
  align-items: center;
  max-width: 980px;
  margin-left: auto;
  margin-right: auto;
}

.logo-link {
  z-index: 1;
  position: relative;
  color: #333;
  text-decoration: none;
}
/* Only where the logo is a link (the case studies); on the home page it
   is plain, and does nothing under the pointer. */
a.logo-link:hover { opacity: .8; }
a.logo-link:active { opacity: .7; }

.logo-image { display: block; }
/* Scales with the glass capsule beside it: 48 → 38 → 36px tall. */
@media screen and (max-width: 767px) { .logo-image { width: auto; height: 13px; } }
@media screen and (max-width: 479px) { .logo-image { height: 12px; } }

.navigation-wrap {
  display: flex;
  align-items: center;
  margin-right: 0;
}

.link-8 {
  color: var(--gray-900);
  font-size: 14px;
  line-height: 150%;
  text-decoration: none;
}

/* ── Dark-page navigation ─────────────────────────────────────
   On dark pages the same fading blur, tinted black, with near-white type.
   ──────────────────────────────────────────────────────────── */

body.dark .navigation { color: var(--text--primary); }
body.dark .navigation::before {
  background: linear-gradient(to bottom, rgba(0, 0, 0, .7), rgba(0, 0, 0, 0));
}

/* Logo ships with black fills; force it to white deterministically. */
body.dark .logo-image { filter: brightness(0) invert(1); }

/* The external-link icon masks currentColor, so it follows along. */
body.dark .link-8 { color: var(--text--primary); }

/* ── Measure ──────────────────────────────────────────────────
   Body copy is capped to --measure wherever it appears. The case-study
   wrappers are sized for images — 980px, and 1312px in places — and the
   prose simply inherited that, so it was running at 122–127 characters a
   line against an optimum of 50–75 and WCAG's ceiling of 80. The images
   keep the full wrapper; only the reading does not.

   `.body` is scoped, because it is also the class on <body> itself and an
   unscoped rule would put the whole page in a 34em column. */

.paragraph_body,
.paragraph_body-2,
.paragraph_body-copy,
.paragraph_proj-brief,
.txt_uid_description,
.list-item { max-width: var(--measure); }

/* ── Layout scaffolding ───────────────────────────────────── */

.section {
  transform-style: preserve-3d;
  max-width: 100%;
  margin: 0 auto;
  padding-top: 60px;
  padding-bottom: 140px;
  padding-left: 0;
}

/* Nothing may scroll the page sideways.

   A case study is full of fixed-width mockups and deliberate bleeds, and
   below the width they were drawn for they used to push the document wider
   than the window. The header is `position: sticky`, which only sticks
   against its containing block — the body, which stays window-width and
   never spans the overflow — so a sideways scroll slid the whole header off
   the screen with the page under it. Measured on the LG page at 1112px: the
   document ran 133px wide and the header sat at left -133.

   `clip` rather than `hidden`: hidden would make each section a scroll
   container, and a sticky header inside a container that no longer scrolls
   drops back to where it started. Paired with an unset overflow-y, `clip` is
   the one value that clips the axis without creating that container — so
   this trims the bleed and leaves vertical stickiness alone. The overflows
   that carry real content are fixed at their source below, so this only ever
   catches the decorative ones. */
.section,
.section-hero { overflow-x: clip; }

.wrapper {
  display: block;
  opacity: 1;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
  max-width: 100%;
  margin-left: auto;
  margin-right: auto;
  padding-left: 4rem;
  padding-right: 4rem;
}

/* Modifiers on .wrapper itself — distinct from the .wrapper_980w ones
   below, and easy to miss because the class name is shared. */
.wrapper.margin-btm {
  margin-bottom: 140px;
  padding-bottom: 0;
}
.wrapper.padding-top { padding-top: 100px; }

.wrapper_980w {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  width: 100%;
  max-width: 980px;
  height: auto;
  margin-top: 0;
  margin-left: auto;
  margin-right: auto;
  overflow: visible;
}

.wrapper_980w.margin-btm {
  display: block;
  position: relative;
  align-items: center;
  height: auto;
  margin-bottom: 140px;
  margin-left: auto;
  margin-right: auto;
  padding-bottom: 0;
}
.wrapper_980w.margin-btm._40 { margin-bottom: 40px; }

.wrapper_980w.horizon {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  width: 100%;
  height: auto;
  margin-top: 0;
}
.wrapper_980w.horizon.margin {
  justify-content: space-between;
  margin-top: 0;
  margin-bottom: 40px;
}

.wrapper_980w.space-between {
  justify-content: space-between;
  width: 100%;
}
.wrapper_980w.space-between.margin {
  width: 100%;
  margin-bottom: 40px;
}

/* Webflow's container, used by the case-study hero grid. */
.w-container {
  max-width: 940px;
  margin-left: auto;
  margin-right: auto;
}

/* ── Footer ───────────────────────────────────────────────── */

.footer {
  display: block;
  justify-content: space-between;
  align-items: center;
  margin-left: 0;
  margin-right: 0;
  padding: 0 50px;
  border: 0px solid var(--gray-300);
}

.wrapper_footer {
  flex: 1;
  display: flex;
  justify-content: space-between;
  max-width: 980px;
  margin-left: auto;
  margin-right: auto;
  padding-top: 40px;
  padding-bottom: 60px;
}

.footer-links {
  display: flex;
  align-items: center;
  grid-column-gap: 40px;
  grid-row-gap: 40px;
  margin-right: 0;
}

.text_footer { color: var(--gray-600); }

.link-7 {
  color: var(--gray-800);
  font-size: 14px;
  line-height: 150%;
  text-decoration: none;
}

/* DEVIATION from the published site: on dark pages it leaves footer links
   at --gray-800 (#424242) on black — 2.1:1, well below AA. Raised to
   --text--secondary (6.5:1). Colour only; no effect on layout. */
body.dark .link-7 { color: var(--text--secondary); }

/* ── ≤ 991px ──────────────────────────────────────────────── */

@media screen and (max-width: 991px) {
  .navigation { padding: 25px 30px; }
  .navigation-items { background-color: #fff0; }
  .navigation-wrap { margin-right: 0; }

  .footer { padding-top: 40px; padding-bottom: 40px; }

  .wrapper {
    display: block;
    grid-column-gap: 16px;
    grid-row-gap: 16px;
    padding-left: 2rem;
    padding-right: 2rem;
    overflow: visible;
  }

  .wrapper_980w { width: 100%; }
  .wrapper_980w.margin-btm { margin-bottom: 140px; }
  .wrapper_980w.margin-btm._40 { width: 100%; margin-bottom: 40px; }
  .wrapper_980w.horizon { display: flex; flex-flow: wrap; width: 100%; }

  .w-container { max-width: 728px; }
}

/* ── ≤ 767px ──────────────────────────────────────────────── */

@media screen and (max-width: 767px) {
  .logo-link { padding-left: 0; }
  .navigation { padding: 20px 30px; }

  .footer {
    flex-direction: column;
    padding-left: 30px;
    text-align: center;
  }
  .footer-links { flex-flow: row; }
  .wrapper_footer { padding-top: 40px; }

  .wrapper_980w.margin-btm._40 { width: 100%; }
  .wrapper_980w.space-between,
  .wrapper_980w.space-between.margin { flex-flow: column; width: 100%; }
}

/* ── ≤ 479px ──────────────────────────────────────────────── */

@media screen and (max-width: 479px) {
  .navigation { padding-left: 20px; padding-right: 20px; }
  .navigation-items { background-color: #fff0; }

  .footer {
    display: block;
    flex-direction: column;
    padding-left: 20px;
    padding-right: 20px;
  }
  .footer-links { flex-flow: row; align-items: center; }
  .wrapper_footer { flex-flow: row; }

  .section {
    display: block;
    flex-direction: column;
    align-items: center;
    margin-bottom: 0;
    padding-top: 40px;
    padding-bottom: 100px;
    padding-left: 0;
    text-align: left;
  }

  .wrapper {
    margin-left: auto;
    margin-right: auto;
    padding-left: 1.5rem;
    padding-right: 1.5rem;
  }

  .wrapper_980w {
    flex-direction: column;
    width: 100%;
    max-width: none;
  }
  .wrapper_980w.margin-btm { margin-bottom: 40px; }
  .wrapper_980w.horizon { width: auto; }
  .wrapper_980w.space-between,
  .wrapper_980w.space-between.margin { flex-direction: column; }

  .w-container { max-width: none; }
}

/* The footer on the page's gutters (as .wrapper: 4rem, 2rem under 992px,
   1.5rem under 480px), so its text lines up with the sections above. */
.footer { padding-left: 4rem; padding-right: 4rem; }
@media screen and (max-width: 991px) { .footer { padding-left: 2rem; padding-right: 2rem; } }
@media screen and (max-width: 479px) { .footer { padding-left: 1.5rem; padding-right: 1.5rem; } }
