/* ============================================================
   home-v2-0916.css — the designer's 2026-09-10 .. 2026-09-16 passes on top
   of home-v2.css + home-v2-0811.css (QA#3 polish, WWO filmstrip 600x400
   hover overlay, nav favicon link, CONTACT US HERE gradient button,
   hero seam/cover/fold fixes, brand colours, mobile P2/P3 fixes, >1920px
   background caps). Loaded LAST so equal-specificity rules here win.
   Every block is lifted verbatim from index-v2.html in her order; the
   only edits are root-absolute url() paths.
   ============================================================ */


/* ===== v2 block: qa-fixbatch-0914 ===== */

  /* ═══ 2026-09-14 QA fix batch (Theresa/Craig) — items 2, 3, 4, 7. Loaded last so it wins the cascade. ═══ */

  /* ── Item 4a: CONTRAST — brand magenta lightened minimally: #C10644 (3.18:1 on #0a0a0f) -> #EE2266 (4.76:1; 4.53:1 on the #111116 card). Still saturated brand magenta. ── */
  :root { --magenta: #EE2266; }
  .svc-nd-index, .svc-inline-header .svc-nd-index { color: var(--magenta) !important; }        /* was rgba(193,6,68,.7)/.45 = 2.03:1 / 1.43:1 */
  #engineering .ww-fac-num { color: #C47D6A !important; }                                        /* was rgba(196,125,106,.75) = 3.85:1 -> 6.1:1 */
  .footer-links a { color: #7F83A7 !important; }                                                 /* was rgba(127,131,167,.7) = 3.16:1 -> 5.37:1 */
  #contactOverlay .contact-overlay-close { color: #8B8EA9 !important; }                          /* was #6B6E8A = 3.78:1 -> 5.86:1 */
  #contactOverlay .contact-field label { color: #8B8EA9 !important; }                            /* was #6B6E8A = 3.78:1 -> 5.86:1 */
  #contactOverlay .contact-field:focus-within label { color: #C47D6A !important; }

  /* ── Item 4b: TYPE FLOOR — no text below 16px at any breakpoint; body copy 17px where it was 14–15.5px.
        Letter-spacing trimmed on the up-scaled labels so nothing collides/overflows. ── */
  .nav-links a { font-size: 16px !important; letter-spacing: 0.12em !important; }
  .nav-links { gap: 30px !important; }
  /* nav links at 16px no longer fit beside the logo between 901–1024px -> use the hamburger there too */
  @media (min-width: 901px) and (max-width: 1024px) {
    .nav-links { display: none !important; }
    .hamburger { display: block !important; order: -1; }
    .nav-logo { margin-left: auto; }
  }
  .btn, .hero-cta .btn { font-size: 16px !important; letter-spacing: 0.14em !important; }
  @media (max-width: 900px) { .btn { font-size: 16px !important; letter-spacing: 0.1em !important; padding: 12px 18px !important; } }
  .hero-eyebrow, .section-label { font-size: 16px !important; }
  @media (max-width: 768px) { .hero-eyebrow { font-size: 16px !important; letter-spacing: 0.16em !important; } }
  .scroll-hint-text, .trusted-by-label { font-size: 16px !important; }
  #engineering .ww-fac-num { font-size: 16px !important; letter-spacing: 0.24em !important; }
  .svc-nd-index, .svc-inline-header .svc-nd-index { font-size: 16px !important; }
  .footer-copy, .footer-links a { font-size: 16px !important; }
  .csf-num { font-size: 16px !important; letter-spacing: 0.12em !important; }
  #wwo-mosaic .tile .fig, #wwo-mslider .mimg .fig, #wwo-reveal .fig { font-size: 16px !important; letter-spacing: 0.12em !important; }
  #wwo-mosaic .tags .t-desc, #wwo-reveal .info .t-desc, #wwo-mslider .minfo .t-desc { font-size: 16px !important; line-height: 1.4 !important; }
  #wwo-mosaic .tags .fold-panel span, #wwo-mslider .minfo .tag-row span:not(.lbl), #wwo-reveal .info .tag-row span:not(.lbl) {
    font-size: 16px !important; letter-spacing: 0.05em !important; padding: 2px 7px !important;
  }
  /* long chips ("Gesture Recognition / Computer Vision") overflowed the 268–338px mobile row at 16px -> let chips wrap instead of nowrap */
  #wwo-mslider .minfo .tag-row span:not(.lbl), #wwo-mosaic .tags .fold-panel span:not(.lbl), #wwo-reveal .info .tag-row span:not(.lbl) { white-space: normal !important; max-width: 100%; line-height: 1.3; }
  #wwo-mosaic .tags .fold-panel .lbl, #wwo-mslider .minfo .tag-row .lbl, #wwo-reveal .info .tag-row .lbl {
    font-size: 16px !important; letter-spacing: 0.14em !important; padding: 0 0 1px !important;
  }
  #wwo-mosaic .tags .fold-panel { gap: 5px !important; padding: 8px 14px 10px !important; }
  /* desktop filmstrip overlay: at 16px the chip panel needs the full remaining tile height (was capped at 62%) — it still scrolls if a slide has more chips */
  #wwo-fs .tile .tags { overflow-y: auto; justify-content: flex-start !important; pointer-events: auto; }
  #wwo-fs .tile .tags .bar { flex: 0 0 auto; margin-top: auto; padding-right: 120px !important; }
  #wwo-fs .tile .tags .fold-panel { flex: 0 0 auto; max-height: none !important; overflow: visible !important; }
  /* shown-state FIG label moves to the top-right (was bottom-right, where 16px chips now collide with it) */
  #wwo-fs .tile:hover .fig, #wwo-fs .tile.is-active .fig, #wwo-fs .tile.show-tags .fig { bottom: auto !important; top: 12px !important; right: 14px !important; left: auto !important; }
  #contactOverlay .contact-field label { font-size: 16px !important; letter-spacing: 0.12em !important; }
  #contactOverlay .contact-overlay-message { font-size: 17px !important; }
  #contactOverlay .contact-field input, #contactOverlay .contact-field textarea, #contactOverlay .contact-field select { font-size: 16px !important; }
  .cs-modal-kicker { font-size: 16px !important; letter-spacing: 0.24em !important; }
  .cs-modal-subtitle { font-size: 16px !important; }
  .cs-modal-bullets li { font-size: 17px !important; }

  /* ── Item 3: keyboard-focusable case-study tiles — focus ring matches the nav focus style (var(--magenta)); inset so slick's overflow:hidden list can't clip it ── */
  .csf-tile:focus-visible { outline: 2px solid var(--magenta) !important; outline-offset: -3px !important; }

  /* ── Item 2: in-modal prev/next arrows. Bar BELOW the panel (column flex, never overlaps content or the X) at all widths;
        at >=1400px the panel (max 1180) leaves >=110px gutters, so the arrows sit at the viewport edges like #csx-prev/#csx-next. ── */
  .cs-modal { flex-direction: column; }
  .cs-modal-panel { flex: 0 1 auto; }
  .csm-nav { position: relative; z-index: 3; display: flex; justify-content: center; gap: 28px; padding: 10px 0 0; flex: 0 0 auto; }
  .csm-arrow {
    background: rgba(10,10,15,0.55); border: 0; cursor: pointer; font-family: var(--font-body); font-weight: 300;
    font-size: 34px; line-height: 1; color: #FFE2C0; opacity: 0.55; padding: 8px 20px 12px; min-width: 64px; min-height: 44px;
  }
  .csm-arrow:hover, .csm-arrow:focus-visible { color: #C47D6A; opacity: 0.9; }
  .csm-arrow:focus-visible { outline: 2px solid var(--magenta); outline-offset: 2px; }
  .cs-modal-panel { max-height: calc(92vh - 74px); }
  @media (max-width: 860px) {
    .cs-modal-panel { max-height: calc(100vh - 74px); }
    .csm-nav { padding: 10px 0 12px; background: rgba(5,5,12,0.92); }
  }
  @media (min-width: 1400px) {
    .cs-modal { flex-direction: row; }
    .cs-modal-panel { max-height: 92vh; }
    .csm-nav { position: static; padding: 0; }
    .csm-arrow {
      position: fixed; top: 50%; transform: translateY(-50%); z-index: 6;
      font-size: 136px; line-height: 0.85; padding: 0 20px 14px; background: rgba(10,10,15,0.35); min-width: 0;
    }
    .csm-arrow:hover, .csm-arrow:focus-visible { transform: translateY(-50%); }
    .csm-prev { left: 14px; }
    .csm-next { right: 14px; }
  }

  /* ── Item 7: footer tap targets >=44x44 on phones/tablets only (footer is column-stacked <=900; desktop untouched) ── */
  @media (max-width: 900px) {
    .footer-links a { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; min-width: 44px; padding: 0 16px; }
  }


/* ===== v2 block: wwo-fs-600-0914 ===== */

  /* ═══ 2026-09-14 (Theresa, #website-dark): WWO desktop filmstrip hover-overlay layout at 600x400 (was 520x347).
     Loaded last so it wins the cascade. Scope: #wwo-fs (>=769px) only — mobile slider, GSAP/parallax, hover/pause/wheel untouched.
     Rules: no text below 16px (glyph sizes unchanged, title stays 22px); FIG tag does NOT move on hover (bottom-left like idle);
     title+desc get the full tile width; TECH USED + INDUSTRIES anchored to the bottom above the FIG; arrows in a gutter outside the strip. ═══ */
  @media (min-width: 769px) {
    /* 4. arrows: strip viewport is inset so the ‹ › chevrons sit in a gutter beside the images, never over chips */
    /* 2026-09-14 13:05 (Theresa): 104px gutters removed again -> full-bleed strip; see <style id="wwo-fs-bleed-0914"> */

    /* 2. FIG: same spot + style as idle (bottom-left) so it does not jump on hover */
    #wwo-fs .tile:hover .fig, #wwo-fs .tile.is-active .fig, #wwo-fs .tile.show-tags .fig {
      top: auto !important; bottom: 12px !important; left: 14px !important; right: auto !important;
    }

    /* 3. layout: title/desc top, chips bottom, ~12px section gaps */
    #wwo-fs .tile .tags { display: flex; flex-direction: column; justify-content: flex-start !important; overflow-y: auto; }
    #wwo-fs .tile .tags .bar { flex: 0 0 auto; margin-top: 0 !important; padding: 14px 16px 0 !important; }
    #wwo-fs .tile .tags .t-title { line-height: 1.08; }
    #wwo-fs .tile .tags .t-desc { padding: 4px 0 0 !important; line-height: 1.35 !important; }
    #wwo-fs .tile .tags .fold-panel { flex: 0 0 auto; gap: 4px 5px !important; padding: 0 16px !important; margin: 0; }
    #wwo-fs .tile .tags .bar + .fold-panel { margin-top: auto; padding-top: 12px !important; }   /* TECH USED absorbs the free space -> bottom-anchored */
    #wwo-fs .tile .tags .fold-panel + .fold-panel { margin-top: 12px; }                            /* INDUSTRIES 12px below TECH USED */
    #wwo-fs .tile .tags .fold-panel:last-child { padding-bottom: 44px !important; }                /* clears the 16px FIG tag at bottom:12px */
    #wwo-fs .tile .tags .fold-panel span:not(.lbl) { padding: 2px 7px !important; line-height: 1.2 !important; }
    #wwo-fs .tile .tags .fold-panel .lbl { padding: 0 !important; line-height: 1.2; }
  }


/* ===== v2 block: wwo-fs-figright-0914 ===== */

  /* 2026-09-14 12:56 follow-up (Theresa, #website-dark): FIG tag bottom-RIGHT on both idle and hover in the desktop filmstrip.
     Same style/offsets as before, mirrored (right:14px bottom:12px). Chips keep the 44px bottom reserve so nothing collides;
     the › arrow lives in the outer gutter (viewport margin 104px), outside the tile. */
  @media (min-width: 769px) {
    #wwo-fs .tile .fig,
    #wwo-fs .tile:hover .fig, #wwo-fs .tile.is-active .fig, #wwo-fs .tile.show-tags .fig {
      top: auto !important; bottom: 12px !important; left: auto !important; right: 14px !important;
    }
  }


/* ===== v2 block: wwo-fs-bleed-0914 ===== */

  /* ═══ 2026-09-14 13:05 (Theresa, #website-dark): WWO desktop filmstrip runs edge to edge again (the 104px gutters from
     12:52 made the ~2nd tile end a few px short of the strip edge at 1200-1300px, so its overlay text looked "cut off").
     Each page edge gets a 150px fade from the page background (#0A0A0F) to transparent; the fade layers are pointer-events:none
     so edge tiles stay hoverable/clickable/draggable. The ‹ › chevrons sit inside the fade zone, tighter to the edge (6px, 8px
     side padding). The tile currently under a chevron gets its overlay text indented on that side so the arrow never sits on
     title/description/chips (class toggled by <script id="wwo-fs-arrowzone-0914">). Mobile slider (<=768) untouched. ═══ */
  @media (min-width: 769px) {
    #wwo-fs .wfs-viewport { margin: 0; position: relative; }
    #wwo-fs .wfs-viewport::before, #wwo-fs .wfs-viewport::after {
      content: ""; position: absolute; top: 0; bottom: 0; width: 150px; z-index: 5; pointer-events: none;
    }
    #wwo-fs .wfs-viewport::before { left: 0;  background: linear-gradient(to right, rgb(10,10,15) 0%, rgba(10,10,15,0.75) 35%, rgba(10,10,15,0) 100%); }
    #wwo-fs .wfs-viewport::after  { right: 0; background: linear-gradient(to left,  rgb(10,10,15) 0%, rgba(10,10,15,0.75) 35%, rgba(10,10,15,0) 100%); }
    #wwo-fs .wfs-arrow { padding-left: 8px; padding-right: 8px; background: rgba(10,10,15,0.55); } /* backdrop .35->.55: worst-pixel glyph contrast on FIG.06 was 4.37:1 at .35, 4.76:1+ at .55 */
    #wwo-fs .wfs-prev { left: 6px; }
    #wwo-fs .wfs-next { right: 6px; }
    /* overlay text clears the chevron on the side the tile touches (padding only; glyph sizes unchanged) */
    #wwo-fs .tile.wfs-under-prev .tags .bar, #wwo-fs .tile.wfs-under-prev .tags .fold-panel { padding-left: 72px !important; }
    #wwo-fs .tile.wfs-under-next .tags .bar, #wwo-fs .tile.wfs-under-next .tags .fold-panel { padding-right: 72px !important; }
  }


/* ===== v2 block: n3-fonts-services-0914 ===== */

  /* 2026-09-14 (Theresa): FIX 1 — brand fonts in the What-we're-working-on overlay.
     Adobe kit family 'trade-gothic-next-condensed' (400 + 700 loaded by use.typekit.net/nje3hle.css) replaces the mono stack. */
  #wwo-fs, #wwo-mosaic, #wwo-reveal, #wwo-mslider { --mono: 'trade-gothic-next-condensed', 'Trade Gothic Next Condensed', 'Trade Gothic Next', sans-serif; }
  #wwo-fs .tile .fig, #wwo-mosaic .tile .fig, #wwo-reveal .fig, #wwo-mslider .mimg .fig,
  #wwo-fs .tile .tags .fold-panel span, #wwo-mosaic .tags .fold-panel span, #wwo-reveal .info .tag-row span, #wwo-mslider .minfo .tag-row span,
  #wwo-fs .tile .tags .fold-panel .lbl, #wwo-mosaic .tags .fold-panel .lbl, #wwo-reveal .info .tag-row .lbl, #wwo-mslider .minfo .tag-row .lbl {
    font-family: 'trade-gothic-next-condensed', 'Trade Gothic Next Condensed', 'Trade Gothic Next', sans-serif !important;
    font-weight: 400 !important;
    letter-spacing: 0.05em !important;
  }
  /* × close buttons -> brand sans (same stack the site already uses for Avenir Next) */
  .cs-modal-close, .contact-overlay-close, #wwo-reveal .close-x, #wwo-mosaic .tags .close-x {
    font-family: "Avenir Next", "AvenirNext", var(--font-sub), sans-serif !important;
    font-weight: 400;
  }
  /* FIX 2 — Services top spacing, desktop only (>=1025px; <=1024 already has its own compact 60px/10px rules).
     Was: section 120px + intro 80px = ~200px header->eyebrow, heading->cards 20+48+40 = 108px.
     Now: 120px header->eyebrow (matches Solutions), heading->cards 20+0+40 = 60px. Anchor landing unchanged (section padding untouched). */
  @media (min-width: 1025px) {
    #services .svc-intro-wrap { padding-top: 0 !important; padding-bottom: 0 !important; }
  }


/* ===== v2 block: wwo-fs-fighide-minh-0914 ===== */

  /* ═══ 2026-09-14 14:15 (Theresa, #pbl-website-dark): WWO desktop filmstrip (>=769px, #wwo-fs only; mobile <=768 untouched).
     1. FIG tag fades OUT while the hover overlay is shown (same .35s ease as the .tags overlay), stays visible bottom-right idle
        (position rules from <style id="wwo-fs-figright-0914"> are kept; only opacity is added here, loaded later in the cascade).
     2. Tiles never shorter than 400px: width was min(600px, 42vw) -> below 1429px the tile shrank (430x287 at 1024) and the
        16px overlay text overflowed. Fixed 600px x 3:2 = 600x400 at every desktop width (min-height 400px as a floor).
        slick runs with variableWidth:true and reads the CSS width on init/setPosition, so no option change is needed;
        <script id="wwo-fs-arrowzone-0914"> already re-marks the tiles under the chevrons on setPosition/resize. ═══ */
  @media (min-width: 769px) {
    #wwo-fs .tile .fig { opacity: 1; transition: opacity .35s ease; }
    #wwo-fs .tile:hover .fig, #wwo-fs .tile.is-active .fig, #wwo-fs .tile.show-tags .fig { opacity: 0 !important; }
    #wwo-fs .tile.wfs-slide { width: 600px; min-height: 400px; aspect-ratio: 3 / 2; }
  }


/* ===== v2 block: wwo-fs-pad28-0914 ===== */

  /* ═══ 2026-09-14 15:20 (Theresa, #website-dark): WWO desktop filmstrip hover overlay (#wwo-fs, >=769px; mobile untouched) —
     content was squeezed top/left with dead space in the middle. Overlay padding 28px all sides (was 14px top / 16px sides),
     TECH USED block keeps absorbing the spare height (margin-top:auto from <style id="wwo-fs-600-0914">) so it stays
     bottom-anchored above the FIG reserve (44px bottom padding kept), label -> chips gap 4px -> 10px. No font-size changes.
     Arrow-zone indents (wfs-under-prev/-next) grow with the padding: 72px -> 84px (= 28px + the same 56px chevron clearance). ═══ */
  @media (min-width: 769px) {
    #wwo-fs .tile .tags .bar { padding: 28px 28px 0 !important; }
    #wwo-fs .tile .tags .fold-panel { padding: 0 28px !important; }
    #wwo-fs .tile .tags .bar + .fold-panel { padding-top: 12px !important; }          /* re-stated: the shorthand above would reset it */
    #wwo-fs .tile .tags .fold-panel:last-child { padding-bottom: 44px !important; }   /* FIG reserve (bottom:12px + 16px tag) kept */
    #wwo-fs .tile .tags .fold-panel .lbl { margin-bottom: 6px; }                       /* + 4px flex row-gap = 10px label -> chips */
    #wwo-fs .tile.wfs-under-prev .tags .bar, #wwo-fs .tile.wfs-under-prev .tags .fold-panel { padding-left: 84px !important; }
    #wwo-fs .tile.wfs-under-next .tags .bar, #wwo-fs .tile.wfs-under-next .tags .fold-panel { padding-right: 84px !important; }
  }


/* ===== v2 block: nav-fav-39-0914 ===== */

  /* 2026-09-14 15:20 (Theresa): small CL logo (favicon home link, leftmost nav item) rendered at 39px on desktop.
     Scoped >=1025px: at 901-1024px the .nav-links list is hidden (hamburger), <=900px mobile unchanged (24px).
     Nav height is set by the 80px right-hand logo (12px padding -> 105px incl. border), so no nav-height change / no layout shift.
     .nav-links gets align-items:center so the text links stay vertically centered on the taller icon. */
  @media (min-width: 1025px) {
    .nav-fav-img { height: 39px; }
    .nav-links { align-items: center; }
  }


/* ===== v2 block: wwo-fs-blur-0914 ===== */

  /* 2026-09-14 15:40 (Theresa, #website-dark): blur the WWO desktop filmstrip photo on hover so text baked into the
     images (signage such as "Welcome" / "UPCOMING MEETINGS" on Greeted by Name, FIG. 08) stops ghosting through the
     85% scrim behind the overlay text. Idle state is unchanged (brightness(.92) from #wwo-mosaic .tile img, no scale).
     The base hover rule sets filter: brightness(1.05); filter is a single property so brightness is re-stated here.
     scale(1.03) hides the blurred-edge halo; .tile is overflow:hidden so nothing leaks. Same .35s ease as the overlay
     fade, so image blur and overlay opacity animate together. Desktop only (>=769px). */
  @media (min-width: 769px) {
    #wwo-fs .tile.wfs-slide img { transform: none; transition: filter .35s ease, transform .35s ease; }
    #wwo-fs .tile.wfs-slide:hover img, #wwo-fs .tile.wfs-slide.is-active img, #wwo-fs .tile.wfs-slide.show-tags img {
      filter: brightness(1.05) blur(4px); transform: scale(1.03);
    }
  }


/* ===== v2 block: contact-dash-0914 ===== */

  /* 2026-09-14 15:50 (Theresa, #website-dark): "CONTACT US HERE" had a magenta dash only BEFORE the label
     (.contact-link::before 24x1px, gap 10px) so the text sat 34px left of centre. Mirror it AFTER the label so the
     label is centred. flex-shrink:0 keeps both dashes intact; white-space:nowrap keeps label + dashes on one line
     (16px text + 2x34px = ~290px, fits 320px; the 480px overflow-wrap rule is left in place as a fallback). */
  #contact .contact-link::before, #contact .contact-link::after {
    content: ''; width: 24px; height: 1px; background: var(--magenta); flex: 0 0 24px;
  }
  #contact .contact-link { white-space: nowrap; justify-content: center; }


/* ===== v2 block: contact-btn-0914 ===== */

  /* 2026-09-14 16:10 (Theresa, #website-dark): "CONTACT US HERE" becomes an OUTLINE BUTTON styled 1:1 like the hero
     "Explore the Lab" (.btn.btn-outline: avenir-next-lt-pro 16px/700, uppercase, ls .14em, padding 16px 36px, 1px solid
     border, radius 0, transition all .35s ease, hover = accent colour + translateY(-2px)) with the brand magenta
     var(--magenta) #EE2266 for the border (text: see rev2 note below) instead of that button's blue/lavender. The 15:50 dashes
     (contact-dash-0914 ::before/::after) are neutralised here (content:none) rather than deleted, so the block stays
     as a record. Responsive padding mirrors the .btn rules at <=1024 (12px 20px) and <=900 (12px 18px); ls stays .14em like Explore.
     Hover in pink: same lift; colour/border shift to the section's lighter pink #EE5C86 (already used on the phone link)
     so there is a visible hover change like Explore's text->lavender. Focus ring: UA outline kept (same as Explore). */
  #contact .contact-link::before, #contact .contact-link::after { content: none !important; display: none !important; }
  #contact .contact-link {
    display: inline-flex !important; align-items: center; justify-content: center; gap: 0 !important;
    font-family: var(--font-sub) !important; font-size: 16px !important; font-weight: 700 !important;
    letter-spacing: 0.14em !important; text-transform: uppercase; white-space: nowrap;
    padding: 16px 36px !important; max-width: none; overflow-wrap: normal;
    border: 1px solid var(--magenta) !important; border-radius: 0;
    color: #F2F0FA !important; background: transparent; text-decoration: none; text-shadow: none;
    transition: all 0.35s ease !important; transform: translateY(0);
  }
  #contact .contact-link:hover { color: var(--lavender) !important; border-color: var(--magenta) !important; transform: translateY(-2px); }
  /* 16:17 rev2 (Theresa): text back to the original #F2F0FA (line 5813 value), ONLY the border pink; hover = Explore text hover (var(--lavender) #7F83A7) + -2px lift, border stays pink; #EE5C86 text hover dropped. */
  @media (max-width: 1024px) { #contact .contact-link { padding: 12px 20px !important; } }
  @media (max-width: 900px)  { #contact .contact-link { padding: 12px 18px !important; } } /* Explore keeps ls .14em at all widths (.hero-cta .btn wins over the <=900 .btn .1em rule) */


/* ===== v2 block: csf-num-font-0914 ===== */

  /* 2026-09-14 16:10 (Theresa, #website-dark): case-study filmstrip index numbers "[01]".."[04]" (.csf-num) rendered
     Menlo via .csf-wrap --mono ('SF Mono','Menlo',...). Switch to the brand condensed face exactly as the WWO tags were
     done in n3-fonts-services-0914 (same stack + fallbacks), regular 400, size kept at 16px (qa-fixbatch floor),
     tabular-nums so the digits keep equal widths, letter-spacing .08em so brackets/digits stay legible in the narrow face.
     .csf-num is position:absolute inside .csf-imgwrap, so no layout shift in the strip. */
  .csf-wrap { --mono: 'trade-gothic-next-condensed', 'Trade Gothic Next Condensed', 'Trade Gothic Next', sans-serif; }
  .csf-wrap .csf-num {
    font-family: 'trade-gothic-next-condensed', 'Trade Gothic Next Condensed', 'Trade Gothic Next', sans-serif !important;
    font-weight: 400 !important; font-size: 16px !important; font-variant-numeric: tabular-nums;
    letter-spacing: 0.08em !important;
  }


/* ===== v2 block: hero-seam-0914 ===== */

/* 2026-09-14 16:18 (Theresa, #website-dark): faint vertical SEAM in the hero at the
   photo's right edge (x = 72% + 58.16vh; e.g. 1748px @1879x680, 1904px @1920x900).
   ROOT CAUSE: the source jpg hero-cylinder-theresa-0825b.jpg (1854x1205) has a 1px
   bright grey column at x=1853 (~rgb(73,71,73) vs ~rgb(10,9,10) for the rest of the
   edge) - an export artefact - and the photo is drawn `72% top / auto 135vh no-repeat`
   over #0a0a0f, so whenever imgW (207.71vh) < 100% the column shows as a hairline
   (full brightness when 135vh ~= 1205px, i.e. vh ~ 893; antialiased otherwise) plus
   a ~2.4/255 tonal step (image edge rgb(10,9,10) vs bg rgb(10,10,15)).
   FIX (CSS only, no re-export): a pseudo strip INSIDE .heb-img (so it inherits the
   parallax transform + bottom mask) feathers transparent -> #0a0a0f over the last
   ~25px of the photo and stays solid past its edge. imgW = 1854/1205 * 135vh =
   207.7095vh; right edge = 0.72*(100% - 207.7095vh) + 207.7095vh = 72% + 58.1587vh.
   When the edge is off-screen (imgW >= 100%) `left` > 100% -> the strip has no area. */
@media (min-width: 901px) {
  #heroeng-bg-wrap .heb-img::after {
    content: '';
    position: absolute; top: 0; bottom: 0;
    left: calc(72% + 58.1587vh - 28px);
    right: -2px;
    pointer-events: none;
    background: linear-gradient(to right, rgba(10,10,15,0) 0px, rgba(10,10,15,0.85) 20px, #0a0a0f 25px, #0a0a0f 100%);
  }
}


/* ===== v2 block: contact-grad-0914 ===== */

  /* 2026-09-14 16:30 (Theresa, #website-dark): CONTACT US HERE outline button -> ANIMATED GRADIENT 1px border.
     Motion copied 1:1 from the section-title text gradients (h2/.section-title/.contact-heading, L1562-1571):
     linear-gradient(120deg, A, B, A, B) / background-size 300% 300% / animation: warmShift 20s ease infinite
     (0% -> 100% -> 0% background-position, same global @keyframes warmShift at L297). Only the colours differ:
     #C10644 and #4C041D (brief). Drawn on the ::before pseudo (absolute, inset -1px = the button's border box,
     1px transparent border + mask-composite exclude leaves ONLY the 1px ring painted), so the button's transparent
     background, #F2F0FA text, square corners, bbox, hover lift and focus ring are untouched. The real border in
     contact-btn-0914 is made transparent (kept at 1px so layout is identical). The 15:50 dash rule (contact-dash-0914)
     and the content:none neutraliser in contact-btn-0914 are both overridden here (same specificity, later in cascade).
     prefers-reduced-motion: animation paused (static gradient ring). */
  #contact .contact-link { border-color: transparent !important; position: relative; }
  #contact .contact-link:hover { border-color: transparent !important; }
  #contact .contact-link::before {
    content: '' !important; display: block !important;
    position: absolute; inset: -1px; width: auto; height: auto; pointer-events: none;
    box-sizing: border-box; border: 1px solid transparent; border-radius: 0;
    background: linear-gradient(120deg, #C10644, #4C041D, #C10644, #4C041D) border-box;
    background-size: 300% 300%; background-origin: border-box; background-clip: border-box;
    -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
    mask-composite: exclude;
    animation: warmShift 20s ease infinite;
  }
  #contact .contact-link::after { content: none !important; display: none !important; }
  @media (prefers-reduced-motion: reduce) { #contact .contact-link::before { animation-play-state: paused; } }


/* ===== v2 block: hero-cover-0914 ===== */

/* 2026-09-14 16:25 (Theresa, #website-dark): "scale the hero photo up on larger
   breakpoints" so it FILLS to the right viewport edge instead of fading there.
   Desktop base rule (L5869): `72% top / auto 135vh` -> imgW = 1854/1205*135vh =
   207.7095vh; on wide+short windows (vw > 207.7vh, e.g. 1879x680, 1920x900,
   2560x1080, 3440x*) the photo ended before the right edge, leaving bare #0a0a0f
   that hero-seam-0914 feathered. With position-x 72%: right edge = 0.72vw + 0.28W,
   so the edge reaches the viewport iff W >= vw. FIX: width floor = max(100vw,
   207.7095vh), height auto (aspect kept), position unchanged -> on normal windows
   (W = 207.7vh > vw) nothing changes; on wide+short ones the photo scales up
   uniformly until W == vw + 8px (left offset 0.72*(vw-W) = -5.8px): the +8px
   pushes the jpg's bright last pixel column (the seam artefact, x=1853) ~2px
   PAST the viewport edge instead of landing exactly on its last column
   (measured: lum 73 at x=vw-1 with a bare 100vw floor). Taller image (0.65vw)
   would run further down inside .heb-img (inset:0, bottom mask 82-100%, wrap
   overflow:clip), but with position-y `top` a uniform scale-up pushes the
   cylinder DOWN (ring at 0.391 of the image height: 1879x680 -> ring 434px ->
   552px; 3440x680 -> cylinder fully below the fold). So position-y shifts the
   image up by the same fraction: offset = 0.391*(135vh - H), H = 1205/1854*vw =
   0.65vw -> min(0px, 52.78vh - 25.41vw); == 0 exactly where the floor takes
   over, so the ring stays at its previous viewport y and the photo zooms around
   it. Image bottom = offset + H >= 135vh, so bottom coverage is never less
   than before; top is above the wrap top (clipped) -> no bg gap either way.
   Parallax keyframes / view-timeline / rAF fallback / LCP preload untouched.
   hero-seam-0914 ::after is obsolete now that the photo edge is never on-screen
   on desktop; neutralised here (content:none) instead of deleting that block. */
@media (min-width: 901px) {
  #heroeng-bg-wrap .heb-img {
    background-size: max(calc(100vw + 8px), 207.7095vh) auto;
    background-position: 72% min(0px, calc(52.78vh - 25.41vw));
  }
  #heroeng-bg-wrap .heb-img::after { content: none; }
}


/* ===== v2 block: polish-0914 ===== */

  /* ═══ 2026-09-14 (Theresa, #website-dark) polish batch — QA#3 findings P2-5, P2-6, P2-8, P3-9 ═══ */

  /* #5 (P2-5): the 4 carousel arrows had outline:none at :focus-visible (idxpass-0811 / v2 overrides).
     Restore the page's own keyboard ring (matches a/button/.btn:focus-visible: 2px var(--magenta), offset 3px).
     :focus-visible only, so mouse clicks stay ring-free. */
  .wfs-arrow:focus-visible, .csx-arrow:focus-visible,
  #wfs-prev:focus-visible, #wfs-next:focus-visible, #csx-prev:focus-visible, #csx-next:focus-visible {
    outline: 2px solid var(--magenta); outline-offset: 3px;
  }

  /* #6 (P2-6): <=768 case-study strip — next tile peeks 24px at the right edge as a swipe affordance.
     Slick now runs in slide mode on mobile (see slick-init-0811 initCsf); slick sizes slides from the
     .slick-list CONTENT width, so padding-right on the list leaves a 24px window in which the next slide
     shows (overflow:hidden clips at the padding box). Current tile stays flush-left. slide margin-right
     (2px, slick-skin-0811) is zeroed here because slick's fixed-width mode ignores margins when positioning
     (2px drift per slide); the 8px gap moves into the tile's own padding instead. */
  @media (max-width: 768px) {
    #csf-strip.slick-initialized .slick-list { padding-right: 24px; }
    #csf-strip.slick-initialized .slick-slide { margin-right: 0; box-sizing: border-box; padding-right: 8px; }
    /* 2026-09-15 (Theresa): chevrons centered on the SCREEN (not the current tile) to match the WWO mobile carousel */
    .csf-wrap .csf-mnav { right: 0; }
  }

  /* #8 (P2-8): at 320px the hero eyebrow top (108 = #hero padding-top) sat 5px under the fixed nav
     (nav bottom 113). 117px puts it at nav bottom + 4px. No-op >=361px. */
  @media (max-width: 360px) {
    #hero { padding-top: 117px; }
  }

  /* #9 (P3-9): services result-line gradient (svcWarmShift x4, declared with !important in several
     blocks so the global reduce rule's duration/iteration-count could not stop it) — off under reduce.
     Selectors mirror the declaring rules (#services .svc-body-box …, #services .svc-name-card .svc-mobile-detail …)
     because !important-vs-!important is decided by specificity. */
  @media (prefers-reduced-motion: reduce) {
    #services .svc-inline-result,
    #services .svc-body-box .svc-inline-result,
    #services .svc-name-card .svc-mobile-detail .svc-inline-result,
    .svc-body-box.svc-hover .svc-inline-result,
    .svc-mobile-detail .svc-inline-result { animation: none !important; }
  }


/* ===== v2 block: hero-fold-0914 ===== */

/* 2026-09-14 19:0x (replaces the 18:37 ITEM-4-only block, which had no ITEM 3 and an unscoped shadow) (Theresa, #website-dark) QA#3 P2-3 + P2-4. Hero copy only; no font-size changes.
   ITEM 3 (P2-3) short desktop windows (<=720px tall, >=901 wide): #hero is 108px top pad + eyebrow(25.6)
   +24 + h1 (2 lines = 368px at >=1600) +28 + sub (2 lines, 89.6) +40 + CTA row (59.6) = 743px at 1879x680,
   so .hero-cta sat below the fold. Padding/gap-only tightening: eyebrow->h1 24->4, h1->sub 28->4,
   sub->cta 40->12 (-72px) for windows <=800px tall (brief said <=720; raised to 800 because the ITEM 4
   wrap below makes the sub 4 lines at 1024-1536 wide, which at 1366x768 / 1280x800 would otherwise push the
   CTA row to 792 / 771px - below or within 29px of the fold). Top pad 108->109 at every >=901 width so the
   eyebrow top is nav bottom (105) + 4 instead of +3 wherever the copy is taller than vh-228 (centered
   windows move 0.5px). Measured 1879x680: CTA bottom 743 -> 672 (in the fold, 8px spare) - padding alone
   CANNOT reach vh-40 = 640 (shortfall 32px; even 0/0/8 gaps leave 20px). 1440x680 -> 621 (ok), 1366x680 -> 648
   (8 short), 1920x700 -> 672 (12 short). Type scaling deliberately NOT added (Theresa decides).
   ITEM 4 (P2-4) hero-sub across the light sculpture: desktop bg rule (hero-cover-0914) is
   size max(100vw+8px, 207.7095vh) auto @ position-x 72% -> image left = 0.72*(vw - W); the lit sculpture's
   leftmost column (ceiling-housing rim/ring glow, pixel-scanned in hero-cylinder-theresa-0825b.jpg rows
   0.325-0.40: lum>60 at col 1167/1854 = 0.629; mesh body 0.645; bright ring 0.653) sits at
   left + 0.629*W = 72vw - 0.091*W  ->  --cyl-left. The sub's box may extend to --cyl-left - 24px; its
   left edge is #hero's 8vw padding. Only where that is narrower than today's natural single-line width
   does anything wrap (measured today: overlaps at 1024x768 -180px, 1165x960 -259, 1366x768 -153,
   1440x900 -128, 1600x900 -25; clear at 1879x680 +152, 1920x1080 +149, 2250x960 +359, 2560x1440 +498,
   3440x1440 +1025 -> untouched). <1100 keeps today's 760px cap (min()); >=1100 the BATCH-0714 nowrap on
   line 1 is released to `normal` so the cap can act (line 1 fits its 84vw container at every >=1100 width,
   so with a non-binding cap the break is identical). 320px floor guards tall/narrow windows. Parallax
   translates .heb-img on Y only (matrix e = 0 at scroll 0/300), so the ring's x is scroll-independent.
   Mobile <=900 (84% 6vh / auto 115vh): --cyl-left = 0.84vw - 35.57vh = 67px at 320x568 / 27px at 390x844,
   i.e. the sculpture starts LEFT of the text column - no line-break rule can clear it; mobile keeps its
   existing 4-layer text-shadow + radial scrim, untouched here. Desktop had text-shadow:none -> soft
   0 1px 12px added (>=901 only, so the stronger mobile shadow is not replaced). */
@media (min-width: 901px) and (max-height: 800px) {
  #hero .hero-eyebrow { margin-bottom: 4px; }
  #hero .hero-title { margin-bottom: 4px; }
  #hero .hero-cta { margin-top: 12px; }
}
@media (min-width: 901px) {
  #hero { padding-top: 109px; }
  #hero { --cyl-left: calc(72vw - 0.091 * max(calc(100vw + 8px), 207.7095vh)); }
  #hero .hero-sub { text-shadow: 0 1px 12px rgba(10,10,15,.8); }
  #hero .hero-sub { max-width: min(760px, max(320px, calc(var(--cyl-left) - 8vw - 24px))) !important; }
}
@media (min-width: 1100px) {
  #hero .hero-sub { max-width: max(320px, calc(var(--cyl-left) - 8vw - 24px)) !important; }
  #hero .hero-sub .hero-sub-line1 { white-space: normal; }
}


/* ===== v2 block: csf-edgefade-0915 ===== */

  /* ═══ 2026-09-15 10:30 (Theresa, #pbl-website-dark): case-studies filmstrip (#csf-strip) gets the SAME left/right edge fades as
     the WWO filmstrip (<style id="wwo-fs-bleed-0914"> #wwo-fs .wfs-viewport::before/::after): 150px, page bg rgb(10,10,15) 0% ->
     .75 at 35% -> transparent, z-index 5 (above slick tiles, below the .csx-arrow chevrons at z-index 6), pointer-events:none so edge
     tiles stay clickable/draggable. Host = .csf-wrap (position:relative, full-bleed 100vw, same rect as the strip on desktop).
     Both sections resolve to the body background rgb(10,10,15) (measured), so the colors are identical. Desktop only (min-width 769px),
     exactly like WWO — the mobile 24px next-tile peek (polish-0914) is untouched. ═══ */
  @media (min-width: 769px) {
    .csf-wrap::before, .csf-wrap::after {
      content: ""; position: absolute; top: 0; bottom: 0; width: 150px; z-index: 5; pointer-events: none;
    }
    .csf-wrap::before { left: 0;  background: linear-gradient(to right, rgb(10,10,15) 0%, rgba(10,10,15,0.75) 35%, rgba(10,10,15,0) 100%); }
    .csf-wrap::after  { right: 0; background: linear-gradient(to left,  rgb(10,10,15) 0%, rgba(10,10,15,0.75) 35%, rgba(10,10,15,0) 100%); }
  }


/* ===== v2 block: brand-colors-0915 ===== */

  /* 2026-09-15 (Theresa, #pbl-website-dark): BRAND COLOUR pass. Light lavender #D9DBF4 becomes the
     text colour of the "CONTACT US HERE" CTA (1 instance, L8927 inside #contact .contact-links) and of the
     four case-study names under the #csf-strip tiles (.csf-name: WellSky / Clinique / Academy Awards / Blue Gallery).
     Hover slate #7F83A7 stays the CTA's hover text colour.
     WHY !important on the CTA: the declaring rule is `#contact .contact-link { color: #F2F0FA !important }`
     (contact-btn-0914, 2026-09-14 16:10 + 16:17 rev2) — same selector/specificity, already !important, so an
     !important declaration later in the cascade is the only way to win without editing that block.
     The hover already resolved to var(--lavender) = #7F83A7, i.e. exactly the requested hover value; it is
     re-stated here as a literal so the intent survives any future change to the --lavender variable.
     .csf-name needs NO !important: the declaring rule is the plain class selector `.csf-name { color:#fff }`
     (L8663), so class specificity later in the cascade is sufficient.
     Text colour ONLY — background, border (the contact-grad-0914 animated gradient ring), padding, size,
     letter-spacing, font-weight, radius and transition timing are all untouched. The CTA keeps its own
     `transition: all .35s ease !important` from contact-btn-0914, so the hover colour still animates;
     the narrow `transition-property` list from perf-cls-0914 is on `#hero .hero-cta .btn` (a different
     element) and is deliberately left alone. The .csf-num "[01]".."[04]" numerals (#FFE2C0, a separate
     element inside .csf-imgwrap) are NOT touched.
     2026-09-15 rev2 (Theresa, #pbl-website-dark): the CTA HOVER colour only changes #7F83A7 -> #9BA0C4.
     Reason: pixel-sampled contrast of #7F83A7 over the .contact-bg photo measured 3.83-4.46:1 average at
     390/768/1440/1920 — below WCAG AA 4.5:1. #9BA0C4 is a lighter step on the same lavender ramp and was
     predicted at ~6.0:1 average. Resting #D9DBF4, the .csf-name case-study names, the .csf-num [01]-[04]
     numerals (#FFE2C0), the contact-grad-0914 gradient ring, border, padding, size, weight, letter-spacing,
     the .35s transition and the translateY(-2px) hover lift are ALL unchanged. The hero "Explore the Lab"
     button and the --lavender variable (L88) are deliberately NOT touched — this fix is local to the
     contact CTA. */
  #contact .contact-link { color: #D9DBF4 !important; }
  #contact .contact-link:hover { color: #9BA0C4 !important; }
  .csf-name { color: #D9DBF4; }
  /* 2026-09-15 rev3 (Theresa, #pbl-website-dark) -- id hero-explore-hover-0915c:
     Hero "Explore the Lab" button (.btn.btn-outline, L6084, the ONLY one inside #hero .hero-cta)
     gets hover TEXT colour 9BA0C4, matching the contact CTA fix from 12:10. Same rationale: the
     inherited hover var(--lavender) 7F83A7 measured 3.8-4.5:1 over the hero art, below WCAG AA.
     SCOPED deliberately: --lavender (L88) has 21 consumers (nav/footer/section labels + a background
     at L1272), so redefining the variable would repaint unrelated UI. Scoping to #hero .hero-cta also
     spares the second .btn.btn-outline, the contact-overlay Close button (L9070).
     TEXT ONLY: border-color is intentionally omitted so the base .btn-outline:hover rule (L403-407)
     keeps painting the border var(--lavender); resting colour (var(--text) E8E8F0), background,
     border-width, padding, font-size/weight, letter-spacing, radius, the -2px lift and the .35s
     transition-property list from perf-cls-0914 (L56, which already includes `color`) are untouched.
     No !important needed: the declaring rule is the bare class .btn-outline:hover (specificity 0,2,0);
     this selector is 1,3,0 and later in the cascade. */
  #hero .hero-cta .btn.btn-outline:hover { color: #9BA0C4; }


/* ===== v2 block: csm-imgs-0915 ===== */

  /* 2026-09-15 (Theresa): modal image pairs keep native aspect ratio, equal height, fill row.
     On <=860px .cs-modal-imgs is a row; default align-items:stretch stretched the shorter image
     of a pair to the taller one's height (e.g. Clinique laserbar 1600x902 next to quiz 1400x1883).
     Fix: flex-grow = each image's aspect ratio (set as --csm-ar by the script below), so widths are
     proportional to w/h and equal heights fall out; align-items:flex-start stops the stretch. */
  @media (max-width:860px) {
    .cs-modal-imgs { align-items:flex-start; min-width:0; max-width:100%; }
    /* width:0 (not auto) so the images' natural widths cannot inflate the panel's intrinsic width;
       the rendered width comes from flex-grow, height follows the intrinsic ratio. */
    .cs-modal-imgs img { width:0; height:auto; min-width:0; flex: var(--csm-ar, 1) 1 0; }
  }


/* ===== v2 block: hero-noparallax-0915 ===== */

/* hero-noparallax-0915: Option D — no parallax on phones (Safari toolbar jumps)
   2026-09-15 16:41 (Theresa, #pbl-website-dark). Phones (<=900px, the hero's
   mobile breakpoint used by the base rules and the rAF fallback's 901px
   matchMedia) get a STATIC hero photo: the view-timeline animation is off, and
   the rAF fallback (legacy browsers without animation-timeline) is neutralised
   too because these !important declarations beat the inline transform/position/
   top/height it writes. Desktop rules (>=901px: hebParallax keyframes,
   view-timeline, hero-cover-0914) are untouched. Static offset: with the CSS
   view-timeline the image sat at translateY ~88px on load (html
   scroll-padding-top:114px shifts the contain range; measured 91.6/88.4/87.0/
   83.6px at 375x667/390x844/430x932/820x1180), so the photo is pinned at
   translate3d(0,88px,0) — same placement/crop as the current 0-scroll frame, it
   just no longer moves. Background image/size/position + bottom mask unchanged. */
@media (max-width: 900px) {
  #heroeng-bg-wrap { view-timeline: none !important; }
  #heroeng-bg-wrap .heb-img {
    animation: none !important;
    animation-timeline: none !important;
    animation-name: none !important;
    transform: translate3d(0, 88px, 0) !important;
    translate: none !important;
    position: absolute !important;
    top: 0 !important; bottom: 0 !important; height: auto !important;
    will-change: auto !important;
  }
}


/* ===== v2 block: every-env-mobile-0915 ===== */

/* every-env-mobile-0915: lighten image on phones (Theresa, 2026-09-15 16:53 iPhone screenshot:
   player in "Every Environment" section barely visible). Phone-only override of the @700 rule
   (opacity .28, w300/54vw, right -40, top 34 via A5) + base mask (fade from 48%), and extra
   top padding so the player sits ABOVE the label/headline instead of under it. Desktop untouched. */
@media (max-width: 900px) {
  #solutions { padding-top: 190px !important; }
  #solutions .env-bball {
    opacity: 0.92 !important;
    width: 270px !important;
    max-width: 72vw !important;
    right: -28px !important;
    top: -8px !important;
    filter: drop-shadow(0 20px 40px rgba(0,0,0,0.55)) saturate(1.05) !important;
    -webkit-mask-image: linear-gradient(210deg, #000 72%, transparent 100%) !important;
    mask-image: linear-gradient(210deg, #000 72%, transparent 100%) !important;
  }
}


/* ===== v2 block: p2fix-0915 ===== */

/* P2-1 · fixed nav see-through. Base rule (L168) is rgba(10,10,15,.92) with no blur, so slider text and the
   INDUSTRIES pills ghost through the header on phones/tablets, and the "EVERY ENVIRONMENT" headline reads through
   at 1440 as well (QA before-shot d1440_header_solutions.png) — so this applies at ALL widths, not just <=900.
   .98 alpha + 12px backdrop blur = effectively opaque, still not a hard black bar; border-bottom untouched.
   Specificity 0,0,1 same as the base rule, later in cascade -> wins; the contact-overlay rule
   `body:has(#contactOverlay.is-open) nav { background:transparent }` (L8993, 0,2,1) still wins over this, and we
   drop the blur in that state too so the overlay reads exactly as before. */
nav {
  background: rgba(10,10,15,0.98);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}
body:has(#contactOverlay.is-open) nav { -webkit-backdrop-filter: none; backdrop-filter: none; }

/* P2-2 · desktop case-study modal (>=861px: 2-col grid, images stacked in the 5fr column). Two stacked images
   (Clinique 426x573 + 426x241) overflow the panel's max-height and the 2nd is cut at the panel bottom while the copy
   column ends early. Height budget per image, derived from the panel rules: panel max-height is
   calc(92vh - 74px) below 1400 (arrows row) / 92vh at >=1400, minus panel padding (clamp(28px,4vw,56px) -> 56px
   at these widths, x2), the CASE STUDY kicker (measured 44px incl. its 18px margin at the 16px !important size), the 16px gap and 4px slack, split in two:
   <1400: (92vh - 74 - 112 - 44 - 16 - 4) / 2 = 46vh - 125px;  >=1400: (92vh - 112 - 44 - 16 - 4) / 2 = 46vh - 88px.
   width:auto + max-width:100% keeps the native ratio (no object-fit letterboxing inside the 1px border); the column
   centres narrower (portrait) images. Never clips: both images always fit without panel scroll. */
@media (min-width: 861px) {
  .cs-modal-imgs { align-items: center; }
  .cs-modal-imgs img { width: auto; max-width: 100%; height: auto; max-height: calc(46vh - 125px); }
}
@media (min-width: 1400px) {
  .cs-modal-imgs img { max-height: calc(46vh - 88px); }
}

/* P2-3 · tablet modal (600–860px, e.g. iPad 820x1180). The flex column centres panel+arrows AS A GROUP, so the
   panel sits 74px (arrows row 54 + 20 padding) above true centre: 190 above vs 264 below on iPad before.
   Balance it with an equal top padding and take the same 74px out of the panel's max-height so a tall panel still
   fits (100vh - 74 - 74 = 100vh - 148px) and keeps scrolling internally. Phones (<600px) are deliberately excluded:
   at 390x844 the panel already uses its full calc(100vh - 74px) budget and would start scrolling. */
@media (min-width: 600px) and (max-width: 860px) {
  .cs-modal { padding-top: 74px; }
  .cs-modal-panel { max-height: calc(100vh - 148px); }
}

/* P2-4 · contact form invalid-field styling (set by the script below). Matches the existing focus treatment but in
   the site magenta so it reads as an error, not focus; label picks up the colour too. */
#contactOverlay .contact-field [aria-invalid="true"],
#contactOverlay .contact-field [aria-invalid="true"]:focus {
  border-color: #E23A5C;
  box-shadow: 0 0 0 2px rgba(226,58,92,0.18);
}
/* !important needed: L11705 sets the label colour !important (contrast fix) */
#contactOverlay .contact-field:has([aria-invalid="true"]) label { color: #E23A5C !important; }
#contactOverlay .contact-field:has([aria-invalid="true"]) label::before { opacity: 1; color: #E23A5C; }


/* ===== v2 block: polish2-0915 ===== */

  /* P3-1 hamburger: 38x40.5 -> 44x44. Glyph (22px bars, 5px margins) unchanged; padding grows 8->11 horizontally
     and 8->9.75 vertically. margin-left:-3px keeps the bars at the same x; nav is align-items:center so y is unchanged. */
  .hamburger { padding: 9.75px 11px !important; min-width: 44px; min-height: 44px; box-sizing: border-box; margin-left: -3px; }
  /* P3-3 contact overlay close: 36 -> 44px box, moved 4px up/left so the x glyph stays exactly where it was (font-size untouched). */
  #contactOverlay .contact-overlay-close { width: 44px; height: 44px; top: 14px; right: 14px; }
  /* P3-4 phone link: 25.6px -> 44px tap height. Text stays put and neighbours do not move: the extra 18.4px is
     cancelled by -9.2px margins top (8px original -> -1.2px) and bottom. */
  #contact .contact-link-phone { display: inline-flex; align-items: center; min-height: 44px; margin-top: -1.2px; margin-bottom: -9.2px; }
  /* P3-10 eyebrow / kicker labels only (WHO WE ARE, WHAT WE DO, WE DO IT IN PUBLIC, HOW WE DO IT).
     #EE2266 measured 4.19-4.76:1 vs mean sampled bg; #F03C78 (same hue, +lightness) measures 4.66-5.29:1. var(--magenta), buttons, focus rings untouched. */
  .section-label, #engineering .ww-hero .section-label { color: #F03C78; }


/* ===== v2 block: maxw-0916 ===== */

/* 2026-09-16: cap full-bleed background photos on >1920px screens (audit .openclaw/tmp/n3-maxw) */
@media (min-width: 1921px) {
  /* THE LAB: freeze at the 1920 rendering (height-fit, ~2180px wide, centred) + edge fade into #08070a.
     Must restate the whole shorthand because the original (L8341) is !important. */
  #the-lab {
    background:
      linear-gradient(180deg, rgba(8,7,10,.82) 0%, rgba(8,7,10,.5) 18%, rgba(8,7,10,.38) 48%, rgba(8,7,10,.56) 80%, rgba(8,7,10,.88) 100%),
      linear-gradient(90deg, #08070a 0, #08070a calc(50% - 1090px), rgba(8,7,10,0) calc(50% - 900px), rgba(8,7,10,0) calc(50% + 900px), #08070a calc(50% + 1090px), #08070a 100%),
      #08070a url('/lab-stage-bg-0714.webp') center 40% / auto 100% no-repeat !important;
  }
  /* CONTACT: native 1920px, centred, vignetted so the layer edge never bands. */
  #contact .contact-bg {
    background-size: 1920px auto;
    background-position: center 38%;
    background-color: #0a0a0f;
    -webkit-mask-image: radial-gradient(1040px 720px at 50% 45%, #000 55%, transparent 100%);
    mask-image: radial-gradient(1040px 720px at 50% 45%, #000 55%, transparent 100%);
  }
}
