/* Lone1.io — Technology Advisory editorial scroll animation
   Reference: scroll-animations/technology-advisory
   All selectors are scoped under .ds-page or .ds-menu-overlay so
   they only affect the home page (which adds .ds-page to <body>'s
   .site wrapper). */

@import url('https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&display=swap');

    html, body { margin: 0; padding: 0; }
    /* Editorial palette tokens (--c-cream/--c-paper/--c-ink/--c-deep/--c-gold/
       --c-gold-soft/--c-line/--c-error) are defined globally in assets/css/app.css
       :root — do not redeclare. Only page-local vars belong here. */
    .ds-page {
      --header-hidden: 0;
      color: var(--c-ink);
      background: var(--c-cream);
      font-family: 'Inter', system-ui, sans-serif;
      font-weight: 400;
      letter-spacing: 0.01em;
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      position: relative;
    }
    .ds-page *,
    .ds-page *::before,
    .ds-page *::after { box-sizing: border-box; }

    /* ── HERO ──────────────────────────────────────────────────────── */
    .ds-page .hero {
      position: fixed;
      top: 0; left: 0; right: 0;
      width: 100%; height: 100vh;
      overflow: hidden;
      background: var(--c-cream);
      z-index: 1;
    }
    .ds-page .hero-spacer { width: 100%; height: 220vh; pointer-events: none; }
    .ds-page .hero-bg {
      position: absolute; inset: 0;
      display: grid;
      grid-template-columns: var(--cream-w, 50%) auto;
      pointer-events: none;
    }
    .ds-page .hero-bg .cream {
      background: color-mix(in oklab, var(--c-cream) calc((1 - var(--cream-fade, 0)) * 100%), var(--c-deep));
    }
    .ds-page .hero-bg .img-pane { position: relative; overflow: hidden; background: #2a2c30; }
    .ds-page .hero-bg .img-pane .img {
      position: absolute; inset: 0;
      overflow: hidden;
      background: #2a2c30;
      /* Initial clip — collapsed at bottom edge (video hidden until heroClipPath engages on load). Graph overwrites this with the animated polygon. */
      clip-path: polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%);
      will-change: clip-path;
    }
    .ds-page .hero-bg .img-pane .img video,
    .ds-page .hero-bg .img-pane .img img {
      width: 100%; height: 100%;
      object-fit: cover;
      object-position: 50% 35%;
      display: block;
    }
    /* Subtle bottom-weighted darken so the white hero-caption + tagline that
       sit over the lower portion of the video remain legible without dulling
       the upper half of the footage. Uses ::after on .img so it's clipped
       together with the video by the graph-driven clip-path reveal. */
    .ds-page .hero-bg .img-pane .img::after {
      content: '';
      position: absolute; inset: 0;
      pointer-events: none;
      background: linear-gradient(180deg,
        rgba(0,0,0,0) 0%,
        rgba(0,0,0,0) 45%,
        rgba(0,0,0,0.18) 75%,
        rgba(0,0,0,0.32) 100%);
    }
    /* ── HEADER ─────────────────────────────────────────────────── */
    .ds-page .hero-nav {
      position: fixed; top: 0; left: 0; right: 0;
      display: flex; align-items: center; justify-content: space-between;
      padding: 22px 28px;
      z-index: 999999; pointer-events: none;
      /* --header-bg-on: 0 at top of page, 1 once scrolled past 100px.
         Bg + blur fade in via opacity multiplier; border same. */
      background: rgba(239, 234, 224, calc(0.86 * var(--header-bg-on, 0)));
      backdrop-filter: blur(calc(14px * var(--header-bg-on, 0)));
      -webkit-backdrop-filter: blur(calc(14px * var(--header-bg-on, 0)));
      border-bottom: 1px solid rgba(37, 40, 45, calc(0.06 * var(--header-bg-on, 0)));
      transform: translateY(calc(var(--header-hidden, 0) * -110%));
      transition: transform 0.32s cubic-bezier(0.4, 0, 0.2, 1), background 0.2s ease, border-color 0.2s ease;
      will-change: transform;
      isolation: isolate;
    }
    .ds-page .hero-nav > * { pointer-events: auto; }

    /* Non-home pages (contact, about, blog, post, tag, author, etc.):
       force the cream header chrome to be opaque from page load so dark
       ink nav text stays readable when a page hero uses a dark image
       (e.g. contact-us). The home page keeps its scroll-driven fade-in
       via --header-bg-on; everywhere else we ignore that variable and
       paint a solid cream + blur backdrop with a subtle bottom hairline.
       Higher specificity (body class) beats the .ds-page variable
       formula above. */
    body:not(.home-template) .ds-page .hero-nav {
      background: rgba(239, 234, 224, 0.92);
      backdrop-filter: blur(14px);
      -webkit-backdrop-filter: blur(14px);
      border-bottom: 1px solid rgba(37, 40, 45, 0.08);
    }
    /* Force the right-hand link text ("Inquire", "hello@lone1.io",
       "Austin, TX") to render in ink on non-home pages. The home page's
       formula color-mixes between white (at top of page, --header-bg-on=0)
       and ink (after scroll), which on non-home pages would render white
       on a now-cream header. We pin them to ink directly. */
    body:not(.home-template) .ds-page .hero-nav-right .form,
    body:not(.home-template) .ds-page .hero-nav-right .phone {
      color: var(--c-ink);
    }
    .ds-page .hero-nav-left {
      display: flex; align-items: center; gap: 56px;
      color: var(--c-ink);
    }
    .ds-page .hero-logo {
      display: flex; align-items: center; gap: 14px;
      font-family: 'Inter', sans-serif; font-size: 16px; font-weight: 500;
      color: var(--c-ink); line-height: 1.15;
    }
    .ds-page .hero-logo .mark {
      width: 56px; height: 36px; color: var(--c-ink);
    }
    .ds-page .hero-logo .brand { font-weight: 500; }
    .ds-page .hero-logo .brand-l2 { font-weight: 500; }

    .ds-page .hero-nav-center {
      display: flex; align-items: center; gap: 36px; justify-content: center;
      font-size: 16px; color: var(--c-ink);
    }
    .ds-page .hero-nav-center button {
      display: inline-flex; align-items: center; gap: 10px;
      background: transparent; border: 0; padding: 8px 4px; margin: 0; cursor: pointer;
      font: inherit; color: inherit; font-weight: 500;
    }
    .ds-page .hero-nav-center .ico-menu {
      display: inline-flex; flex-direction: column; gap: 4px;
      width: 16px;
    }
    /* Menu icon — two horizontal bars. On hover, the top bar collapses
       from the right and the bottom bar collapses from the left, leaving
       a staggered offset shape that re-expands on mouse-out. Cubic-bezier
       gives a quick acceleration, slow settle. */
    .ds-page .hero-nav-center .ico-menu span {
      display: block; height: 1.5px; background: currentColor; width: 100%;
      transition: transform 0.32s cubic-bezier(0.4, 0, 0.2, 1);
    }
    .ds-page .hero-nav-center .ico-menu span:nth-child(1) { transform-origin: right center; }
    .ds-page .hero-nav-center .ico-menu span:nth-child(2) { transform-origin: left center; }
    .ds-page .hero-menu-trigger:hover .ico-menu span:nth-child(1) { transform: scaleX(0.55); }
    .ds-page .hero-menu-trigger:hover .ico-menu span:nth-child(2) { transform: scaleX(0.55); }
    /* Services chevron — idles at -2px translate so it sits centred on
       the cap line. On hover, it bobs DOWN (+2px) for a subtle invitation
       gesture. When the popover is open, rotates 180deg (chevron flips up).
       Hover-during-open keeps the rotated state. */
    .ds-page .hero-nav-center .ico-chev {
      display: inline-block; transform: translateY(-2px);
      transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
    }
    .ds-page .hero-services-trigger:hover .ico-chev {
      transform: translateY(2px);
    }
    .ds-page .hero-services-trigger[data-open="1"] .ico-chev,
    .ds-page .hero-services-trigger[data-open="1"]:hover .ico-chev {
      transform: translateY(-2px) rotate(180deg);
    }

    .ds-page .hero-nav-right {
      display: flex; align-items: center; gap: 14px; justify-content: flex-end;
      font-size: 16px; color: var(--c-ink);
    }
    .ds-page .hero-nav-right .form {
      color: color-mix(in oklab, #fff calc((1 - var(--header-bg-on, 0)) * 100%), var(--c-ink));
      text-decoration: none;
      display: inline-flex; align-items: center; gap: 4px;
      padding: 10px 4px;
    }
    .ds-page .hero-nav-right .form .arrow { font-size: 12px; }
    .ds-page .hero-nav-right .phone {
      display: inline-grid;
      grid-template-columns: auto auto;
      grid-template-rows: auto auto;
      column-gap: 8px;
      align-items: baseline;
      background: transparent; border: 0; padding: 8px 12px; margin: 0; cursor: pointer;
      font: inherit;
      color: color-mix(in oklab, #fff calc((1 - var(--header-bg-on, 0)) * 100%), var(--c-ink));
      text-align: left;
    }
    .ds-page .hero-nav-right .phone .phone-num {
      grid-column: 1; grid-row: 1; font-weight: 500;
    }
    .ds-page .hero-nav-right .phone .phone-chev {
      grid-column: 2; grid-row: 1;
      font-size: 11px; transform: translateY(-1px);
      transition: transform 0.2s ease;
    }
    .ds-page .hero-phone-trigger[data-open="1"] .phone-chev {
      transform: translateY(-1px) rotate(180deg);
    }
    .ds-page .hero-nav-right .phone .city {
      grid-column: 1 / span 2; grid-row: 2;
      font-size: 11px; opacity: 0.7; font-weight: 400;
    }
    .ds-page .hero-nav-right .cta {
      display: inline-flex; align-items: center; gap: 14px;
      background: var(--c-ink); color: #fff;
      padding: 14px 14px 14px 26px; border: 0;
      border-radius: 999px;
      font: inherit; font-weight: 500; font-size: 16px;
      cursor: pointer;
    }
    .ds-page .hero-nav-right .cta .cta-plus {
      width: 28px; height: 28px;
      display: inline-flex; align-items: center; justify-content: center;
      background: rgba(255,255,255,0.14);
      border-radius: 50%; font-size: 16px; font-weight: 300;
      line-height: 1;
    }

    /* ── POPOVERS (phone + services) ─────────────────────────────── */
    .ds-page .popover {
      position: absolute;
      background: var(--c-paper);
      border: 1px solid rgba(37, 40, 45, 0.12);
      border-radius: 18px;
      box-shadow: 0 24px 60px rgba(0,0,0,0.16), 0 4px 12px rgba(0,0,0,0.06);
      pointer-events: none;
      will-change: opacity, transform;
      z-index: 6;
    }
    .ds-page .phone-area {
      position: relative;
      display: inline-flex;
    }
    .ds-page .phone-popover {
      position: absolute;
      top: -27px;
      left: -14px;
      min-width: calc(100% + 28px);
      padding: 36px 16px 14px;
      border-radius: 0 0 22px 22px;
      overflow: hidden;
      clip-path: inset(0 0 calc((1 - var(--phone-open, 0)) * 100%) round 0 0 22px 22px);
      transition: clip-path 0.32s cubic-bezier(0.22, 0.8, 0.32, 1);
      z-index: 6;
    }
    .ds-page .phone-popover[data-open="1"] { pointer-events: auto; }
    .ds-page .hero-phone-trigger { opacity: calc(1 - var(--phone-open, 0)); }
    .ds-page .phone-popover .phone-row {
      display: block; padding: 10px 0;
      border-bottom: 1px solid rgba(37,40,45,0.08);
    }
    .ds-page .phone-popover .phone-row.primary { padding: 0 0 10px; }
    .ds-page .phone-popover .phone-row:last-child { border-bottom: 0; }
    .ds-page .phone-popover .phone-row .num {
      display: block; font-size: 16px; font-weight: 500; color: var(--c-ink);
    }
    .ds-page .phone-popover .phone-row .city {
      display: block; font-size: 11px; opacity: 0.6; margin-top: 2px;
    }

    /* Services backdrop — click-out-to-close. */
    .ds-page .services-backdrop {
      position: fixed; inset: 0;
      background: rgba(0,0,0,0.45);
      backdrop-filter: blur(14px);
      -webkit-backdrop-filter: blur(14px);
      opacity: var(--services-open, 0);
      pointer-events: none;
      transition: opacity 0.32s ease;
      z-index: 1000000;
    }
    .ds-page .services-backdrop[data-open="1"] { pointer-events: auto; }

    .ds-page .services-popover {
      position: fixed;
      top: 0; left: 16vw; right: 16vw;
      padding: 32px 32px 28px;
      border-radius: 0 0 22px 22px;
      overflow: hidden;
      clip-path: inset(0 0 calc((1 - var(--services-open, 0)) * 100%) round 0 0 22px 22px);
      transition: clip-path 0.36s cubic-bezier(0.22, 0.8, 0.32, 1);
      z-index: 1000001;
    }
    .ds-page .services-popover[data-open="1"] { pointer-events: auto; }
    .ds-page .hero-services-trigger { opacity: calc(1 - var(--services-open, 0)); }
    .ds-page .services-popover-head {
      display: flex; justify-content: space-between; align-items: center;
      font-weight: 500; font-size: 15px; color: var(--c-ink);
      margin-bottom: 18px;
    }
    .ds-page .services-popover-head .close-x { cursor: pointer; opacity: 0.8; }
    .ds-page .services-popover-grid {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 18px;
    }
    .svc-card {
      display: flex; flex-direction: column;
      padding: 10px 10px 14px;
      border-radius: 14px;
      background: transparent;
      transition: background 0.18s ease;
      cursor: pointer;
    }
    .ds-page .svc-card:hover { background: rgba(37,40,45,0.18); }
    .svc-card .svc-img {
      width: 100%; aspect-ratio: 1 / 1;
      background-size: cover; background-position: center;
      filter: grayscale(1);
      border-radius: 6px;
      margin-bottom: 12px;
    }
    .svc-card .svc-foot {
      display: flex; align-items: center; justify-content: space-between;
      gap: 10px;
      padding: 0 4px;
    }
    .svc-card .svc-label {
      font-weight: 500; font-size: 14px; color: var(--c-ink);
    }
    .svc-card .svc-arrow {
      font-size: 14px; color: var(--c-ink);
      opacity: 0;
      transition: opacity 0.18s ease;
    }
    .svc-card:hover .svc-arrow { opacity: 1; }
    /* Menu overlay variant — labels are white. */
    .ds-menu-overlay .svc-card { background: transparent; }
    .ds-menu-overlay .svc-card:hover { background: rgba(255,255,255,0.06); }
    .ds-menu-overlay .svc-card .svc-label,
    .ds-menu-overlay .svc-card .svc-arrow { color: #fff; }

    /* ── FULL-VIEWPORT MENU ─────────────────────────────────────── */
    .ds-menu-overlay {
      position: fixed; inset: 0;
      background: var(--c-deep, #0d1116);
      color: #fff;
      z-index: 1000002;
      pointer-events: none;
      clip-path: inset(0 0 calc((1 - var(--menu-open, 0)) * 100%) 0);
      transition: clip-path 0.85s cubic-bezier(0.16, 1, 0.3, 1);
      display: flex;
      font-family: 'Inter', sans-serif;
    }
    .ds-menu-overlay[data-open="1"] { pointer-events: auto; }
    .ds-menu-inner {
      flex: 1;
      display: grid;
      grid-template-columns: 1fr 1fr;
      grid-template-rows: auto 1fr auto;
      padding: 22px 28px 28px;
      column-gap: 4vw;
      row-gap: 4vh;
    }
    .ds-menu-top-left {
      grid-column: 1; grid-row: 1;
      display: flex; align-items: center; gap: 56px;
    }
    .ds-menu-logo {
      display: flex; align-items: center; gap: 14px;
      font-size: 14px; font-weight: 500; line-height: 1.15;
    }
    .ds-menu-logo .mark { width: 50px; height: 32px; color: #fff; }
    .ds-menu-close {
      display: inline-flex; align-items: center; gap: 14px;
      background: transparent; border: 0; color: #fff; cursor: pointer;
      font: inherit; font-size: 16px; font-weight: 500;
      padding: 8px 4px;
    }
    .ds-menu-close .x { font-size: 14px; opacity: 0.85; }

    .ds-menu-services {
      grid-column: 2; grid-row: 1 / span 2;
      display: flex; flex-direction: column;
      gap: 4vh;
      align-self: start;
    }
    .ds-menu-services-title {
      margin: 0;
      font-family: 'Instrument Serif', serif; font-style: italic;
      font-weight: 400;
      font-size: clamp(48px, 5vw, 88px);
      letter-spacing: -0.02em;
      color: #fff;
    }
    .ds-menu-services-grid {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 18px;
    }
    .ds-menu-services-grid .svc-card .svc-label { color: #fff; }

    .ds-menu-bottom {
      grid-column: 1 / -1; grid-row: 3;
      display: grid;
      grid-template-columns: 1fr 1fr;
      align-items: end;
      gap: 4vw;
    }
    .ds-menu-bottom-left {
      display: flex; flex-direction: column; gap: 32px;
    }
    .ds-menu-socials { display: flex; gap: 22px; }
    .ds-menu-socials .soc {
      width: 88px; height: 88px;
      border-radius: 50%;
      background: rgba(255,255,255,0.07);
      display: inline-flex; align-items: center; justify-content: center;
      font-size: 32px; color: #fff;
      text-decoration: none;
    }
    .ds-menu-links {
      display: flex; flex-direction: column;
      max-width: 320px;
      border-top: 1px solid rgba(255,255,255,0.12);
    }
    .ds-menu-links a {
      display: flex; justify-content: space-between; align-items: center;
      color: #fff; text-decoration: none;
      padding: 14px 0;
      border-bottom: 1px solid rgba(255,255,255,0.12);
      font-size: 14px;
    }
    .ds-menu-links a .arrow { font-size: 12px; opacity: 0.7; }
    .ds-menu-nav {
      display: grid;
      grid-template-columns: 1fr 1fr;
      column-gap: 4vw;
      row-gap: 14px;
    }
    .ds-menu-nav a {
      color: #fff; text-decoration: none;
      font-family: 'Instrument Serif', serif;
      font-weight: 400;
      font-size: clamp(56px, 6vw, 110px);
      letter-spacing: -0.01em;
      line-height: 1.0;
      display: inline-block;
    }
    /* Cube-flip text: two faces share an axis half-em behind the face plane; perspective on parent gives the depth read. */
    .ds-menu-nav .rolltext {
      display: inline-block;
      position: relative;
      vertical-align: top;
      height: 1em;
      line-height: 1;
      perspective: 800px;
      transform-style: preserve-3d;
    }
    .ds-menu-nav .rolltext .t {
      display: block;
      line-height: 1;
      backface-visibility: hidden;
      transform-origin: 50% 50% -0.5em;
      transition: transform 0.55s cubic-bezier(0.65, 0, 0.35, 1);
      will-change: transform;
    }
    .ds-menu-nav .rolltext .t:nth-child(2) {
      position: absolute;
      top: 0; left: 0; width: 100%;
      transform: rotateX(90deg);
    }
    .ds-menu-nav a:hover .rolltext .t:nth-child(1) {
      transform: rotateX(-90deg);
    }
    .ds-menu-nav a:hover .rolltext .t:nth-child(2) {
      transform: rotateX(0deg);
    }
    .ds-page .hero-meta {
      position: absolute; bottom: 4vh; left: 28px;
      font-size: 14px; color: var(--c-ink); z-index: 4;
      line-height: 1.4;
      opacity: var(--hero-op, 1);
    }
    .ds-page .hero-meta .label { display: block; margin-bottom: 8px; opacity: 0.7; }
    .ds-page .hero-meta .city { display: block; font-weight: 500; line-height: 1.4; }
    /* Grid-stacked ink + white title copies overlap in one cell. */
    .ds-page .hero-title-stack {
      position: absolute; top: 50%; left: 0; right: 0;
      display: grid;
      transform: translate(var(--hero-tx, 0%), -50%);
      opacity: var(--hero-op, 1);
      pointer-events: none; z-index: 3;
      will-change: transform, opacity;
    }
    .ds-page .hero-title-stack > .hero-title {
      grid-area: 1 / 1 / 2 / 2;
    }
    .ds-page .hero-title {
      margin: 0;
      text-align: center;
      font-family: 'Instrument Serif', serif; font-weight: 500;
      font-size: clamp(118px, 13.2vw, 280px);
      line-height: 0.94; letter-spacing: -0.025em;
      pointer-events: none; white-space: nowrap;
    }
    /* Ink/white split fixed at 50% of title-stack width. Cream pane width is graph-driven (50% → 0% via --cream-w) but title's hero-op fades 1 → 0 over progress 0 → 0.4 — by the time the cream pane has shrunk past 50%, the title is already invisible, so the apparent mismatch never visually manifests. (Tracking --cream-w continuously was tried and reverted: it caused the title to visibly shift leftward mid-scroll because the clip moved while the title itself was still partially visible during the early portion of the fade.) */
    .ds-page .hero-title.ink   { color: var(--c-ink); clip-path: inset(0 50% 0 0); }
    .ds-page .hero-title.white { color: #ffffff;      clip-path: inset(0 0 0 50%); }
    .ds-page .hero-title .tline { display: block; overflow: hidden; padding: 0.04em 0 0.16em; }
    .ds-page .hero-title .ft-split-char { display: inline-block; will-change: transform, opacity; }
    .ds-page .hero-title em { font-style: italic; font-weight: 500; }
    .ds-page .hero-caption {
      position: absolute; bottom: 4vh; left: calc(50% + 2vw); max-width: 420px;
      font-family: 'Instrument Serif', serif; font-size: 28px; line-height: 1.2;
      color: #fff; z-index: 4; pointer-events: none;
      opacity: var(--hero-op, 1);
    }
    .ds-page .hero-caption .lead { display: block; font-style: normal; font-weight: 500; }
    .ds-page .hero-caption .body { display: block; font-style: italic; }
    .ds-page .hero-tagline {
      position: absolute; bottom: 4vh; right: 28px; max-width: 320px;
      font-size: 14px; line-height: 1.4;
      color: rgba(255,255,255,0.95);
      text-align: right; font-weight: 500;
      z-index: 4; pointer-events: none;
      opacity: var(--hero-op, 1);
    }
    .ds-page .hero-services {
      position: absolute; bottom: 6vh; left: 0; right: 0;
      display: flex; justify-content: space-around; align-items: center;
      padding: 0 6vw; z-index: 4; pointer-events: none;
      color: #fff; font-size: 13px; letter-spacing: 0.06em; font-weight: 500;
      opacity: var(--overlay-op, 0); will-change: opacity;
    }
    /* Overlay caption — slides in from right while chars stagger in. */
    .ds-page .hero-overlay {
      position: absolute; top: 50%; left: 0; right: 0;
      transform: translate(var(--overlay-tx, 100%), -50%);
      margin: 0;
      text-align: center;
      white-space: nowrap;
      font-family: 'Instrument Serif', serif; font-style: italic;
      font-weight: 400;
      font-size: clamp(54px, 7.6vw, 132px);
      letter-spacing: -0.02em; line-height: 1.04;
      color: #ffffff; pointer-events: none; z-index: 4;
      padding: 0 4vw;
      will-change: transform;
    }
    .ds-page .hero-overlay .ft-split-char {
      display: inline-block;
      will-change: transform, opacity;
    }

    /* ── TEAM TOP ───────────────────────────────────────────────── */
    .ds-page .team {
      position: relative;
      z-index: 2;
      background: var(--c-paper);
      width: 100%;
      padding: 10vh 6vw 0;
    }
    .ds-page .team-top {
      display: grid;
      grid-template-columns: minmax(80px, 1fr) clamp(280px, 26vw, 420px) minmax(220px, 1.1fr) auto;
      column-gap: 4vw;
      align-items: start;
      padding-bottom: 4vh;
    }
    .ds-page .team-portrait-slot {
      grid-column: 2; grid-row: 1;
      width: 100%;
      height: 47vh;
    }
    .ds-page .team-paragraph {
      font-size: 18px; line-height: 1.55;
      color: var(--c-ink);
      max-width: 420px;
      grid-column: 3; grid-row: 1;
    }
    .ds-page .team-avatars {
      display: flex;
      align-items: center;
      grid-column: 4; grid-row: 1;
    }
    .ds-page .team-avatars .avatar,
    .ds-page .team-avatars .badge {
      width: 76px; height: 76px;
      border-radius: 50%;
      margin-left: -16px;
      border: 2px solid var(--c-paper);
    }
    .ds-page .team-avatars .avatar:first-child { margin-left: 0; }
    .ds-page .team-avatars .avatar {
      background-size: cover;
      background-position: center;
      filter: grayscale(0.4);
    }
    .ds-page .team-avatars .badge {
      background: rgba(37, 40, 45, 0.08);
      display: flex; align-items: center; justify-content: center;
      color: var(--c-ink);
      font-family: 'Instrument Serif', serif;
      font-size: 22px;
    }

    /* ── PIN WRAP ─────────────────────────────────────────────── */
    .ds-page .pin-wrap {
      position: relative;
      z-index: 2;
      background: var(--c-paper);
    }
    /* Portrait — sized at end-state (47vw × 100vh); graph drives tx + scale via CSS vars. */
    .ds-page .portrait-anchor {
      position: absolute;
      top: 0;
      left: 0;
      width: 50vw;
      height: 100vh;
      transform-origin: top left;
      pointer-events: none;
      /* Stack above services overlays (z:5) across the full pin lifecycle — single source via CSS. */
      z-index: 1100;
      /* --portrait-after-y: one-shot post-release flow-shift compensation. --portrait-parallax-y: graph-driven parallax (svc-exit-px × 0.45 — portrait exits at ~55% of section scroll-rate). */
      transform: translateY(var(--portrait-after-y, 0px))
                 translateY(var(--portrait-parallax-y, 0px));
    }
    /* Portrait inner — graph-driven tx/scale. Vertical positioning is
       owned entirely by PinEngine (anchor pinned at services-track top). */
    .ds-page .portrait-pin {
      width: 100%;
      height: 100%;
      transform:
        translateY(var(--portrait-ty, -22vh))
        translateX(var(--portrait-tx, 12vw))
        scale(var(--portrait-scale, 0.32));
      transform-origin: center center;
      will-change: transform;
      /* Post-pin darken: brightness 1→0.15 keyed off --svc-exit so portrait fades in lockstep with the section. */
      filter: brightness(calc(1 - var(--svc-exit, 0) * 0.85));
    }
    /* Image stack — each img clipped from top via --img-N-clip. */
    .ds-page .portrait-pin .img {
      position: absolute; top: 0; left: 0;
      width: 100%; height: 100%;
      background-size: cover;
      background-position: center;
      filter: grayscale(1) brightness(0.55) contrast(1.05);
    }
    .ds-page .portrait-pin .img-0 { background-image: url('https://fasterhq1-prod.s3.amazonaws.com/media/623/Nick_hume.jpg'); z-index: 1; }
    .ds-page .portrait-pin .img-1 { background-image: url('https://fasterhq1-prod.s3.amazonaws.com/media/578/Technical_diligence.png'); z-index: 2; clip-path: inset(calc(var(--img-1-clip, 100%)) 0 0 0); }
    .ds-page .portrait-pin .img-2 { background-image: url('https://fasterhq1-prod.s3.amazonaws.com/media/578/Strategy-as-service.png'); z-index: 3; clip-path: inset(calc(var(--img-2-clip, 100%)) 0 0 0); }
    .ds-page .portrait-pin .img-3 { background-image: url('https://fasterhq1-prod.s3.amazonaws.com/media/578/Data_Center_cooling.png'); z-index: 4; clip-path: inset(calc(var(--img-3-clip, 100%)) 0 0 0); }

    /* TEAM GOAL — 3-column grid (lead | portrait-slot | words). .goal-portrait-spacer reserves the middle slot until portraitPin engages. */
    .ds-page .team-goal {
      display: grid;
      grid-template-columns: minmax(220px, 1fr) clamp(220px, 20vw, 320px) minmax(280px, 1.6fr);
      column-gap: 2.5vw;
      align-items: start;
      padding: 6vh 3vw 4vh;
      height: 100vh;
      overflow: visible;
      position: relative;
      /* Frosted blur driven by --goal-exit (graph). The darken half of the
         frosted-glass effect is owned exclusively by the ::after overlay
         below — single source of truth for opacity, no compounded filter
         brightness fighting the rgba alpha. */
      filter: blur(calc(var(--goal-exit, 0) * 6px));
      will-change: filter;
    }
    .ds-page .team-goal::after {
      content: '';
      position: absolute; inset: 0;
      background: rgba(20, 22, 28, calc(var(--goal-exit, 0) * 0.62));
      pointer-events: none;
      z-index: 5;
    }
    /* Dark pill CTA under the goal-words paragraph. Same shape vocabulary as
       the hero CTA (pill + 16px gap to icon) but inverted ink-on-cream. The
       trailing icon is two crossed strokes — a subtle "+" / sparkle mark
       borrowed from the reference, draws the eye without being literal. */
    .ds-page .team-goal-button {
      display: inline-flex; align-items: center; gap: 32px;
      background: var(--c-ink); color: #fff;
      padding: 18px 22px 18px 28px;
      border-radius: 999px;
      text-decoration: none;
      font-family: 'Inter', sans-serif; font-size: 15px; font-weight: 500;
      margin-top: 36px;
      transition: background 0.25s ease, transform 0.25s ease;
    }
    .ds-page .team-goal-button:hover { background: #2a2c30; transform: translateY(-1px); }
    .ds-page .team-goal-button .icon {
      display: inline-flex; align-items: center; justify-content: center;
      width: 18px; height: 18px;
    }
    .ds-page .team-goal-button .icon svg { width: 18px; height: 18px; }
    .ds-page .team-goal-lead {
      font-family: 'Instrument Serif', serif;
      font-weight: 400;
      font-size: clamp(60px, 6.6vw, 108px);
      line-height: 1.0;
      color: var(--c-ink);
      letter-spacing: -0.01em;
    }
    .ds-page .team-goal-words {
      font-family: 'Instrument Serif', serif;
      font-weight: 400;
      font-size: clamp(51px, 6vw, 96px);
      line-height: 0.9;
      letter-spacing: -0.01em;
      color: var(--c-ink);
    }
    .ds-page .team-goal-words .ft-split-char,
    .ds-page .team-goal-words .ft-split-word {
      display: inline-block;
      opacity: 0.22;
      will-change: opacity;
    }

    /* SERVICES — dark full-viewport section. Left half hosts the pinned portrait (graph-pinned via portraitPin); right half holds the solutions stack. */
    .ds-page .services-track {
      position: relative;
      height: 700vh;
    }
    .ds-page .services {
      position: relative;
      background: transparent;
      color: #fff;
      height: 100vh;
      overflow: hidden;
    }
    /* Full-width dark bg — portrait (z:1100) paints on top of left half. */
    .ds-page .services::before {
      content: '';
      position: absolute;
      inset: 0;
      background: var(--c-deep);
      pointer-events: none;
      z-index: 0;
    }
    .ds-page .services > * { position: relative; z-index: 1; }
    /* Post-pin darken overlay: opacity = --svc-exit (0→1 over the post-pin scroll-out window). */
    .ds-page .services::after {
      content: '';
      position: absolute;
      inset: 0;
      background: #000;
      opacity: var(--svc-exit, 0);
      pointer-events: none;
      z-index: 5;
    }
    .ds-page .services-leftcol {
      /* Left half — left empty for the pinned portrait. */
      display: none;
    }
    /* N stacked right-column states. Graph emits the integer state index as `--svc-active-int` (computed by `exprSvcStateIndex = round(progress * count)` where `count` is auto-derived live from F369 `elementCount` over `.svc-state`). Each .svc-state carries `style="--idx: N"`; opacity is binary integer arithmetic: `1 - abs(active-int - idx)` is 1 when active-int == idx, 0 otherwise. Adding state #5: one more <div class="svc-state" style="--idx: 4"> in HTML — zero graph or CSS edits. */
    .ds-page .svc-states {
      display: grid;
      grid-template-columns: 1fr;
    }
    .ds-page .svc-states > .svc-state {
      grid-area: 1 / 1;
      opacity: max(0, calc(1 - abs(var(--svc-active-int, 0) - var(--idx, 0))));
    }
    /* N services-titles stacked at same bottom-center cell. Same integer-driven binary flip × --svc-vis (post-pin fade). */
    .ds-page .services-title {
      pointer-events: none;
      transform: translateY(calc(
        var(--title-ty, 100vh)
        - var(--title-exit, 0vh)
      ));
      opacity: calc(max(0, calc(1 - abs(var(--svc-active-int, 0) - var(--idx, 0)))) * var(--svc-vis, 0));
    }
    /* Spring entrance: each .title-inner gets its own --title-inner-y CSS variable written by a F351 forEach instance (titleSpring template). The pulseTween fires when the indexedDispatch detects a state-index edge for that slot, mapping eased 0..1 progress to translateY(28→0)px with back.out(4) overshoot. One CSS rule for any N — adding a state requires no CSS or graph changes. */
    .ds-page .services-title .title-inner {
      display: block;
      transform: translateY(var(--title-inner-y, 28px));
    }
    /* Active services-meta item highlight: dim non-active items. */
    .ds-page .services-meta .item {
      opacity: 0.45; cursor: pointer; pointer-events: auto;
      transition: opacity 0.28s ease;
      display: block; padding: 4px 0;
    }
    .ds-page .services-meta .item:hover { opacity: 0.75; }
    .ds-page[data-active="0"] .services-meta .item[data-state="0"],
    .ds-page[data-active="1"] .services-meta .item[data-state="1"],
    .ds-page[data-active="2"] .services-meta .item[data-state="2"],
    .ds-page[data-active="3"] .services-meta .item[data-state="3"],
    .ds-page:not([data-active]) .services-meta .item[data-state="0"] {
      opacity: 1;
    }
    /* Right column on right half (left:50vw): eyebrow → blurb → SUB-GRID(scanner | list). */
    .ds-page .services-rightcol {
      position: absolute;
      top: 8vh;
      left: 52vw;
      right: 4vw;
      display: flex;
      flex-direction: column;
      gap: 18px;
    }
    .ds-page .services-eyebrow {
      font-size: 12px; letter-spacing: 0.28em; text-transform: uppercase;
      font-weight: 500;
      color: #fff;
      opacity: 0.85;
    }
    .ds-page .services-blurb {
      font-family: 'Inter', sans-serif;
      font-size: 18px; line-height: 1.4; font-weight: 600;
      color: #fff;
      max-width: 440px;
      margin: 6px 0 12px;
    }
    .ds-page .services-grid {
      display: grid;
      grid-template-columns: minmax(140px, 200px) 1fr;
      column-gap: 24px;
      align-items: start;
    }
    .ds-page .services-scanner {
      width: 100%;
      aspect-ratio: 4 / 5;
      background-image: url('https://images.unsplash.com/photo-1606811971618-4486d14f3f99?w=900&auto=format&fit=crop&q=85');
      background-size: cover; background-position: center;
    }
    .ds-page .services-list { list-style: none; padding: 0; margin: 0; }
    .ds-page .services-list li {
      display: flex; align-items: center; justify-content: space-between;
      padding: 14px 0;
      border-bottom: 1px solid rgba(255,255,255,0.22);
      font-size: 17px; font-weight: 700;
    }
    .ds-page .services-list li:first-child { padding-top: 0; }
    .ds-page .services-list li::after {
      content: "↗"; color: rgba(255,255,255,0.6); font-weight: 400; margin-left: 12px;
    }

    /* Title: viewport-fixed at bottom, centered. position:fixed keeps it locked while .services scrolls; --title-ty/--title-exit drive entry/exit from the graph. */
    .ds-page .services-title {
      position: fixed;
      bottom: 4vh;
      left: 0; right: 0;
      margin: 0;
      text-align: center;
      font-family: 'Instrument Serif', serif;
      font-style: italic; font-weight: 500;
      font-size: clamp(72px, 9.5vw, 180px);
      line-height: 0.95;
      letter-spacing: -0.025em;
      color: #fff;
      pointer-events: none;
      z-index: 90;
      /* --title-ty: entry slide-up. --title-exit: post-cycle slide-out (0→100vh, 1:1 with scroll). */
      transform: translateY(calc(
        var(--title-ty, 100vh)
        - var(--title-exit, 0vh)
      ));
      will-change: transform;
    }
    .ds-page .services-title em { font-style: italic; }
    .ds-page .services-title .l1,
    .ds-page .services-title .l2 { display: block; }

    /* Services nav: viewport-fixed bottom-left at z:1500 (above portrait z:1100). Visibility+clickability gated on data-svc-pinned attribute (graph sets "1" during PINNED phase). */
    .ds-page .services-meta {
      position: fixed;
      left: 4vw;
      bottom: 4vh;
      font-size: 11px;
      color: rgba(255,255,255,0.55);
      z-index: 1500;
      /* opacity via --svc-vis (1 PIN, 0 BEFORE/AFTER ramp). translateY = -1 × --svc-exit-px so the fixed nav glues to section 1:1 during exit. */
      opacity: var(--svc-vis, 0);
      transform: translateY(calc(var(--svc-exit-px, 0) * -1px));
      pointer-events: none;
    }
    /* data-svc-pinned binary-gates pointer-events so items aren't clickable during fade-out or before pin. */
    .ds-page[data-svc-pinned="1"] .services-meta { pointer-events: auto; }
    .ds-page .services-meta .label { display: block; margin-bottom: 14px; opacity: 0.8; letter-spacing: 0.04em; }
    .ds-page .services-meta .item { display: block; line-height: 1.85; cursor: pointer; }
    .ds-page .services-meta .item.active { color: #fff; }

    .ds-page .services-cta {
      position: absolute;
      right: 4vw;
      bottom: 6vh;
      background: #fff; color: var(--c-ink);
      padding: 14px 28px; border-radius: 999px;
      font-weight: 500; font-size: 13px;
      z-index: 6;
      display: inline-flex;
      align-items: center;
      gap: 8px;
      text-decoration: none;
      /* Same binary integer opacity flip as .svc-state — stacks all CTAs
         at the same position; only the one matching --svc-active-int shows. */
      opacity: max(0, calc(1 - abs(var(--svc-active-int, 0) - var(--idx, 0))));
      pointer-events: auto;
    }
    .ds-page .services-cta::after { content: "+"; font-weight: 400; }

    /* TEAM OF EXPERTS — full-bleed dark photo + huge serif headline + 3 text-only cards + CTA. Stack order: .te-photo (z 0) → .te-overlay (z 1, gradient darken) → .te-title (z 2, headline straddles photo edge) → .te-cards / .te-cta (z 3, foreground text). Section is one viewport-height-plus tall and occupies the natural document flow. */
    .ds-page .team-experts {
      position: relative;
      z-index: 2;
      min-height: 145vh;
      background: #0e1014;
      color: #eae8e8;
      overflow: hidden;
      padding: 12vh 5vw 8vh;
      font-family: 'Inter', sans-serif;
    }
    .ds-page .te-photo {
      position: absolute;
      inset: 0 0 30vh 0;
      background-image: url('https://images.unsplash.com/photo-1517048676732-d65bc937f952?w=2400&auto=format&fit=crop&q=85');
      background-size: cover;
      background-position: center top;
      filter: grayscale(0.35) brightness(0.78) contrast(1.05);
      z-index: 0;
    }
    /* Dark gradient on the photo: legible white text without losing the doctor figures behind the headline. Bottom edge fades to the section's solid background so cards + CTA sit on flat black. */
    .ds-page .te-overlay {
      position: absolute;
      inset: 0;
      background: linear-gradient(180deg, rgba(14,16,20,0.35) 0%, rgba(14,16,20,0.55) 35%, rgba(14,16,20,0.85) 60%, #0e1014 78%);
      z-index: 1;
    }
    .ds-page .te-title {
      position: relative;
      z-index: 2;
      margin: 0;
      font-family: 'Instrument Serif', serif;
      font-weight: 400;
      font-size: clamp(120px, 19vw, 345px);
      line-height: 0.84;
      letter-spacing: -0.02em;
      color: #eae8e8;
      text-align: left;
      will-change: transform, opacity;
    }
    /* 3-column grid of text-only cards, sitting low against the photo where the doctors' bodies are dark + uniform. Cards inherit white-on-dark; bios use a slightly muted white. */
    .ds-page .te-cards {
      position: relative;
      z-index: 3;
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      column-gap: 4vw;
      margin-top: 60vh;
      padding: 0 1vw;
    }
    .ds-page .te-card {
      max-width: 320px;
      will-change: transform, opacity;
    }
    .ds-page .te-name {
      font-size: clamp(20px, 1.4vw, 25px);
      line-height: 1.1;
      font-weight: 600;
      color: #eae8e8;
      margin-bottom: 4px;
    }
    .ds-page .te-role {
      font-size: 15px;
      font-weight: 500;
      color: rgba(233, 231, 231, 0.4);
      margin-bottom: 14px;
    }
    .ds-page .te-bio {
      font-size: 15px;
      line-height: 1.19;
      font-weight: 500;
      color: #eae8e8;
      margin: 0;
    }
    /* Bottom CTA — left column small lockup, right column large serif tagline + cycling phrase + pill button. The cycling phrase is written by a textSequenceAnimation (mode:round) targeting `.te-cycle`. */
    .ds-page .te-cta {
      position: relative;
      z-index: 3;
      display: grid;
      grid-template-columns: 1fr 1.4fr;
      column-gap: 4vw;
      margin-top: 12vh;
      align-items: end;
    }
    .ds-page .te-cta-left {
      align-self: end;
      max-width: 320px;
    }
    .ds-page .te-cta-lead {
      font-size: 25px;
      font-weight: 600;
      color: #eae8e8;
      line-height: 1.1;
    }
    .ds-page .te-cta-sub {
      font-size: 15px;
      font-weight: 500;
      color: rgba(233, 231, 231, 0.4);
      line-height: 1.2;
      margin-top: 4px;
    }
    .ds-page .te-cta-right {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 28px;
    }
    .ds-page .te-cta-line {
      font-family: 'Instrument Serif', serif;
      font-weight: 400;
      font-size: clamp(38px, 4.2vw, 70px);
      line-height: 1.05;
      letter-spacing: -0.01em;
      color: #eae8e8;
    }
    /* Phrase-cycler text — written by the graph (textRevealAnimation in multi-source mode). The caret is a `::after` pseudo on .te-cycle itself so it lays out inline right after the typed text node — no separate caret element to position. min-width on the inline-block reserves layout space (right side of the box stays as whitespace) so the surrounding line doesn't reflow as phrases change length. */
    .ds-page .te-cycle {
      display: inline-block;
      min-width: 12ch;
    }
    .ds-page .te-cycle::after {
      content: '|';
      display: inline-block;
      margin-left: 0.06em;
      animation: te-caret-blink 1s steps(1, end) infinite;
    }
    @keyframes te-caret-blink { 50% { opacity: 0; } }
    /* Phrase sources are read at bind time by textRevealAnimation; never visible. */
    .ds-page .te-phrase-sources { display: none; }
    .ds-page .te-button {
      display: inline-flex;
      align-items: center;
      gap: 10px;
      background: #eae8e8;
      color: #0e1014;
      padding: 16px 26px;
      border-radius: 999px;
      text-decoration: none;
      font-family: 'Inter', sans-serif;
      font-size: 15px;
      font-weight: 500;
      transition: background 0.25s ease;
    }
    .ds-page .te-button:hover { background: #ffffff; }
    .ds-page .te-button .te-plus {
      display: inline-flex; align-items: center; justify-content: center;
      width: 18px; height: 18px; font-size: 18px; line-height: 1;
    }

    /* WHY CHOOSE US — the section is twice viewport-height tall; the inner .wu-stage is sticky-pinned in the first viewport so headlines + circles + balls all share one stage. The graph drives circle convergence + ball drop entrance via the section's scrollTrigger. Two thin-line SVG circles flank "We are here / to Enhance / Your Smile / Why choose us?" headlines; six stat balls sit absolutely positioned and drop in from above-viewport on a stagger. */
    .ds-page .why-us {
      position: relative;
      z-index: 2;
      height: 200vh;
      background: #0e1014;
      color: #eae8e8;
    }
    .ds-page .wu-stage {
      position: relative;
      width: 100%;
      height: 100vh;
      overflow: hidden;
    }
    /* The two outline circles are inside a single .wu-circles wrapper that rotates as one rigid body. The wrapper is positioned dead-center of the stage and the rotation pivots around its own center (the section seam). At rot=0 the layout is HORIZONTAL infinity (left circle on the left, right circle on the right, inner edges touching at the seam). At rot=90° the wrapper has spun 90° clockwise: layout becomes VERTICAL infinity (originally-left circle now ABOVE seam, originally-right circle now BELOW seam, inner edges still touching). This is a combined rotation — neither circle rotates independently around its own center. After rotation completes, --wu-ty translates the whole wrapper UP so only the lower circle's lobe stays in viewport — the cup the balls drop into. */
    .ds-page .wu-circles {
      position: absolute;
      left: 50%;
      top: 50%;
      width: 0;
      height: 0;
      transform: translate(-50%, calc(-50% + var(--wu-ty, 0vh))) rotate(var(--wu-rot, 0deg)) scale(var(--wu-scale, 1));
      will-change: transform;
      pointer-events: none;
    }
    .ds-page .wu-circle {
      position: absolute;
      top: 50%;
      /* Base size min(60vw, 100vh) — vw on portrait/standard aspects keeps
         the original cup width; vh cap kicks in on wide aspects (≥ ~16:9
         large desktops, ultrawides) where 60vw exceeds 100vh and the
         lower lobe was getting cut off after the 1.67× scale. The lower
         lobe still extends below viewport at end (intentional — only the
         upper arc is needed as the "cup brim" for the balls), but the
         visible arc no longer terminates inside the viewport on wide
         screens. */
      width: min(60vw, 100vh);
      height: min(60vw, 100vh);
      pointer-events: none;
    }
    /* Circles are positioned at offsets ±(--wu-spread-factor × radius)
       within the rotating wrapper. --wu-spread-factor is a unitless
       graph-driven ratio: starts at ~1.667 (circles wide apart) and
       ramps to 1.0 (inner edges touching at the seam) during the early
       portion of scroll. The factor multiplies the SAME min(30vw, 50vh)
       radius the .wu-circle uses, so the spread tracks the vh-cap on
       wide aspects automatically — no gap regardless of viewport. */
    .ds-page .wu-circle-left {
      left: calc(0px - var(--wu-spread-factor, 1) * min(30vw, 50vh));
      transform: translate(-50%, -50%);
    }
    .ds-page .wu-circle-right {
      left: calc(var(--wu-spread-factor, 1) * min(30vw, 50vh));
      transform: translate(-50%, -50%);
    }
    /* Headlines — large serif italic at the four cardinal positions around the center. */
    .ds-page .wu-headline {
      position: absolute;
      font-family: 'Instrument Serif', serif;
      font-weight: 400;
      font-size: clamp(60px, 9vw, 168px);
      line-height: 0.95;
      letter-spacing: -0.02em;
      color: #eae8e8;
      white-space: nowrap;
      pointer-events: none;
    }
    .ds-page .wu-headline em { font-style: italic; }
    .ds-page .wu-h-left {
      top: 50%; right: calc(50% + 1.5vw);
      transform: translateY(-50%);
      padding: 0;
    }
    .ds-page .wu-h-right {
      top: 50%; left: calc(50% + 1.5vw);
      transform: translateY(-50%);
      padding: 0;
    }
    .ds-page .wu-h-bottom {
      top: 60%; left: 50%;
      transform: translateX(-50%);
    }
    .ds-page .wu-mid {
      position: absolute;
      top: 18%; left: 50%;
      transform: translate(-50%, -50%);
      font-family: 'Inter', sans-serif;
      font-size: 14px;
      font-weight: 500;
      color: rgba(234, 232, 232, 0.7);
      text-align: center;
      line-height: 1.3;
      white-space: nowrap;
    }
    /* Stat balls. Each ball is absolutely positioned at (--bx, --by) with diameter --bd. Default state is hidden + lifted off-screen; the graph staggerAnimation drops them in. */
    .ds-page .wu-balls {
      position: absolute;
      inset: 0;
      pointer-events: none;
    }
    .ds-page .wu-balls { --wu-ball-opacity: 1; }
    .ds-page .wu-ball {
      /* F367 — each ball is anchored at (0,0) of .wu-balls. The physics
         world's body position (in viewport-px) is written via
         `transform: translate(...)` by domPoseWrite. The -50% inner
         offset centres the ball on the body's pose point. */
      position: absolute;
      left: 0; top: 0;
      width: var(--bd); height: var(--bd);
      margin-left: calc(var(--bd) * -0.5);
      margin-top: calc(var(--bd) * -0.5);
      background: var(--bg);
      color: var(--fg);
      border-radius: 50%;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      text-align: center;
      will-change: transform, opacity;
      /* Scroll-up fade: opacity is driven by --wu-ball-opacity (set by a
         domVariablesWrite on .wu-balls). Below the reset threshold the
         opacity drops to 0 BEFORE the body re-snaps, so the snap is
         invisible. */
      opacity: var(--wu-ball-opacity, 1);
      /* F367 step 5 v2 — wu-balls are interactive (drag-to-throw). Need
         pointer-events to bypass the .wu-balls container's
         `pointer-events: none` so pointerdown reaches the ball. */
      pointer-events: auto;
      cursor: grab;
      user-select: none;
    }
    .ds-page .wu-ball:active { cursor: grabbing; }
    .ds-page .wu-ball .wu-num {
      font-family: 'Instrument Serif', serif;
      font-weight: 400;
      font-size: calc(var(--bd) * 0.32);
      line-height: 1;
      letter-spacing: -0.01em;
    }
    .ds-page .wu-ball .wu-lbl {
      font-family: 'Inter', sans-serif;
      font-size: calc(var(--bd) * 0.06);
      font-weight: 600;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      margin-top: calc(var(--bd) * 0.04);
      line-height: 1.25;
    }

    /* TESTIMONIALS — pinned scrollytelling section that follows .why-us.
       3-column layout: services list on left, circular nav button in
       middle, long quote on right. Active service category transitions
       through the list as scroll progresses. */
    .ds-page .testimonials {
      position: relative;
      z-index: 2;
      height: 100vh;
      background: #0e1014;
      color: #eae8e8;
    }
    .ds-page .ts-pinned {
      position: relative;
      height: 100vh;
      overflow: hidden;
    }
    .ds-page .ts-grid {
      position: absolute;
      inset: 0;
      display: grid;
      grid-template-columns: 1fr 1fr;
      align-items: start;
      padding: 14vh 6vw 8vh;
      column-gap: 6vw;
    }
    .ds-page .ts-col-left {
      display: flex;
      flex-direction: column;
      gap: 36px;
    }
    .ds-page .ts-title {
      font-family: 'Inter', system-ui, sans-serif;
      font-size: clamp(22px, 1.7vw, 30px);
      letter-spacing: -0.01em;
      color: #eae8e8;
      font-weight: 500;
    }
    /* Strip browser's default UL bullet — the per-item progress ring
       below is the ONLY indicator. Without this we get both the LI
       disc and the ::before ring side-by-side, which is exactly what
       the reference page does NOT do. */
    .ds-page .ts-list {
      list-style: none;
      margin: 0;
      padding: 0;
      display: flex;
      flex-direction: column;
      gap: 14px;
      font-family: 'Inter', system-ui, sans-serif;
      font-size: clamp(15px, 1vw, 18px);
      line-height: 1.5;
      font-weight: 500;
    }
    .ds-page .ts-item {
      position: relative;
      padding-left: 28px;
      /* Pure plug-in: graph writes --ts-item-alpha pre-mapped to the
         final 0.42..1 range. No CSS calc / multiplier — the mapping
         lives in the domVariablesWrite outputMin/outputMax. */
      color: rgba(234, 232, 232, var(--ts-item-alpha, 0.42));
    }
    /* Progress ring shown ONLY on the active item. Conic-gradient
       sweep visualises remaining dwell time. The graph writes
       --ts-item-deg pre-mapped to 0..360deg (with `unit: "deg"` on
       the domVariablesWrite), so CSS just plugs the variable into
       the conic gradient stops — no `calc(... * 360deg)` math. */
    .ds-page .ts-item::before {
      content: '';
      position: absolute;
      left: 0;
      top: 50%;
      transform: translateY(-50%);
      width: 14px;
      height: 14px;
      border-radius: 50%;
      background:
        conic-gradient(from -90deg, #eae8e8 0deg,
          #eae8e8 var(--ts-item-deg, 0deg),
          rgba(234, 232, 232, 0.18) var(--ts-item-deg, 0deg),
          rgba(234, 232, 232, 0.18) 360deg);
      /* Mask out the centre to leave a 1.4px-thick ring. */
      -webkit-mask: radial-gradient(circle, transparent 4.4px, #000 5px);
              mask: radial-gradient(circle, transparent 4.4px, #000 5px);
      opacity: var(--ts-item-active, 0);
    }
    /* Mouse-following cursor — fully graph-driven (no inline JS).
       The `pointer` graph node writes --ts-cursor-x/y (px relative
       to .ts-pinned) and --ts-cursor-opacity (0/1 from `isInside`).
       A direction flip is encoded as --ts-cursor-flip-x = 1 (left
       half, arrow points left) or -1 (right half, scaleX flip). All
       values are pre-mapped by the graph; CSS is pure plug-in. */
    .ds-page .testimonials { cursor: none; }
    .ds-page .ts-pinned { cursor: none; position: relative; }
    /* Cursor structure: a 0×0 anchor at the pointer location (transform
       + opacity written directly by `tsCursorPose` domPoseWrite), with
       the actual visual SVG centered on that anchor via its own
       `translate(-50%, -50%)`. Collapsing the three previous CSS
       variables (--ts-cursor-x/y/opacity) into inline styles managed
       by one domPoseWrite. */
    .ds-page .ts-cursor {
      position: absolute;
      left: 0; top: 0;
      width: 0; height: 0;
      pointer-events: none;
      z-index: 9;
      mix-blend-mode: screen;
    }
    .ds-page .ts-cursor-svg {
      position: absolute;
      left: 0; top: 0;
      width: clamp(180px, 16vw, 260px);
      height: clamp(180px, 16vw, 260px);
      display: block;
      pointer-events: none;
      stroke-linecap: round;
      stroke-linejoin: round;
      transform-origin: 50% 50%;
      transform: translate(-50%, -50%) scaleX(var(--ts-cursor-flip-x, 1));
      transition: transform 220ms cubic-bezier(0.4, 0, 0.2, 1);
    }
    .ds-page .ts-cursor-svg * { pointer-events: none; }
    .ds-page .ts-col-right {
      position: relative;
      padding-right: 4vw;
      padding-left: 4vw;
      min-height: 70vh;
      /* Thin vertical divider in the gutter between list and quote.
         Sits at the left edge of the right column, full column height,
         matches the reference page's column separator. */
      border-left: 1px solid rgba(234, 232, 232, 0.18);
    }
    /* All quote boxes occupy the same absolute slot — only opacity
       distinguishes the active one. Cross-fade between testimonials
       happens because adjacent gates' ranges abut: as progress sweeps
       past a boundary, the outgoing box ramps to 0 while the incoming
       ramps to 1. */
    .ds-page .ts-quote-box {
      position: absolute;
      inset: 0;
      padding-right: 4vw;
      padding-left: 1.5vw;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      opacity: var(--ts-quote-opacity, 0);
      pointer-events: none;
    }
    .ds-page .ts-quote-box[data-active="1"] { pointer-events: auto; }
    .ds-page .ts-quote {
      font-family: 'Inter', system-ui, sans-serif;
      font-size: clamp(20px, 1.6vw, 30px);
      line-height: 1.45;
      letter-spacing: -0.005em;
      color: #eae8e8;
      font-weight: 400;
    }
    .ds-page .ts-author {
      font-family: 'Inter', system-ui, sans-serif;
      font-size: clamp(13px, 0.95vw, 16px);
      color: rgba(234, 232, 232, 0.5);
      letter-spacing: 0.01em;
    }

    /* OUTRO — full-bleed dentist portrait with editorial split-typography
       overlay. Dark dramatic vignette gradient drifts on scroll under
       graph control (`outroVignetteTween` writes --outro-vig-x/y). Title
       lines are positioned absolutely to overlap diagonally the way the
       reference collages them: "Your Perfect" italic on the lower-left,
       "Bringing / Smile to Life" on the lower-right with an italic accent
       on "to Life". The eyebrow sits between the two columns. */
    .ds-page .outro {
      position: relative;
      z-index: 2;
      height: 180vh;
      min-height: 1100px;
      background: #cfcfcf;
      color: #f6f4ef;
      overflow: hidden;
      isolation: isolate;
    }
    .ds-page .outro-bg {
      position: absolute;
      inset: 0;
      background-image: url('https://images.unsplash.com/photo-1486325212027-8081e485255e?w=2000&auto=format&fit=crop&q=85');
      background-size: cover;
      background-position: 50% center;
      filter: contrast(1.2) brightness(0.42) saturate(0.5);
    }
    .ds-page .outro-vignette {
      position: absolute;
      inset: 0;
      background: radial-gradient(
        ellipse 80% 70% at var(--outro-vig-x, 30%) var(--outro-vig-y, 40%),
        rgba(245, 243, 238, 0.55) 0%,
        rgba(180, 178, 173, 0.18) 35%,
        rgba(20, 18, 22, 0.55) 75%,
        rgba(10, 10, 12, 0.85) 100%
      );
      pointer-events: none;
      mix-blend-mode: multiply;
    }
    .ds-page .outro-inner {
      position: relative;
      height: 100%;
      padding: 6vh 4vw 14vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      text-align: center;
    }
    .ds-page .outro-eyebrow {
      font-family: 'Inter', system-ui, sans-serif;
      font-size: clamp(11px, 0.85vw, 13px);
      letter-spacing: 0.05em;
      color: rgba(245, 243, 238, 0.85);
      margin: 0 0 24px;
      text-align: center;
      line-height: 1.3;
    }
    /* Title uses mix-blend-mode: difference against white text → on light
       background regions it renders black, on dark silhouette regions it
       renders bright cream. Pure compositing math, no image URL pinning,
       no fixed attachment required, and it adapts to whatever the vignette
       parallax is doing underneath. Layer (z) sits above .outro-bg and
       .outro-vignette so the difference operates on the visible pixels. */
    .ds-page .outro-title {
      font-family: 'Instrument Serif', serif;
      font-size: clamp(72px, 13vw, 220px);
      line-height: 0.88;
      letter-spacing: -0.03em;
      font-weight: 400;
      margin: 0;
      color: #ffffff;
      mix-blend-mode: difference;
    }
    .ds-page .outro-line { display: block; }
    .ds-page .outro-italic { font-style: italic; }

    /* FOOTER — dark navy band with a CONVEX TOP arch that rises UP into
       the outro image. The arch is a ::before whose corners use 50%/100%
       radii to form the bottom half of an ellipse — the dark fill
       silhouettes against the cream/photo above. */
    .ds-page .ds-footer {
      position: relative;
      background: #2a2b3a;
      color: #eae8e8;
      padding: 14vh 6vw 32px;
      margin-top: -8vh;
      z-index: 3;
    }
    /* Convex arch — grows from a flat line into a tall ellipse cap as
       the user scrolls toward the footer. Height driven by graph-written
       --footer-arch-h (vh units), additionally translated up/down by
       --footer-arch-y (vh) for parallax over the photo above. Both are
       pure plug-ins; the arch shape itself stays a 50%/100% radius. */
    .ds-page .ds-footer::before {
      content: '';
      position: absolute;
      bottom: 100%;
      left: -4vw;
      right: -4vw;
      height: var(--footer-arch-h, 0vh);
      background: #2a2b3a;
      border-radius: 50% 50% 0 0 / 100% 100% 0 0;
      transform: translateY(var(--footer-arch-y, 0vh));
      will-change: height, transform;
    }
    .ds-page .ds-footer-inner {
      position: relative;
      max-width: 1400px;
      margin: 0 auto;
    }
    .ds-page .ds-footer-top {
      display: grid;
      grid-template-columns: 1fr 1.4fr;
      gap: 4vw;
      align-items: start;
      margin-bottom: 100px;
    }
    .ds-page .ds-footer-socials {
      display: flex;
      flex-direction: column;
      gap: 14px;
    }
    .ds-page .ds-footer-social {
      width: 48px;
      height: 48px;
      border-radius: 50%;
      background: rgba(255, 255, 255, 0.06);
      display: inline-flex;
      align-items: center;
      justify-content: center;
      color: #eae8e8;
      text-decoration: none;
    }
    .ds-page .ds-footer-social svg { width: 18px; height: 18px; }
    .ds-page .ds-footer-mark {
      position: absolute;
      top: -3vh;
      left: 50%;
      transform: translateX(-50%);
      width: 88px;
      color: #eae8e8;
    }
    .ds-page .ds-footer-cta {
      font-family: 'Instrument Serif', serif;
      font-size: clamp(36px, 4.5vw, 64px);
      line-height: 1.05;
      letter-spacing: -0.015em;
      font-weight: 400;
      margin: 0 0 56px;
      max-width: 640px;
    }
    .ds-page .ds-footer-cta-italic { font-style: italic; }
    .ds-page .ds-form-label {
      font-family: 'Inter', system-ui, sans-serif;
      font-size: 13px;
      color: rgba(234, 232, 232, 0.55);
      margin: 0 0 16px;
    }
    .ds-page .ds-form-radios {
      display: flex;
      gap: 28px;
      margin-bottom: 36px;
      flex-wrap: wrap;
    }
    .ds-page .ds-form-radio {
      display: inline-flex;
      align-items: center;
      gap: 10px;
      font-family: 'Inter', system-ui, sans-serif;
      font-size: 15px;
      font-weight: 500;
      color: #eae8e8;
      cursor: pointer;
    }
    .ds-page .ds-form-radio input { display: none; }
    .ds-page .ds-form-radio .dot {
      width: 18px;
      height: 18px;
      border-radius: 50%;
      border: 1px solid rgba(234, 232, 232, 0.45);
      display: inline-block;
      position: relative;
    }
    .ds-page .ds-form-radio input:checked + .dot::after {
      content: '';
      position: absolute;
      inset: 3px;
      border-radius: 50%;
      background: #eae8e8;
    }
    .ds-page .ds-form-row {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 16px;
      margin-bottom: 16px;
    }
    .ds-page .ds-form-input {
      background: transparent;
      border: 1px solid #d96a4a;
      color: #d96a4a;
      border-radius: 999px;
      padding: 18px 28px;
      font-family: 'Inter', system-ui, sans-serif;
      font-size: 15px;
      outline: none;
    }
    .ds-page .ds-form-input::placeholder { color: #d96a4a; }
    .ds-page .ds-form-message-row {
      display: grid;
      grid-template-columns: 1fr auto;
      gap: 16px;
      align-items: center;
    }
    .ds-page .ds-form-message {
      background: transparent;
      border: 1px solid rgba(234, 232, 232, 0.35);
      color: #eae8e8;
      border-radius: 999px;
      padding: 18px 28px;
      font-family: 'Inter', system-ui, sans-serif;
      font-size: 15px;
      outline: none;
    }
    .ds-page .ds-form-message::placeholder { color: rgba(234, 232, 232, 0.4); }
    .ds-page .ds-form-submit {
      width: 56px;
      height: 56px;
      border-radius: 50%;
      background: #f1ece3;
      color: #2a2b3a;
      border: none;
      cursor: pointer;
      font-size: 22px;
      display: inline-flex;
      align-items: center;
      justify-content: center;
    }
    .ds-page .ds-footer-cols {
      display: grid;
      grid-template-columns: 1fr 1fr 2fr;
      gap: 4vw;
      margin-top: 100px;
      padding-top: 40px;
    }
    .ds-page .ds-footer-col h4 {
      font-family: 'Inter', system-ui, sans-serif;
      font-size: 13px;
      color: rgba(234, 232, 232, 0.5);
      margin: 0 0 28px;
      font-weight: 400;
    }
    .ds-page .ds-footer-col a {
      font-family: 'Inter', system-ui, sans-serif;
      font-size: clamp(14px, 1vw, 17px);
      color: #eae8e8;
      text-decoration: none;
      display: block;
      margin: 0 0 14px;
      line-height: 1.4;
      font-weight: 500;
    }
    .ds-page .ds-footer-col a:hover { color: #fff; }
    .ds-page .ds-footer-locations {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 2.5vw;
    }
    .ds-page .ds-footer-loc h5 {
      font-family: 'Inter', system-ui, sans-serif;
      font-size: clamp(15px, 1.05vw, 18px);
      font-weight: 600;
      margin: 0 0 14px;
      color: #eae8e8;
      text-decoration: underline;
      text-underline-offset: 4px;
    }
    .ds-page .ds-footer-loc p {
      font-family: 'Inter', system-ui, sans-serif;
      font-size: 13px;
      color: rgba(234, 232, 232, 0.7);
      margin: 0 0 14px;
      line-height: 1.5;
    }
    .ds-page .ds-footer-loc .phone {
      font-family: 'Inter', system-ui, sans-serif;
      font-size: 15px;
      color: #eae8e8;
      font-weight: 500;
      margin-bottom: 18px;
      display: block;
    }
    .ds-page .ds-footer-loc .hours {
      display: grid;
      grid-template-columns: max-content 1fr;
      gap: 4px 12px;
      font-family: 'Inter', system-ui, sans-serif;
      font-size: 12px;
      color: rgba(234, 232, 232, 0.65);
    }
    .ds-page .ds-footer-loc .hours .val { white-space: nowrap; }
    .ds-page .ds-footer-bottom {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding-top: 56px;
      margin-top: 80px;
      font-family: 'Inter', system-ui, sans-serif;
      font-size: 12px;
      color: rgba(234, 232, 232, 0.5);
      gap: 24px;
      flex-wrap: wrap;
    }
    .ds-page .ds-footer-legal {
      display: flex;
      gap: 18px;
    }
    .ds-page .ds-footer-legal a {
      color: rgba(234, 232, 232, 0.5);
      text-decoration: none;
    }
    .ds-page .ds-footer-faster-link {
      color: #eae8e8;
      text-decoration: underline;
      text-underline-offset: 3px;
      transition: color 0.2s ease;
    }
    .ds-page .ds-footer-faster-link:hover { color: #fff; }

    /* TECHNOLOGY STACK — pinned scrollytelling section. 600vh runway holds 6 states; pinned content swaps image + counter + active list-item highlight as scroll progresses. */
    .ds-page .tech-stack-track {
      position: relative;
      z-index: 2;
      height: 600vh;
      background: var(--c-paper);
    }
    .ds-page .tech-stack-pinned {
      position: relative;
      height: 100vh;
      overflow: hidden;
    }
    .ds-page .tech-stack-grid {
      position: absolute;
      inset: 0;
      display: grid;
      grid-template-columns: minmax(140px, 1fr) minmax(0, 2.2fr) minmax(0, 2.4fr);
      align-items: center;
      padding: 0 6vw;
      column-gap: 2vw;
    }
    /* Counter — large numeral on the left */
    .ds-page .tech-counter {
      display: flex;
      align-items: baseline;
      gap: 6px;
      font-family: 'Instrument Serif', serif;
      font-weight: 400;
      color: var(--c-ink);
      justify-self: start;
    }
    .ds-page .tech-num {
      font-size: clamp(60px, 7vw, 132px);
      line-height: 1;
      letter-spacing: -0.02em;
      font-feature-settings: "lnum" 1;
    }
    .ds-page .tech-total {
      font-size: clamp(14px, 1.05vw, 18px);
      letter-spacing: 0.06em;
      color: rgba(37, 40, 45, 0.6);
    }
    /* Single image div for the pinned tech-stack section. `background-image` is set by techStackImage (textSequenceAnimation) which writes the URL string directly via domStringWrite as scroll progresses. No stacking, no opacity tricks. Uses .tech-stack-image (unique class) to avoid colliding with .tech-image used by .tech-block / team section. */
    /* Outer frame owns the layout slot. Fixed size + overflow:hidden so the
       inner scaled image is clipped to the frame's bounds and never expands
       past its allotted column on the grid. */
    .ds-page .tech-stack-image-frame {
      position: relative;
      width: min(100%, 44vh);
      aspect-ratio: 4 / 5;
      max-height: 62vh;
      overflow: hidden;
      justify-self: center;
      background: #0e1014;
    }
    /* Inner image holder — fills the frame, holds the graph-written
       background-image, and applies the --tech-img-scale Ken-Burns transform.
       Because it's a child of the overflow-hidden frame, scaling beyond 1.0
       crops INTO the image content rather than growing the layout box. */
    .ds-page .tech-stack-image {
      position: absolute;
      inset: 0;
      background: #0e1014 center / cover no-repeat;
      transform: scale(var(--tech-img-scale, 1));
      transform-origin: 50% 50%;
      will-change: transform;
    }

    /* List of tech items — right column. Active item color is written by techStackHighlight (staggerAnimation) directly on each `.tech-item:nth-child(N)`. The list translates UP one slot-height per state so the active item always sits at the top of the visible window. */
    .ds-page .tech-list-rightcol {
      display: flex;
      flex-direction: column;
      gap: 12px;
      align-self: stretch;
      justify-content: center;
    }
    .ds-page .tech-list-label {
      font-family: 'Inter', sans-serif;
      font-size: 12px;
      font-weight: 500;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: rgba(37, 40, 45, 0.55);
      padding: 0 0 14px;
      border-bottom: 1px solid rgba(37, 40, 45, 0.12);
    }
    /* Scroll window — clips the items so off-state ones disappear cleanly. Height = 4 slot-heights so the active + 3 upcoming are always visible. */
    .ds-page .tech-list-window {
      position: relative;
      overflow: hidden;
      height: calc(var(--tech-slot-h, 14vh) * 4);
    }
    .ds-page .tech-list-items {
      list-style: none;
      margin: 0;
      padding: 0;
      font-family: 'Instrument Serif', serif;
      /* Pure plug-in: --tech-list-y is the FINAL translateY (in vh) computed by the graph (techStackList propertyAnimation, 0vh → -70vh = 5 slot heights). No CSS animation math. */
      transform: translateY(var(--tech-list-y, 0));
      will-change: transform;
    }
    .ds-page .tech-item {
      display: flex;
      align-items: baseline;
      justify-content: space-between;
      gap: 12px;
      height: var(--tech-slot-h, 14vh);
      padding: 0;
      border-bottom: 1px solid rgba(37, 40, 45, 0.12);
      /* Default inactive color. The graph's techStackHighlight (staggerAnimation with a `color` channel) writes the live color directly to each .tech-item via per-child domPoseWrite — no CSS color-mix recipe. */
      color: rgba(37, 40, 45, 0.32);
    }
    .ds-page .tech-item .name {
      font-size: clamp(32px, 3vw, 56px);
      line-height: 1.05;
      letter-spacing: -0.01em;
      font-weight: 400;
      align-self: center;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      min-width: 0;
    }
    .ds-page .tech-item .learn {
      font-family: 'Inter', sans-serif;
      font-size: 11px;
      font-weight: 500;
      letter-spacing: 0.12em;
      color: inherit;
      text-decoration: underline;
      text-underline-offset: 4px;
      flex-shrink: 0;
      align-self: center;
    }

    /* TECHNOLOGY block: 130vh image + two absolute headlines whose translateY is graph-driven via --tech-main-ty / --tech-rest-ty (techMainTy scrollTween). See techMainTy's _doc in the .fmtion for keyframe + phase details. */
    .ds-page .tech-block {
      position: relative;
      z-index: 2;
      /* 185vh runway: 130vh image phase + ~55vh exit. The .tech-headline-rest holds 3 cream lines at clamp(34px,4.4vw,86px) line-height 0.96 ≈ 28vh tall. At its peak ty=152vh, content spans 152-180vh. Block height must ≥ 180vh or the next section's cream/photo backdrop covers the bottom of "Dentistry" / "Results" lines. */
      height: 185vh;
      background: var(--c-paper);
    }
    .ds-page .tech-image {
      position: relative;
      height: 130vh;
      width: 100%;
      background-image: url('https://images.unsplash.com/photo-1486325212027-8081e485255e?w=2400&auto=format&fit=crop&q=85');
      background-size: cover;
      background-position: center;
      filter: grayscale(1) brightness(0.4) contrast(1.18);
    }
    /* translateY driven by --tech-main-ty (techMainTy scrollTween). Sub-rate, not strict pin — visual y eases 95vh→44vh while image is dominant, then exits. */
    .ds-page .tech-headline-main {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      margin: 0;
      padding: 0 4vw;
      text-align: center;
      transform: translateY(var(--tech-main-ty, 95vh));
      will-change: transform;
      font-family: 'Instrument Serif', serif;
      font-weight: 400;
      font-size: clamp(64px, 8vw, 160px);
      line-height: 1.0;
      letter-spacing: -0.015em;
      color: #fff;
      mix-blend-mode: difference;
      pointer-events: none;
      z-index: 3;
    }
    /* translateY driven by --tech-rest-ty: holds 132vh below image, then 152vh stacked below main, then exits with main. */
    .ds-page .tech-headline-rest {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      margin: 0;
      padding: 0 4vw;
      text-align: center;
      transform: translateY(var(--tech-rest-ty, 132vh));
      will-change: transform;
      font-family: 'Instrument Serif', serif;
      font-weight: 400;
      /* Sized so 3 lines fit in the ~25vh window between main_bottom
         (≈73vh) and the viewport bottom. */
      font-size: clamp(34px, 4.4vw, 86px);
      line-height: 0.96;
      letter-spacing: -0.01em;
      color: #fff;
      mix-blend-mode: difference;
    }
    .ds-page .tech-headline-rest .line { display: block; white-space: nowrap; }
    .ds-page .tech-headline-rest em { font-style: italic; }

    /* RESPONSIVE BREAKPOINTS
       Three tiers: 1200 (tablet), 900 (small tablet / large phone), 600 (mobile).
       Strategy: keep the desktop graph-driven scroll choreography intact above 900px;
       below 900px collapse multi-column layouts to single column and disable the most
       layout-fragile animation surfaces (wu-balls physics stage, hero clip-path split,
       portrait crossfade pin) by reducing them to static fallbacks. We do NOT rebuild
       the scroll graph for mobile — the graph is desktop-canonical; mobile gets a
       readable static-ish version of the same content. */

    @media (max-width: 1200px) {
      .ds-page .hero-nav { padding: 18px 22px; }
      .ds-page .hero-nav-left { gap: 32px; }
      .ds-page .hero-nav-center { gap: 24px; }
      .ds-page .hero-nav-right { gap: 10px; }
      .ds-page .hero-nav-right .cta { padding: 12px 12px 12px 22px; font-size: 13px; }
      .ds-page .ds-footer-cols { grid-template-columns: 1fr 1fr 1.6fr; gap: 3vw; }
    }

    @media (max-width: 1100px) {
      /* Header on tablet/phone: keep the Menu trigger (fullscreen overlay
         works fine here) but hide the Services trigger — its popover is a
         desktop-pattern backdrop+grid that doesn't fit a phone viewport.
         Users still reach Services from inside the Menu overlay. */
      .ds-page .hero-nav-center { gap: 0; }
      .ds-page .hero-nav-center button.hero-services-trigger { display: none; }
      .ds-page .hero-nav-right .form { display: none; }
      .ds-page .hero-nav-right .phone .city { display: none; }
      .ds-page .hero-nav { padding: 14px 16px; gap: 12px; }
      .ds-page .hero-nav-left { gap: 28px; flex: 0 1 auto; min-width: 0; }
      .ds-page .hero-nav-right { flex: 0 0 auto; gap: 12px; }
      .ds-page .hero-menu-trigger { font-size: 13px; padding: 8px 12px; }
      .ds-page .hero-logo { gap: 10px; font-size: 12px; }
      .ds-page .hero-logo .mark { width: 36px; height: 24px; flex: 0 0 36px; }
      .ds-page .hero-logo .brand { white-space: nowrap; }
      /* Drop the "Strategic Advisory" subline so brand stays single-line
         and doesn't crash into the Menu trigger. */
      .ds-page .hero-logo .brand-l2,
      .ds-page .hero-logo .brand br { display: none; }
      /* Hide phone email on tablet/phone — too long to fit alongside CTA. */
      .ds-page .hero-nav-right .phone-area { display: none; }
      /* Keep CTA on one line, tighten padding. */
      .ds-page .hero-nav-right .cta {
        white-space: nowrap;
        padding: 8px 10px 8px 14px;
        font-size: 12px;
        gap: 8px;
        flex: 0 0 auto;
      }
      .ds-page .hero-nav-right .cta .cta-plus {
        width: 22px; height: 22px; flex: 0 0 22px;
      }

      /* Hero right-column reflow on tablet:
         Desktop puts .hero-caption at left:calc(50% + 2vw) max-w 420px
         AND .hero-tagline at right:28px max-w 320px BOTH at bottom:4vh —
         on viewports between ~600 and 1100 the right half is too narrow
         to hold them side-by-side, so they collide. Stack vertically on
         the right edge: caption higher, tagline at the bottom. */
      .ds-page .hero-caption {
        left: auto;
        right: 22px;
        bottom: 22vh;
        max-width: min(60vw, 380px);
        font-size: clamp(20px, 2.6vw, 26px);
        text-align: right;
      }
      .ds-page .hero-tagline {
        right: 22px;
        bottom: 8vh;
        max-width: min(58vw, 300px);
        font-size: 12px;
      }
      /* Hero meta tighten — it's bottom-left and stays in the cream
         pane, but pad away from the edge a bit. */
      .ds-page .hero-meta {
        left: 22px;
        bottom: 8vh;
        font-size: 12px;
      }
      /* Services strip can wrap on tablet so 3 items don't run together. */
      .ds-page .hero-services {
        font-size: 11px;
        padding: 0 4vw;
        gap: 12px;
        flex-wrap: wrap;
        justify-content: center;
      }
      /* Hero overlay (slide-in italic line) shrinks for tablet width. */
      .ds-page .hero-overlay {
        font-size: clamp(44px, 6.4vw, 88px);
        padding: 0 5vw;
      }

      /* Outro: keep full-bleed photo, reduce title to readable scale, kill side padding. */
      .ds-page .outro { height: 110vh; min-height: 720px; }
      .ds-page .outro-inner { padding: 6vh 6vw 12vh; }
      .ds-page .outro-title { font-size: clamp(56px, 14vw, 120px); }

      /* Footer: drop to 2 cols on top, 1-col location stack. */
      .ds-page .ds-footer-cols { grid-template-columns: 1fr 1fr; gap: 32px; margin-top: 60px; }
      .ds-page .ds-footer-locations { grid-template-columns: 1fr; gap: 28px; }
      .ds-page .ds-footer-bottom { flex-direction: column; gap: 16px; align-items: flex-start; padding-top: 36px; margin-top: 56px; }
      .ds-page .ds-footer-top { flex-direction: column; align-items: flex-start; gap: 32px; }
      .ds-page .ds-footer-cta { font-size: clamp(36px, 9vw, 64px); }

      /* Why-us mobile: paired with whyUsCircles overrides + whyUsCupMaskMobile
         in the .fmtion. The graph rotates the circles wrapper 90° and writes
         --wu-mask-cut on .wu-circle so the top half cuts to transparent.
         Headlines re-center as a stacked column in the middle. */
      .ds-page .wu-circle {
        -webkit-mask-image: linear-gradient(to right, transparent calc(var(--wu-mask-cut, 0%) - 0.5%), black var(--wu-mask-cut, 0%));
        mask-image: linear-gradient(to right, transparent calc(var(--wu-mask-cut, 0%) - 0.5%), black var(--wu-mask-cut, 0%));
        width: min(95vw, 70vh);
        height: min(95vw, 70vh);
      }
      .ds-page .wu-circle-left  { left: calc(0px - var(--wu-spread-factor, 1) * min(47.5vw, 35vh)); }
      .ds-page .wu-circle-right { left: calc(var(--wu-spread-factor, 1) * min(47.5vw, 35vh)); }
      .ds-page .wu-headline { font-size: clamp(48px, 14vw, 80px); line-height: 1; }
      .ds-page .wu-h-left, .ds-page .wu-h-right, .ds-page .wu-h-bottom {
        left: 50%; right: auto;
        text-align: center;
        white-space: nowrap;
        transform: translate(-50%, -50%);
      }
      .ds-page .wu-h-left   { top: 42%; }
      .ds-page .wu-h-right  { top: 50%; }
      .ds-page .wu-h-bottom { top: 58%; }
      /* Make balls touch-draggable on mobile (physicsMouseDrag is enabled
         only when prefers-reduced-motion: no-preference). */
      .ds-page .wu-ball { touch-action: none; pointer-events: auto; }
      /* Per-ball tablet sizing — preserves desktop variety at ~50% scale.
         !important overrides the inline `--bd:Xpx` style on each ball;
         the physics body reads --bd via radiusFromCSS so collider radii
         match the visual size. */
      .ds-page .wu-ball:nth-child(1) { --bd: 85px !important; }
      .ds-page .wu-ball:nth-child(2) { --bd: 100px !important; }
      .ds-page .wu-ball:nth-child(3) { --bd: 115px !important; }
      .ds-page .wu-ball:nth-child(4) { --bd: 70px !important; }
      .ds-page .wu-ball:nth-child(5) { --bd: 65px !important; }
      .ds-page .wu-ball:nth-child(6) { --bd: 120px !important; }

      /* CAPABILITIES — Tech block mobile: paired with techMainTyMobile in
         the .fmtion (different keyframe values). CSS shrinks the section
         height + headline type so the graph-driven translateY values land
         in the right viewport positions. */
      .ds-page .tech-block { height: 150vh; }
      .ds-page .tech-image { height: 100vh; }
      .ds-page .tech-headline-main {
        font-size: clamp(36px, 10vw, 72px);
        padding: 0 22px;
      }
      .ds-page .tech-headline-rest {
        font-size: clamp(28px, 8vw, 56px);
        padding: 0 22px;
      }

      /* CAPABILITIES — Tech-stack mobile LAYOUT only. The graph owns motion
         (techStackListMobile activeWhen, --tech-list-y range tightened to
         -40vh). CSS stacks the 3-col grid, shrinks the image frame, and
         drops --tech-slot-h to 8vh so 6 items fit a 100vh pinned window. */
      .ds-page .tech-stack-grid {
        grid-template-columns: 1fr;
        gap: 16px;
        padding: 4vh 22px;
        align-items: start;
        align-content: start;
      }
      .ds-page .tech-stack-image-frame {
        width: auto;
        height: 24vh;
        max-height: 24vh;
        max-width: 60vw;
        justify-self: center;
      }
      .ds-page .tech-counter { font-size: clamp(20px, 5vw, 30px); }
      .ds-page .tech-list-items { font-size: clamp(16px, 3.5vw, 22px); }
      .ds-page .tech-stack-pinned { --tech-slot-h: 8vh; }
    }

    @media (max-width: 600px) {
      /* Hero title: smaller clamp + allow wrapping. Kill the L/R clip-path
         split (needs equal widths to read as ink↔white) and hide the white
         twin so we get a single readable headline. */
      .ds-page .hero-title {
        font-size: clamp(36px, 10vw, 64px);
        white-space: normal;
        text-align: left;
        padding: 0 22px;
      }
      .ds-page .hero-title.ink, .ds-page .hero-title.white { clip-path: none; }
      .ds-page .hero-title.white { display: none; }

      /* Mobile hero layout — stack cream pane on top (where text sits) and
         video on the bottom so the video is always visible. The desktop's
         grid-template-columns: 50% auto becomes vertical rows. */
      .ds-page .hero-bg {
        grid-template-columns: 1fr;
        grid-template-rows: 70% 30%;
      }
      .ds-page .hero-bg .img-pane { display: block; }
      /* Override the desktop clip-path that hides the video until the scroll
         animation runs — on mobile the pinned scrollTrigger doesn't engage
         cleanly, so reveal the video statically. */
      .ds-page .hero-bg .img-pane .img { clip-path: none; }

      /* Re-flow the absolute-positioned hero elements as a vertical stack
         so they don't pile up on top of each other. Each gets an explicit
         top: value with breathing room between. */
      .ds-page .hero-meta {
        top: 84px; bottom: auto;
        left: 22px; right: 22px;
        font-size: 11px;
        line-height: 1.3;
      }
      /* Compact hero-meta to a single horizontal line on phones so it
         doesn't push into the title block. */
      .ds-page .hero-meta .label,
      .ds-page .hero-meta .city {
        display: inline;
        margin: 0 8px 0 0;
      }
      .ds-page .hero-title-stack {
        top: 26vh; bottom: auto;
        transform: translate(var(--hero-tx, 0%), 0);
      }
      .ds-page .hero-caption {
        top: 44vh; bottom: auto;
        left: 22px; right: 22px;
        max-width: none;
        font-size: 16px;
        color: var(--c-ink);
        text-align: left;
      }
      .ds-page .hero-tagline {
        top: 52vh; bottom: auto;
        left: 22px; right: 22px;
        max-width: none;
        text-align: left;
        color: rgba(37, 40, 45, 0.7);
        font-size: 12px;
        line-height: 1.45;
      }
      .ds-page .hero-services {
        bottom: 4vh; top: auto;
        left: 22px; right: 22px;
        gap: 14px; padding: 0;
        flex-wrap: wrap; justify-content: flex-start;
        opacity: 1;
      }

      /* Hide hero phone (only CTA + logo remain). */
      .ds-page .hero-nav-right .phone { display: none; }
      .ds-page .hero-nav-right .cta {
        padding: 8px 8px 8px 14px;
        font-size: 11px;
        gap: 8px;
        white-space: nowrap;
      }
      .ds-page .hero-nav-right .cta .cta-plus {
        width: 22px; height: 22px; flex: 0 0 22px;
      }

      /* Outro: smaller min-height for short phones. */
      .ds-page .outro { height: 100vh; min-height: 600px; }
      .ds-page .outro-eyebrow { font-size: 10px; }
      .ds-page .outro-title { font-size: clamp(44px, 13vw, 72px); line-height: 0.92; }

      /* Footer: single-column everything. */
      .ds-page .ds-footer { padding: 80px 22px 32px; }
      .ds-page .ds-footer-top {
        grid-template-columns: 1fr;
        gap: 32px;
        margin-bottom: 60px;
      }
      .ds-page .ds-footer-socials { flex-direction: row; }
      .ds-page .ds-footer-cta {
        font-size: clamp(28px, 7vw, 40px);
        margin-bottom: 32px;
      }
      .ds-page .ds-form-radios { gap: 14px; }
      .ds-page .ds-form-row { grid-template-columns: 1fr; }
      .ds-page .ds-form-message-row { grid-template-columns: 1fr; gap: 12px; }
      .ds-page .ds-form-submit { justify-self: end; }
      .ds-page .ds-footer-locations { grid-template-columns: 1fr; }

      /* Why-us mobile layout is in the 1100px block + graph overrides
         (whyUsCircles overrides for max-width: 1100px, whyUsCupMaskMobile,
         whyUsBalls.initialXSpacing/jitter overrides). Phone-only ball
         sizing below tightens .wu-ball --bd values. */
      .ds-page .wu-ball:nth-child(1) { --bd: 56px !important; }
      .ds-page .wu-ball:nth-child(2) { --bd: 66px !important; }
      .ds-page .wu-ball:nth-child(3) { --bd: 76px !important; }
      .ds-page .wu-ball:nth-child(4) { --bd: 46px !important; }
      .ds-page .wu-ball:nth-child(5) { --bd: 43px !important; }
      .ds-page .wu-ball:nth-child(6) { --bd: 80px !important; }
    }

/* ── LONE1 OVERRIDES ───────────────────────────────────────────────
   Beat the theme's index.css h1-h6 color rule (which sets a dark
   color on every heading) so editorial sections inherit their
   container's color. Also style the brand-mark <img> tags. */
.ds-page h1,
.ds-page h2,
.ds-page h3,
.ds-page h4,
.ds-page h5,
.ds-page h6,
.ds-menu-overlay h1,
.ds-menu-overlay h2,
.ds-menu-overlay h3,
.ds-menu-overlay h4,
.ds-menu-overlay h5,
.ds-menu-overlay h6 {
  color: inherit;
  font-family: inherit;
  letter-spacing: inherit;
  line-height: inherit;
  margin: 0;
}

/* Header logo: render the Lone1 mark image in its native navy + gold
   on the cream header background. Responsive variants below match the
   reference's @media (max-width: 1100px) override; they MUST live in
   their own @media wrappers since this block ships AFTER the
   reference @media blocks (cascade order would otherwise win). */
.ds-page .hero-logo img.mark {
  width: auto;
  height: 48px;
  display: block;
}
@media (max-width: 1100px) {
  .ds-page .hero-logo img.mark { height: 32px; }
}
/* Menu overlay logo: inline SVG with explicit fills (L = cream-white,
   1 + star = brand gold), matching the footer mark. */
.ds-menu-overlay .ds-menu-logo svg.ds-menu-mark {
  width: 50px;
  height: 32px;
  display: block;
}
@media (max-width: 1100px) {
  .ds-menu-overlay .ds-menu-logo svg.ds-menu-mark { width: 38px; height: 24px; }
}
/* Footer arch mark: inline SVG with explicit fills (L = cream-white,
   1 + star = brand gold) so we don't need the filter trick. */
.ds-page svg.ds-footer-mark {
  position: absolute;
  top: -3vh;
  left: 50%;
  transform: translateX(-50%);
  width: 88px;
  height: auto;
  display: block;
}

/* ── ADDITIONAL RESPONSIVE COVERAGE ─────────────────────────────────
   The reference's @media blocks cover hero/header/footer/why-us but
   miss several full-bleed sections that read fine on desktop and
   break on mobile. Add the missing rules here. */

/* Guard against horizontal scroll on narrow viewports — the reference
   uses many position:fixed full-width elements that can spill outside
   the viewport on phones. clip preserves sticky/fixed positioning;
   hidden would break it. */
@media (max-width: 1100px) {
  html, body { overflow-x: clip; }
}

@media (max-width: 1100px) {
  /* Hero text positioning — at narrow widths, vw-based bottoms collide. */
  .ds-page .hero-title { font-size: clamp(40px, 11vw, 72px); }
  /* Desktop is clamp(54px, 7.6vw, 132px) which at 900px yields ~68px.
     At nowrap that overflows the viewport, so on tablet widths shrink
     a bit and allow wrapping if needed. */
  .ds-page .hero-overlay {
    font-size: clamp(32px, 5.6vw, 64px);
    white-space: normal;
    line-height: 1.05;
  }
  .ds-page .hero-services { font-size: 11px; gap: 12px; flex-wrap: wrap; }

  /* Hero caption ("Independent counsel...") and tagline ("Fractional CIO &
     CTO leadership...") both anchor to bottom: 4vh on desktop — caption
     at left: calc(50% + 2vw) max-width 420px, tagline at right: 28px
     max-width 320px. At tablet widths their boxes collide horizontally.
     Stack them vertically along the right edge: caption above tagline,
     each pinned to right: 28px. Caption uses calc() to clear the tagline
     so a 4–5 line tagline at narrow widths still has clear separation.
     Both clamp width and font so they breathe even at 1024px. */
  .ds-page .hero-caption {
    left: auto;
    right: 28px;
    bottom: calc(4vh + 120px);
    max-width: min(60vw, 360px);
    font-size: clamp(20px, 2.4vw, 24px);
    line-height: 1.18;
    text-align: right;
  }
  .ds-page .hero-tagline {
    right: 28px;
    bottom: 4vh;
    max-width: min(48vw, 280px);
    font-size: 12px;
    line-height: 1.4;
  }
  .ds-page .hero-meta {
    left: 28px; bottom: 4vh;
    font-size: 12px;
    max-width: 38vw;
  }

  /* Hero spacer is 220vh — at phone heights that's a long empty scroll
     before the pin engages. Reduce to 130vh on mobile. */
  .ds-page .hero-spacer { height: 130vh; }

  /* Safety net: if the scroll-driven title reveal hasn't fired (mobile
     pinned scrollTriggers can be flaky), keep characters visible by
     default so the title is always readable. The .fmtion still animates
     them on top of these baseline values. */
  .ds-page .hero-title .ft-split-char {
    opacity: 1;
    transform: translateY(0);
  }

  /* === WHAT WE DO — pinned crossfade kept; right column gets full viewport ===
     Desktop reserves the left half for the pinned portrait and absolutely
     positions the right column on the right half. On mobile we hide the
     portrait, drop rightcol's absolute positioning so it flows inside
     .services as a normal block, and let the Learn More CTA flow as a
     sibling right below it. Pin engine + crossfade + cycling title stay
     intact. */
  /* Keep position:relative (NOT static) so the base
     `.services > * { z-index: 1 }` rule still wins against
     `.services::before` (z:0 absolute dark overlay). Static would
     drop it below the overlay and read as "empty section". */
  .ds-page .services-rightcol {
    position: relative;
    top: auto; left: auto; right: auto; bottom: auto;
    margin: 6vh 4vw 0;
    width: auto;
    gap: 14px;
    z-index: 1;
  }
  .ds-page .services-blurb {
    max-width: none;
    font-size: clamp(15px, 3vw, 18px);
  }
  /* Two-up scanner | list grid is too cramped — let the list breathe. */
  .ds-page .services-grid {
    grid-template-columns: minmax(120px, 32vw) 1fr;
    column-gap: 18px;
  }
  .ds-page .services-list li { font-size: 15px; padding: 10px 0; }
  /* CTA flows below the rightcol on mobile rather than absolute
     bottom-right of the pinned section. All 4 CTAs occupy the same
     grid cell so only the active one is visible (opacity flip retained). */
  .ds-page .services-cta {
    position: absolute;
    top: auto; left: 4vw; right: 4vw; bottom: 4vh;
    margin: 0;
    align-self: flex-start;
    z-index: 1;
    justify-content: center;
  }
  /* Cycling fixed-position title is calibrated for full-viewport width;
     shrink so it fits. */
  .ds-page .services-title { font-size: clamp(56px, 13vw, 110px); }
  /* Side-nav at bottom-left collides with the CTA at bottom-right on
     narrow widths — hide it; the cycling title already shows progress. */
  .ds-page .services-meta { display: none; }


  /* === TEAM TOP / TEAM GOAL — stacked single-column on mobile === */
  /* The portrait-anchor is position:absolute 50vw × 100vh — it covers the
     left half of pin-wrap and squeezes text into the right edge. Hide
     it entirely; the pinned scroll choreography doesn't read well on
     phones anyway. */
  .ds-page .portrait-anchor { display: none; }

  /* team-top: collapse the 4-col grid to a single column, override the
     explicit grid-column placements on children so they stack naturally,
     and hide the portrait slot (the absolute portrait that filled it is
     gone). */
  .ds-page .team-top {
    display: flex;
    flex-direction: column;
    gap: 24px;
    padding: 6vh 22px;
  }
  .ds-page .team-portrait-slot { display: none; }
  .ds-page .team-paragraph {
    grid-column: auto; grid-row: auto;
    max-width: none;
    font-size: clamp(16px, 3.6vw, 20px);
    line-height: 1.55;
  }
  .ds-page .team-avatars { grid-column: auto; grid-row: auto; }

  /* team-goal: same treatment. Drop the fixed 100vh height (forces
     content into a clipped view), kill the blur/darken filter (those
     are scroll-driven and stay stuck on a static layout), single-col
     stack, hide the absolute portrait spacer. */
  .ds-page .team-goal {
    display: flex;
    flex-direction: column;
    gap: 28px;
    padding: 8vh 22px;
    height: auto;
    filter: none;
  }
  .ds-page .team-goal::after { display: none; }
  .ds-page .team-goal-lead {
    font-size: clamp(36px, 9vw, 64px);
    text-align: left;
    line-height: 1;
  }
  .ds-page .goal-portrait-spacer { display: none; }
  .ds-page .team-goal-col { width: 100%; }
  .ds-page .team-goal-words {
    font-size: clamp(22px, 5.4vw, 32px);
    line-height: 1.15;
    max-width: none;
  }
  /* Reveal all the scroll-driven split chars/words at full opacity since
     the scroll trigger may not engage on a static-flow layout. */
  .ds-page .team-goal-words .ft-split-char,
  .ds-page .team-goal-words .ft-split-word { opacity: 1; }
  .ds-page .team-goal-button { margin-top: 24px; }

  /* CAPABILITIES (tech-block + tech-stack) mobile layout is in the first
     1100px block above (paired with techMainTyMobile / techStackListMobile
     graph nodes that activeWhen on the same breakpoint). */

  /* Team-experts: 3-col card grid stacks to 1-col. */
  .ds-page .te-cards { grid-template-columns: 1fr; gap: 24px; padding: 0 22px; }
  .ds-page .te-title { font-size: clamp(56px, 14vw, 96px); padding: 0 22px; }
  .ds-page .te-cta { grid-template-columns: 1fr; gap: 24px; padding: 0 22px; }
  .ds-page .te-cta-line { font-size: clamp(24px, 6vw, 40px); }

  /* Testimonials: 2-col (list | quote) stacks. Cursor hidden on mobile. */
  .ds-page .ts-grid { grid-template-columns: 1fr; gap: 24px; padding: 8vh 22px 4vh; }
  .ds-page .ts-col-right { padding-left: 0; padding-right: 0; border-left: 0; border-top: 1px solid rgba(234, 232, 232, 0.18); padding-top: 24px; min-height: 50vh; }
  .ds-page .ts-quote-box { padding-left: 0; padding-right: 0; }
  .ds-page .ts-quote { font-size: clamp(17px, 4vw, 22px); }
  .ds-page .ts-cursor { display: none; }

  /* === Menu overlay (full-screen) — tablet/phone === */
  /* Stack the 2-col inner grid (top-left + services side-by-side on desktop)
     into a single column so services fill the width, logo+close stay on top. */
  .ds-menu-inner {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto;
    padding: 22px 22px 28px;
    column-gap: 0;
    row-gap: 28px;
    overflow-y: auto;
  }
  .ds-menu-top-left { grid-column: 1; grid-row: 1; justify-content: space-between; gap: 16px; }
  .ds-menu-services { grid-column: 1; grid-row: 2; gap: 18px; }
  .ds-menu-services-title { font-size: clamp(32px, 7vw, 56px); }
  .ds-menu-services-grid { grid-template-columns: repeat(2, 1fr); gap: 14px; }
  .ds-menu-bottom { grid-column: 1; grid-row: 3; grid-template-columns: 1fr; gap: 28px; align-items: start; }
  .ds-menu-bottom-left { gap: 22px; }
  .ds-menu-nav { grid-template-columns: 1fr; row-gap: 6px; }
  .ds-menu-nav a { font-size: clamp(36px, 9vw, 64px); }
  .ds-menu-socials .soc { width: 56px; height: 56px; font-size: 22px; }
  .ds-menu-socials .soc svg { width: 24px; height: 24px; }

  /* Services popover/backdrop are desktop-only — hide on tablet/phone.
     The Services trigger button is already hidden, but force-hide the
     popover layers too so they can't render even if their open state
     gets toggled. Users reach Services via the full-screen Menu. */
  .ds-page .services-popover,
  .ds-page .services-backdrop { display: none !important; }
}

@media (max-width: 600px) {
  /* Tighter still on phones — single-col services in the menu. */
  .ds-menu-services-grid { grid-template-columns: 1fr; gap: 12px; }
  .ds-menu-services-grid .svc-card .svc-img { aspect-ratio: 16 / 9; }
  .ds-menu-bottom-left { gap: 18px; }
  .ds-menu-socials { gap: 12px; }
  .ds-menu-socials .soc { width: 48px; height: 48px; font-size: 18px; }
  .ds-menu-socials .soc svg { width: 20px; height: 20px; }
  .ds-menu-links a { font-size: 13px; padding: 12px 0; }
  .ds-menu-nav a { font-size: clamp(32px, 10vw, 48px); }
}

@media (max-width: 600px) {
  /* Hero overlay text on the cream pane is tight on phones. */
  .ds-page .hero-meta { padding: 0; gap: 8px; flex-wrap: wrap; }
  /* Restore the "Technology, translated into outcomes" slide-in. The
     desktop nowrap + 132px font won't fit; allow wrapping, shrink, and
     center it vertically in the cream-pane area (top 70% of hero) which
     darkens during scroll — sliding into that empty dark band rather
     than over the video below. The .fmtion still drives --overlay-tx. */
  .ds-page .hero-overlay {
    display: block;
    top: 35vh;
    bottom: auto;
    transform: translate(var(--overlay-tx, 100%), -50%);
    white-space: normal;
    font-size: clamp(28px, 7vw, 44px);
    line-height: 1.08;
    padding: 0 22px;
    text-align: center;
    color: #ffffff;
  }

  /* Tech-stack image frame smaller still. */
  .ds-page .tech-stack-image-frame { max-height: 32vh; }

  /* Phone email is long — at very narrow widths it wraps awkwardly. */
  .ds-page .hero-nav-right .phone-area { display: none; }
}

/* === Footer engagement form === */
.ds-page .ds-footer-form { display: contents; }
.ds-page .ds-footer .ds-form-radios {
  align-items: center;
  row-gap: 12px;
  flex-wrap: wrap;
}
.ds-page .ds-footer .ds-form-radio {
  align-items: center;
  white-space: nowrap;
  line-height: 18px;
  height: 18px;
  padding: 0;
  margin: 0;
}
.ds-page .ds-footer .ds-form-radio .dot {
  flex: 0 0 18px;
  width: 18px;
  height: 18px;
  align-self: center;
  vertical-align: middle;
  box-sizing: border-box;
}
.ds-page .ds-footer .ds-form-radio > * { vertical-align: middle; }
.ds-page .ds-footer .ds-form-radio input[type="radio"] {
  display: none !important;
  width: 0; height: 0; margin: 0; padding: 0; border: 0;
}
.ds-page .ds-footer .ds-form-radio .lbl {
  display: inline-flex;
  align-items: center;
  height: 18px;
  line-height: 18px;
}
.ds-page .ds-footer .ds-form-message {
  background: transparent;
  border: 1px solid rgba(234, 232, 232, 0.35);
  border-radius: 999px;
  color: #eae8e8;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 15px;
  padding: 18px 28px;
  resize: none;
  outline: none;
  width: 100%;
  height: 56px;
  min-height: 56px;
  line-height: 20px;
  overflow: hidden;
  box-sizing: border-box;
  display: block;
}
.ds-page .ds-footer .ds-form-message::placeholder { color: rgba(234, 232, 232, 0.55); }
.ds-page .ds-footer .ds-form-message:focus { border-color: #c89a3a; }
.ds-page .ds-footer .ds-form-input {
  border-color: rgba(234, 232, 232, 0.35);
  color: #eae8e8;
}
.ds-page .ds-footer .ds-form-input::placeholder { color: rgba(234, 232, 232, 0.55); }
.ds-page .ds-footer .ds-form-input:focus { border-color: #c89a3a; }
.ds-page .ds-form-captcha { margin-top: 18px; min-height: 0; }
.ds-page .ds-form-captcha:not(:empty) { margin-top: 18px; }
.ds-page .ds-form-status {
  margin: 12px 0 0;
  font-size: 13px;
  letter-spacing: 0.02em;
  color: rgba(234, 232, 232, 0.7);
  min-height: 1em;
}
.ds-page .ds-form-status[data-kind="success"] { color: #c89a3a; }
.ds-page .ds-form-status[data-kind="error"] { color: #e98a8a; }
.ds-page .ds-form-submit:disabled { opacity: 0.55; cursor: progress; }

/* ══════════════════════════════════════════════════════════════════════
   LONE1 DESIGN SYSTEM — shared sub-page primitives (.l1-*)
   ──────────────────────────────────────────────────────────────────────
   Reusable building blocks for any non-home page (contact, about,
   service detail, blog index, etc.). Tokens come from .ds-page above:
   --c-cream, --c-paper, --c-ink, --c-deep, --c-line, --c-gold,
   --c-gold-soft, --c-error.

   Usage example (contact page hero):
     <section class="l1-page-hero">
       <div class="l1-page-hero-bg" style="background-image:url(...)"></div>
       <div class="l1-page-hero-vignette"></div>
       <div class="l1-page-hero-inner">
         <p class="l1-eyebrow l1-eyebrow--gold-rule">Eyebrow</p>
         <h1 class="l1-page-hero-title">Headline <em>italic</em></h1>
       </div>
     </section>
   ══════════════════════════════════════════════════════════════════════ */

/* ── PAGE HERO (dark band, serif italic title, optional meta strip) ── */
.ds-page .l1-page-hero {
  position: relative;
  min-height: 92vh;
  background: var(--c-deep);
  color: #f6f4ef;
  overflow: hidden;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 22vh 6vw 12vh;
}
.ds-page .l1-page-hero-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-size: cover;
  background-position: 50% 35%;
  filter: contrast(1.15) brightness(0.32) saturate(0.55);
}
.ds-page .l1-page-hero-vignette {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(ellipse 70% 80% at 30% 70%, rgba(22, 25, 34, 0) 0%, rgba(22, 25, 34, 0.85) 100%),
    linear-gradient(180deg, rgba(22, 25, 34, 0.55) 0%, rgba(22, 25, 34, 0.85) 100%);
  pointer-events: none;
}
.ds-page .l1-page-hero-inner {
  position: relative;
  z-index: 2;
  max-width: 1400px;
  width: 100%;
  margin: 0 auto;
}
.ds-page .l1-page-hero-title {
  font-family: 'Instrument Serif', serif;
  font-size: clamp(64px, 11vw, 180px);
  line-height: 0.92;
  letter-spacing: -0.02em;
  font-weight: 400;
  margin: 0;
  max-width: 14ch;
  color: #f6f4ef;
}
.ds-page .l1-page-hero-title em {
  font-style: italic;
  color: var(--c-gold);
}
.ds-page .l1-page-hero-meta {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 32px;
  margin-top: 64px;
  padding-top: 28px;
  border-top: 1px solid rgba(246, 244, 239, 0.18);
}
.ds-page .l1-page-hero-meta-item .label {
  display: block;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(246, 244, 239, 0.55);
  margin-bottom: 8px;
}
.ds-page .l1-page-hero-meta-item .value {
  font-family: 'Instrument Serif', serif;
  font-size: clamp(20px, 2vw, 26px);
  line-height: 1.25;
  color: #f6f4ef;
}
.ds-page .l1-page-hero-meta-item .value em { font-style: italic; }

/* ── TYPEWRITER WORD (single-word char-stagger reveal target) ───────
   Apply to any inline word that should reveal character-by-character
   on page load. The page's .fmtion file handles the actual animation
   (loadPulse → pulseTween → textStaggerAnimation). The CSS here
   provides the initial-state guard so chars start clipped below the
   word's own box (no FOUC before .fmtion binds). Mirrors the home
   page's .hero-title .tline + .ft-split-char pattern. */
.ds-page .l1-typewriter {
  display: inline-block;
  overflow: hidden;
  vertical-align: baseline;
  /* Tight padding-bottom so descenders ('y' in "technology") aren't
     visually cropped by the overflow:hidden box. */
  padding: 0.04em 0 0.16em;
}
.ds-page .l1-typewriter .ft-split-char {
  display: inline-block;
  will-change: transform, opacity;
}

/* ── EYEBROW (small uppercase Inter label) ──────────────────────────── */
.ds-page .l1-eyebrow {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--c-ink);
  opacity: 0.55;
  margin: 0 0 24px;
}
/* Variant: gold ink, no opacity, no rule */
.ds-page .l1-eyebrow--gold {
  color: var(--c-gold);
  opacity: 1;
}
/* Variant: gold ink with leading horizontal hairline rule */
.ds-page .l1-eyebrow--gold-rule {
  color: var(--c-gold);
  opacity: 1;
  display: inline-flex;
  align-items: center;
  gap: 14px;
}
.ds-page .l1-eyebrow--gold-rule::before {
  content: '';
  display: inline-block;
  width: 36px;
  height: 1px;
  background: var(--c-gold);
}

/* ── SECTION TITLE (Instrument Serif with em italic accent) ─────────── */
.ds-page .l1-section-title {
  font-family: 'Instrument Serif', serif;
  font-size: clamp(40px, 4.5vw, 68px);
  line-height: 1.02;
  letter-spacing: -0.015em;
  font-weight: 400;
  color: var(--c-deep);
  margin: 0 0 28px;
}
.ds-page .l1-section-title em { font-style: italic; }
/* Compact variant for in-card titles */
.ds-page .l1-section-title--sm {
  font-size: clamp(32px, 3.2vw, 48px);
  line-height: 1.05;
  margin: 0 0 36px;
}

/* ── LEDE PARAGRAPH ─────────────────────────────────────────────────── */
.ds-page .l1-lede {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: clamp(15px, 1.1vw, 17px);
  line-height: 1.55;
  color: var(--c-ink);
  opacity: 0.78;
  margin: 0 0 56px;
  max-width: 38ch;
}

/* ── META LIST (hairline-divided label/value rows) ──────────────────── */
.ds-page .l1-meta-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  border-top: 1px solid var(--c-line);
}
.ds-page .l1-meta-row {
  display: grid;
  grid-template-columns: minmax(110px, 0.4fr) 1fr;
  gap: 24px;
  padding: 24px 0;
  border-bottom: 1px solid var(--c-line);
  align-items: baseline;
}
.ds-page .l1-meta-row .label {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--c-ink);
  opacity: 0.55;
}
.ds-page .l1-meta-row .value {
  font-family: 'Instrument Serif', serif;
  font-size: clamp(20px, 1.8vw, 26px);
  line-height: 1.25;
  color: var(--c-deep);
}
.ds-page .l1-meta-row .value a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--c-line);
  transition: border-color 0.25s ease, color 0.25s ease;
}
.ds-page .l1-meta-row .value a:hover {
  border-color: var(--c-gold);
  color: var(--c-gold);
}

/* ── SOCIAL ICON CIRCLES ────────────────────────────────────────────── */
.ds-page .l1-socials {
  display: flex;
  gap: 12px;
}
.ds-page .l1-social {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--c-line);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--c-ink);
  text-decoration: none;
  transition: border-color 0.25s ease, color 0.25s ease, background 0.25s ease;
}
.ds-page .l1-social:hover {
  border-color: var(--c-deep);
  color: var(--c-cream);
  background: var(--c-deep);
}
.ds-page .l1-social svg { width: 16px; height: 16px; }

/* ── EDITORIAL FORM FIELDS (sharp underline inputs, no rounding) ────── */
.ds-page .l1-field { margin-bottom: 22px; }
.ds-page .l1-field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
}
.ds-page .l1-label {
  display: block;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--c-ink);
  opacity: 0.7;
  margin-bottom: 10px;
}
.ds-page .l1-label .req { color: var(--c-gold); }
.ds-page .l1-input,
.ds-page .l1-select,
.ds-page .l1-textarea {
  width: 100%;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--c-line);
  padding: 12px 0;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 15px;
  color: var(--c-deep);
  outline: none;
  transition: border-color 0.25s ease;
  border-radius: 0;
}
.ds-page .l1-input::placeholder,
.ds-page .l1-textarea::placeholder { color: rgba(66, 67, 70, 0.4); }
.ds-page .l1-input:focus,
.ds-page .l1-select:focus,
.ds-page .l1-textarea:focus { border-bottom-color: var(--c-gold); }
.ds-page .l1-input.error,
.ds-page .l1-select.error,
.ds-page .l1-textarea.error { border-bottom-color: var(--c-error); }
.ds-page .l1-select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%23424346' stroke-width='1.4' d='M1 1.5 L6 6.5 L11 1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 4px center;
  padding-right: 28px;
  cursor: pointer;
}
.ds-page .l1-textarea {
  min-height: 110px;
  resize: vertical;
  line-height: 1.55;
}
.ds-page .l1-error {
  display: block;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 12px;
  color: var(--c-error);
  margin-top: 6px;
  min-height: 16px;
}
.ds-page .l1-consent {
  display: grid;
  grid-template-columns: 18px 1fr;
  gap: 12px;
  align-items: start;
  cursor: pointer;
  margin: 28px 0 8px;
}
.ds-page .l1-consent input[type="checkbox"] {
  width: 18px;
  height: 18px;
  margin: 2px 0 0;
  accent-color: var(--c-gold);
  cursor: pointer;
}
.ds-page .l1-consent-text {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 13px;
  line-height: 1.55;
  color: var(--c-ink);
  opacity: 0.78;
}

/* ── DARK CTA BUTTON (ink → gold on hover) ──────────────────────────── */
.ds-page .l1-cta {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  background: var(--c-deep);
  color: #f6f4ef;
  border: none;
  padding: 16px 28px;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 13px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.25s ease, transform 0.25s ease;
  border-radius: 0;
  text-decoration: none;
}
.ds-page .l1-cta:hover {
  background: var(--c-gold);
  transform: translateY(-1px);
}
.ds-page .l1-cta:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none;
}
.ds-page .l1-cta .arrow {
  display: inline-flex;
  width: 18px;
  height: 18px;
  align-items: center;
  justify-content: center;
}

/* ── SUCCESS STATE (after form submit) ──────────────────────────────── */
.ds-page .l1-success {
  text-align: center;
  padding: 60px 20px;
}
.ds-page .l1-success h3 {
  font-family: 'Instrument Serif', serif;
  font-size: 36px;
  line-height: 1.1;
  color: var(--c-deep);
  margin: 18px 0 12px;
  font-weight: 400;
}
.ds-page .l1-success h3 em { font-style: italic; color: var(--c-gold); }
.ds-page .l1-success p {
  font-family: 'Inter', system-ui, sans-serif;
  color: var(--c-ink);
  opacity: 0.75;
  font-size: 15px;
  line-height: 1.6;
  max-width: 40ch;
  margin: 0 auto;
}

/* ── L1 RESPONSIVE — mobile/tablet collapses for shared primitives ─── */
@media (max-width: 1100px) {
  .ds-page .l1-page-hero {
    padding: 20vh 6vw 10vh;
    min-height: 80vh;
  }
  .ds-page .l1-page-hero-meta { gap: 24px; }
}
@media (max-width: 600px) {
  .ds-page .l1-page-hero {
    padding: 18vh 22px 8vh;
    min-height: 72vh;
  }
  .ds-page .l1-page-hero-meta {
    grid-template-columns: 1fr;
    gap: 18px;
    margin-top: 48px;
    padding-top: 22px;
  }
  .ds-page .l1-field-row {
    grid-template-columns: 1fr;
    gap: 0;
  }
  .ds-page .l1-meta-row {
    grid-template-columns: 1fr;
    gap: 8px;
    padding: 20px 0;
  }
}
