/* ═══ WWO popup — Mockup F build 16 port (2026-09-22, Theresa, #pbl-website-dark thread 1790022597.018409). Replaces css/wwo-popup-0918.css.
   Generated by .openclaw/tmp/wwo-staging-0922/build-css.mjs from cobblestone-new3 wwo-gallery.html f-css.css (Part 1b + Part 2 + builds 5-16),
   rescoped #mockup-popup .mf-fs -> #wwo-fs (index-v2's real WWO filmstrip), #mf-track/#mf-prev/#mf-next -> #wfs-track/#wfs-prev/#wfs-next.
   Hint A hardcoded (F's shipped variant), layout stacked; B/C/toggles/hint line dropped. Build-12 mobile layout-match block dropped: staging already
   runs that slider (#wwo-mslider, slick fade) — the <=768 SHEET (builds 13-16) opens from taps on its .mslide instead of the hidden desktop tile.
   The base carousel cascade (.wfs-*) is untouched (index-v2 carries it). ═══ */
.mf-modal { --mono: 'SF Mono', 'Menlo', 'Roboto Mono', monospace; } /* = the gallery page :root --mono the F popup chips render in (staging :root defines no --mono) */
    #wwo-fs .tile { cursor: pointer; outline: none; }
    /* 2026-09-18h (Theresa): set by JS on modal close while the pointer still rests on the tile so the overlay returns to the plain image. Cleared on the
       next real mousemove / pointerdown / keydown (see f-js close()).
       2026-09-21 build 11 QA (B2): was `pointer-events:none` — that made the tile un-hit-testable, so the NEXT click at the same spot (Esc, then click again
       without moving) targeted the track and was swallowed. Now the class neutralises the hover VISUALS instead (:hover still matches, clicks still land):
       every hover rule of the ported cascade + the hint variants is reset to its idle value with a higher-specificity !important rule. */
    #wwo-fs .tile.mf-no-hover:hover .tags, #wwo-fs .tile.mf-no-hover:hover .mf-lane, #wwo-fs .tile.mf-no-hover:hover .mf-cta { opacity: 0 !important; }
    #wwo-fs .tile.mf-no-hover:hover img { filter: brightness(0.92) !important; transform: none !important; }
    #wwo-fs .tile.mf-no-hover:hover .fig { opacity: 1 !important; text-decoration: none !important; }
    #wwo-mosaic #wwo-fs .tile.mf-no-hover:hover .mf-badge { opacity: 0.55 !important; border-color: rgba(255,226,192,0.7) !important; }

    /* bottom 44px lane = same tint as the live overlay, never scrolls: CTA left (the live overlay reserves these 44px for the FIG) */
    #wwo-fs .mf-lane { position: absolute; left: 0; right: 0; bottom: 0; height: 44px; z-index: 3; background: rgba(8,8,12,0.85); opacity: 0; transition: opacity .35s ease; pointer-events: none; }
    #wwo-fs .tile:hover .mf-lane, #wwo-fs .tile.is-active .mf-lane { opacity: 1; }
    /* subtle "click to expand" affordance, bottom-left of the hover overlay */
    #wwo-fs .mf-cta {
      position: absolute; z-index: 5; left: 28px; bottom: 12px; font-family: var(--mono); font-size: 16px; letter-spacing: 0.05em; text-transform: uppercase;
      color: var(--terra); opacity: 0; transition: opacity .35s ease; pointer-events: none; display: inline-flex; align-items: center; gap: 6px;
    }
    #wwo-fs .mf-cta::before { content: '\2922'; font-size: 14px; line-height: 1; }
    #wwo-fs .tile:hover .mf-cta, #wwo-fs .tile.is-active .mf-cta { opacity: 1; }
    #wwo-fs .tile.wfs-under-prev .mf-cta { left: 84px; }

    #wwo-fs .mf-badge { position: absolute; z-index: 5; right: 12px; bottom: 6px; width: 32px; height: 32px; display: none; align-items: center; justify-content: center; border: 1px solid rgba(255,226,192,0.7); background: rgba(8,8,12,0.55); color: var(--cream); font-size: 16px; line-height: 1; opacity: 0.55; transition: opacity .3s ease, border-color .3s ease; pointer-events: none; }
    #wwo-fs .mf-badge::before { content: '\2922'; }
    /* A — persistent corner badge (idle 55%, hover 100% + accent), FIG shifts left of it; CTA reads "View project →" */
    #wwo-mosaic #wwo-fs .mf-badge { display: inline-flex; }
    @media (min-width: 901px) { #wwo-mosaic #wwo-fs .tile .fig, #wwo-mosaic #wwo-fs .tile:hover .fig, #wwo-mosaic #wwo-fs .tile.is-active .fig, #wwo-mosaic #wwo-fs .tile.show-tags .fig { right: 56px !important; } }
    #wwo-mosaic #wwo-fs .tile { cursor: zoom-in; }
    #wwo-mosaic #wwo-fs .tile:hover .mf-badge, #wwo-mosaic #wwo-fs .tile.is-active .mf-badge { opacity: 1; border-color: var(--terra); }
    #wwo-mosaic #wwo-fs .mf-cta::before { display: none; }

    /* ── 769–900px: carousel exactly as live, but the popup is desktop-only (≥901px): no click, no hint affordance ── */
    @media (max-width: 900px) {
      #wwo-fs .tile { cursor: default; }
      #wwo-fs .mf-lane, #wwo-fs .mf-cta, #wwo-fs .mf-badge { display: none !important; }
      #wwo-fs .tile .fig::after { content: none !important; }
    }
    /* 2026-09-21 build 13: the popup is hidden ONLY in the 769-900 band now; <=768 it becomes the full-screen sheet (block at the end of this sheet) */
    @media (min-width: 769px) and (max-width: 900px) { .mf-modal { display: none !important; } }
        /* modal — cs-modal look */
    .mf-modal { position: fixed; inset: 0; z-index: 4000; display: flex; align-items: center; justify-content: center; padding: 4vh 4vw; }
    .mf-modal[hidden] { display: none; }
    .mf-modal-scrim { position: absolute; inset: 0; background: rgba(5,5,12,0.92); }
    .mf-modal-panel {
      position: relative; z-index: 2; max-width: 1180px; width: 100%; max-height: 92vh; overflow-y: auto;
      background-color: #0A0A12; /* 2026-09-18d: solid dark panel; the atmosphere comes from .mf-modal-bg (tile image, blurred, low opacity) */
      border: 1px solid rgba(196,125,106,0.3); padding: clamp(28px,4vw,56px);
    }
    /* 2026-09-18d (Theresa): tile's ORIGINAL carousel image as full-bleed cover background at low opacity + slight blur — atmosphere, not content.
       Absolutely positioned + clipped wrapper (img bleeds 16px past every edge so the blur has no bright halo); z-index 0 under all content, never affects layout. */
    .mf-modal-bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
    .mf-modal-bg img { position: absolute; inset: -16px; width: calc(100% + 32px); height: calc(100% + 32px); object-fit: cover; object-position: center; opacity: 0.26; filter: blur(6px); display: block; }
    .mf-modal-layout, .mf-modal-img, .mf-modal-copy { position: relative; z-index: 1; }
    .mf-modal-close {
      position: absolute; top: 14px; right: 14px; z-index: 3; width: 44px; height: 44px; border: 1px solid rgba(232,232,240,0.3); background: rgba(5,5,12,0.5);
      color: rgba(232,232,240,0.85); font-size: 26px; line-height: 1; cursor: pointer; transition: border-color .3s, color .3s;
    }
    .mf-modal-close:hover { border-color: #C47D6A; color: #FFE2C0; }
    .mf-modal-layout { display: grid; grid-template-columns: minmax(0,7fr) minmax(0,5fr); gap: clamp(24px,3vw,48px); align-items: start; }
    /* 2026-09-21 build 11 QA (B4): the layout has THREE children since build 5 (.mf-modal-img, .mf-thumbs, .mf-modal-copy). In the side-by-side variant
       the thumbs auto-placed into column 2 and pushed the copy card to a new row (panel 860px > 826 -> inner scroll). Pin: media + thumbs in column 1, copy spans both rows. */
    .mf-modal:not(.is-stacked) .mf-modal-layout { grid-template-rows: auto auto; row-gap: 12px; }
    .mf-modal:not(.is-stacked) .mf-modal-img { grid-column: 1; grid-row: 1; }
    .mf-modal:not(.is-stacked) .mf-thumbs { grid-column: 1; grid-row: 2; margin: 0; }
    .mf-modal:not(.is-stacked) .mf-modal-copy { grid-column: 2; grid-row: 1 / span 2; }
    .mf-modal-img img { width: 100%; height: auto; display: block; border: 1px solid rgba(232,232,240,0.12); }
    /* 2026-09-18d (Theresa): copy block = frosted card over the blurred tile background (same treatment for video and image tiles) */
    .mf-modal-copy {
      background: rgba(10,10,18,0.55); border: 1px solid rgba(232,232,240,0.12); border-radius: 12px; padding: 22px 24px;
      backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    }
    .mf-modal-copy .mf-modal-tags:last-child { margin-bottom: 0; }
    /* stacked variant (default) — media on top, copy card below. 2026-09-18g (Theresa: "model sizing after staging; the video should be
       the size the image is in the staging popup"). Media box == staging.cobblestonelabs.ai WWO popup image (css/wwo-popup-0918.css):
       panel max-width 800px, media width 100% of panel content, aspect-ratio 16/10, capped at 44vh (measured 718x396 @1440x900, 721x352 @1280x800),
       gap 20px. Video = contain inside that same box (16:9 source gets thin letterbox bars), image = cover. Media never shrinks for copy
       (flex: 0 0 auto); if the copy card does not fit in the 92vh panel the CARD scrolls internally — never the media. Card width == media width == 100%. */
    .mf-modal.is-stacked .mf-modal-panel { max-width: 800px; padding: clamp(22px,2.6vw,34px) clamp(24px,3vw,40px); display: flex; flex-direction: column; }
    .mf-modal.is-stacked .mf-modal-layout { display: flex; flex-direction: column; align-items: stretch; gap: 0; flex: 0 1 auto; min-height: 0; width: 100%; margin: 0 auto; }
    .mf-modal.is-stacked .mf-modal-img { flex: 0 0 auto; width: 100%; height: auto; margin-bottom: 20px; text-align: center; line-height: 0; }
    .mf-modal.is-stacked .mf-modal-img img, .mf-modal.is-stacked .mf-modal-img video { display: inline-block; vertical-align: top; box-sizing: border-box; width: 100%; max-width: 100%; margin: 0; aspect-ratio: 16 / 10; height: auto; max-height: 44vh; }
    .mf-modal.is-stacked .mf-modal-img img { object-fit: cover; object-position: center; }
    .mf-modal.is-stacked .mf-modal-copy { flex: 0 1 auto; width: 100%; box-sizing: border-box; min-height: 120px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: rgba(196,125,106,0.6) transparent; }
    /* 2026-09-18g-2 (Theresa): card must FIT at 1440x900 without shrinking the 718x396 media. Match staging's vertical rhythm:
       no kicker row in the panel (staging hides it) — the layout itself reserves the x row: 72px from panel top minus panel padding (as staging);
       2026-09-18h (Theresa): eyebrow REMOVED entirely (kicker markup + ::before deleted); title sits at the top of the card. Card padding 22/24 -> 16/20,
       title/desc/tag margins tightened, panel max-height 92vh -> 94vh. */
    .mf-modal.is-stacked .mf-modal-panel { max-height: 94vh; padding-bottom: 24px; /* 34 -> 24: the 10px that FIG 10 / FIG 02 still overflowed by at 1440x900 */ }
    .mf-modal.is-stacked .mf-modal-layout { margin-top: calc(72px - clamp(22px,2.6vw,34px)); }
    .mf-modal.is-stacked .mf-modal-copy { padding: 16px 20px; }
    .mf-modal.is-stacked .mf-modal-title { margin: 0 0 10px; }
    .mf-modal.is-stacked .mf-modal-desc { margin: 0 0 14px; }
    .mf-modal.is-stacked .mf-modal-tags { margin-bottom: 10px; }
    .mf-modal.is-stacked .mf-modal-copy .mf-modal-tags:last-child { margin-bottom: 0; }
    /* 2026-09-18d (Theresa): concept VIDEO 16:9, contain (3:2 sources get small pillar bars), poster = vthumb.webp (real video frame, build 8). Stills row removed. */
    .mf-modal-img video { display: block; width: auto; max-width: 100%; margin: 0 auto; aspect-ratio: 16 / 9; height: auto; max-height: 52vh; object-fit: contain; object-position: center; background: #000; border: 1px solid rgba(232,232,240,0.12); }
    .mf-modal.is-stacked .mf-modal-img video { max-height: 44vh; }
    .mf-modal-img video[hidden], .mf-modal-img img[hidden], .mf-modal.is-stacked .mf-modal-img video[hidden], .mf-modal.is-stacked .mf-modal-img img[hidden] { display: none; }
    .mf-modal:not(.is-stacked) .mf-modal-img video { max-height: none; }
    .mf-modal.is-stacked .mf-modal-title { font-size: clamp(28px, 3vw, 40px); }
    /* ── 2026-09-20 build 5 (Theresa): VIEWER THUMBNAILS under the media box. Row = left-aligned, same width as the viewer, 100px 16:9 thumbs, 10px gap:
       [video poster + play glyph] [original tile image] [one more concept still]. Selected = accent border (site --terra #C47D6A, the accent every other
       Mockup F control uses), others dimmed. <button aria-pressed> + arrow keys (f-js). Hidden (and no class) when a tile has a single item (FIG 03 / 04).
       The 718x396 viewer is NEVER shrunk: the row's ~66px is paid for by tighter panel/card spacing below (72 -> 62px above the media, 24 -> 18 panel
       bottom, card 16 -> 14 top/bottom, desc 14 -> 10, tags 10 -> 8) and the panel cap 94vh -> 96vh with 2vh modal padding (tallest copy: 820 -> ~852 @1440x900). ── */
    .mf-modal.is-stacked .mf-modal-panel { max-height: 96vh; padding-bottom: 18px; }
    .mf-modal.is-stacked { padding: 2vh 4vw; }
    .mf-modal.is-stacked .mf-modal-layout { margin-top: calc(62px - clamp(22px,2.6vw,34px)); }
    .mf-modal.is-stacked .mf-modal-copy { padding: 14px 20px; }
    .mf-modal.is-stacked .mf-modal-title { margin: 0 0 8px; }
    .mf-modal.is-stacked .mf-modal-desc { margin: 0 0 10px; }
    .mf-modal.is-stacked .mf-modal-tags { margin-bottom: 8px; }
    .mf-modal.is-stacked.mf-has-thumbs .mf-modal-img { margin-bottom: 10px; }
    /* 2026-09-21 build 11 QA (short laptops 1280x720 / 1366x768): the card overflowed by 22-67px and scrolled as a whole (title scrolled away,
       industries chips cut). Now the card is a flex column and ONLY the description scrolls; title + tags stay pinned; the viewer is never shrunk
       (still == staging 44vh box). Under 820px height the type/spacing tighten so most FIGs need no scroll at all. */
    .mf-modal.is-stacked .mf-modal-copy { display: flex; flex-direction: column; overflow: hidden; }
    .mf-modal.is-stacked .mf-modal-title, .mf-modal.is-stacked .mf-modal-tags { flex: 0 0 auto; }
    .mf-modal.is-stacked .mf-modal-desc { flex: 0 1 auto; min-height: 0; overflow-y: auto; scrollbar-width: thin; scrollbar-color: rgba(196,125,106,0.6) transparent; }
    .mf-modal.is-stacked .mf-modal-desc.mf-desc-scroll { -webkit-mask-image: linear-gradient(#000 calc(100% - 22px), transparent); mask-image: linear-gradient(#000 calc(100% - 22px), transparent); }
    @media (min-width: 901px) and (max-height: 820px) {
      .mf-modal.is-stacked .mf-modal-layout { margin-top: calc(52px - clamp(22px,2.6vw,34px)); }
      .mf-modal.is-stacked .mf-modal-panel { padding-bottom: 12px; }
      .mf-modal.is-stacked .mf-modal-title { font-size: clamp(24px, 2.4vw, 30px); margin: 0 0 6px; }
      .mf-modal.is-stacked .mf-modal-desc { font-size: 15px; line-height: 1.45; margin: 0 0 8px; }
      .mf-modal.is-stacked .mf-modal-copy { padding: 12px 18px; }
      .mf-modal.is-stacked .mf-modal-tags { margin-bottom: 6px; }
      .mf-modal.is-stacked .mf-thumbs { margin-bottom: 10px; }
      .mf-modal.is-stacked .mf-thumb { flex-basis: 88px; width: 88px; }
    }
    /* 2026-09-21 build 6 (Theresa): 5 thumbs (video + 4 concept images) centered under the viewer; 5x100 + 4x10 = 540px < 718px viewer, one row */
    .mf-thumbs { position: relative; z-index: 1; display: flex; flex-wrap: nowrap; justify-content: center; align-items: center; gap: 10px; width: 100%; box-sizing: border-box; margin: 0 0 14px; overflow-x: auto; scrollbar-width: thin; scrollbar-color: rgba(196,125,106,0.6) transparent; }
    .mf-thumbs[hidden] { display: none; }
    .mf-thumb { position: relative; flex: 0 0 100px; width: 100px; aspect-ratio: 16 / 9; padding: 0; margin: 0; border: 2px solid rgba(232,232,240,0.14); background: #000; overflow: hidden; cursor: pointer; line-height: 0; opacity: 0.5; transition: opacity .2s ease, border-color .2s ease; box-sizing: border-box; }
    .mf-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center; }
    .mf-thumb:hover { opacity: 0.85; }
    .mf-thumb[aria-pressed="true"] { opacity: 1; border-color: var(--terra, #C47D6A); }
    .mf-thumb:focus-visible { outline: 2px solid #FFE2C0; outline-offset: 2px; }
    /* play glyph on the video thumb: dark disc + cream triangle */
    .mf-thumb-video::before { content: ''; position: absolute; left: 50%; top: 50%; width: 24px; height: 24px; margin: -12px 0 0 -12px; border-radius: 50%; background: rgba(8,8,12,0.72); border: 1px solid rgba(255,226,192,0.8); box-sizing: border-box; pointer-events: none; }
    .mf-thumb-video::after { content: ''; position: absolute; left: 50%; top: 50%; width: 0; height: 0; margin: -5px 0 0 -3px; border-style: solid; border-width: 5px 0 5px 8px; border-color: transparent transparent transparent #FFE2C0; pointer-events: none; }
    /* image shown in the viewer of a VIDEO tile: contain in the same fixed 16:10 box on the same black, like the video (FIG 03/04 keep their cover image) */
    .mf-modal.is-stacked.mf-has-media.mf-viewer-image .mf-modal-img img { object-fit: contain; object-position: center; background: #000; }
    @media (prefers-reduced-motion: reduce) { .mf-thumb { transition: none !important; } }
    /* ── 2026-09-21 build 7 (Theresa): small ‹ › steppers INSIDE the 718x396 viewer (absolute, 12px inset, vertically centered; .mf-modal-img is
       position:relative + line-height:0, so its box == the media box). Echo the carousel chevrons (#wfs-prev/#wfs-next: translucent dark disc, cream
       glyph, light 300 weight, terra on hover) at 36px. Overlay => popup width/height unchanged. Hidden for single-item tiles (FIG 03/04) via [hidden]
       + .mf-has-thumbs guard; ≤768 the popup does not exist, hidden anyway. ── */
    .mf-viewer-arrow { position: absolute; top: 50%; z-index: 2; width: 36px; height: 36px; margin-top: -18px; padding: 0 0 3px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border-radius: 50%; border: 1px solid rgba(255,226,192,0.35); background: rgba(10,10,15,0.55); color: #FFE2C0; font-family: var(--font-body, inherit); font-weight: 300; font-size: 28px; line-height: 1; cursor: pointer; opacity: 0.65; transition: opacity .25s ease, border-color .25s ease, background .25s ease, color .25s ease; }
    .mf-viewer-prev { left: 12px; } .mf-viewer-next { right: 12px; }
    .mf-viewer-arrow:hover, .mf-viewer-arrow:focus-visible { opacity: 1; background: rgba(10,10,15,0.8); border-color: rgba(196,125,106,0.9); color: #FFE2C0; }
    .mf-viewer-arrow:focus-visible { outline: 2px solid #FFE2C0; outline-offset: 2px; }
    .mf-viewer-arrow[hidden], .mf-modal:not(.mf-has-thumbs) .mf-viewer-arrow { display: none; }
    @media (max-width: 768px) { .mf-modal:not(.mf-sheet) .mf-viewer-arrow { display: none !important; } } /* build 13: the sheet reuses the ‹ › discs */
    @media (prefers-reduced-motion: reduce) { .mf-viewer-arrow { transition: none !important; } }
    /* layout + hint toggles */
    .mf-modal-title {
      font-family: var(--font-head); font-weight: 700; font-size: clamp(34px,3.4vw,52px); line-height: 1.02; text-transform: uppercase; letter-spacing: 0.05em;
      background: linear-gradient(120deg,#FFE2C0,#C47D6A,#FFE2C0); background-size: 200% 100%; -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; color: #FFE2C0; margin: 0 0 14px;
    }
    .mf-modal-desc { font-family: var(--font-body); font-size: 16px; font-weight: 300; line-height: 1.65; color: rgba(232,232,240,0.85); margin: 0 0 22px; }
    .mf-modal-tags { display: flex; flex-wrap: wrap; gap: 5px 6px; margin-bottom: 14px; }
    .mf-modal-tags .lbl { flex-basis: 100%; font-family: var(--mono); font-size: 12px; letter-spacing: 0.2em; color: var(--terra); }
    .mf-modal-tags span:not(.lbl) { font-family: var(--mono); font-size: 13px; letter-spacing: 0.05em; text-transform: uppercase; color: var(--cream); border: 1px solid rgba(255,226,192,0.55); padding: 2px 7px; line-height: 1.2; background: rgba(10,10,15,0.55); }
    .mf-modal-tags span.tech { border-color: rgba(196,125,106,0.65); color: #F0C9BC; }
    @media (max-width: 900px) {
      .mf-modal { padding: 0; align-items: stretch; }
      .mf-modal-panel { max-height: 100vh; border: 0; padding-top: 72px; }
      .mf-modal-layout { grid-template-columns: 1fr; }
      .mf-modal-title { font-size: 30px; }
    }
    @media (prefers-reduced-motion: reduce) { #wwo-fs .mf-cta, #wwo-fs .mf-badge, #wwo-fs .mf-lane, #wwo-fs .tile .fig, #wwo-fs .tile .tags { /* B6 0921: FIG chip + tags overlay fade under RM (ported .tile rules out-specify the RM reset) */ transition: none !important; } }

    /* ── 2026-09-21 build 13 (Theresa, #pbl-website-dark): MOBILE (≤768px) FULL-SCREEN SHEET popup. ONE code path: the SAME #mf-modal DOM, fill/selectViewer/
       stepViewer/close logic as the desktop popup; f-js adds .mf-sheet at open() when the ≤768 MQ matches (and closes/reopens across 768/769, see applyMode).
       Layout: top bar (FIG label + ×, 44px, safe-area aware) / edge-to-edge 16:9 viewer (100vw × 56.25vw, the ‹ › discs + swipe) / 5 thumbs (44px tall,
       centered when they fit — first/last margin:auto — else horizontally scrollable with snap) / copy region (title + desc + chips in the layout-match
       mobile styles) which SCROLLS INSIDE the sheet while the viewer stays pinned. Pinned viewer chosen because at 320×568 the copy region still gets
       568 − 44 − 180 − 60 = 284px ≈ 50% ≥ 40%. Landscape phones (≤500px tall) switch to a whole-sheet scroll with a 56vh viewer. Slides up 300ms
       (none under prefers-reduced-motion). Body scroll lock = html/body overflow hidden + body position:fixed with the saved scrollY (iOS-safe), restored on close. ── */
    .mf-sheet-bar { display: none; }
    html.mf-sheet-lock, body.mf-sheet-lock { overflow: hidden !important; }
    body.mf-sheet-lock { position: fixed !important; left: 0; right: 0; width: 100%; }
    @media (max-width: 768px) {
      #wwo-mslider .mslide { cursor: pointer; -webkit-tap-highlight-color: transparent; } /* build 13: tap = sheet (staging: the mobile slide, not the hidden desktop tile) */
      .mf-modal.mf-sheet { display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start; padding: 0; z-index: 4100; background: #0A0A12; height: 100vh; height: 100dvh; }
      .mf-modal.mf-sheet[hidden] { display: none; }
      .mf-modal.mf-sheet .mf-modal-scrim, .mf-modal.mf-sheet .mf-modal-bg { display: none; }
      .mf-modal.mf-sheet .mf-modal-panel { position: relative; width: 100%; max-width: none; height: 100%; max-height: none; border: 0; border-radius: 0; padding: 0; margin: 0; display: flex; flex-direction: column; overflow: hidden; background: #0A0A12; transform: translateY(100%); transition: transform .3s ease; }
      .mf-modal.mf-sheet.mf-sheet-in .mf-modal-panel { transform: none; }
      .mf-modal.mf-sheet .mf-sheet-bar { display: flex; align-items: center; flex: 0 0 auto; height: 44px; padding: env(safe-area-inset-top, 0px) 60px 0 14px; box-sizing: content-box; font-family: var(--mono, 'SF Mono', Menlo, monospace); font-size: 13px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--terra, #C47D6A); }
      .mf-modal.mf-sheet .mf-modal-close { top: env(safe-area-inset-top, 0px); right: 8px; width: 44px; height: 44px; border: 0; background: transparent; font-size: 30px; color: var(--cream, #FFE2C0); }
      .mf-modal.mf-sheet .mf-modal-layout { display: flex; flex-direction: column; align-items: stretch; flex: 1 1 auto; min-height: 0; margin: 0; gap: 0; width: 100%; }
      .mf-modal.mf-sheet .mf-modal-img { flex: 0 0 auto; width: 100vw; height: 56.25vw; margin: 0; position: relative; line-height: 0; background: #000; touch-action: pan-y; }
      .mf-modal.mf-sheet .mf-modal-img img, .mf-modal.mf-sheet .mf-modal-img video { display: block; width: 100%; height: 100%; max-width: none; max-height: none; aspect-ratio: auto; margin: 0; border: 0; object-fit: contain; object-position: center; background: #000; }
      .mf-modal.mf-sheet .mf-modal-img img[hidden], .mf-modal.mf-sheet .mf-modal-img video[hidden] { display: none; }
      .mf-modal.mf-sheet .mf-thumbs { flex: 0 0 auto; justify-content: flex-start; gap: 8px; margin: 0; padding: 8px 12px; width: 100%; overflow-x: auto; overflow-y: hidden; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
      .mf-modal.mf-sheet .mf-thumbs::-webkit-scrollbar { display: none; }
      .mf-modal.mf-sheet .mf-thumb { flex: 0 0 78px; width: 78px; height: 44px; aspect-ratio: auto; scroll-snap-align: center; }
      .mf-modal.mf-sheet .mf-thumb:first-child { margin-left: auto; }
      .mf-modal.mf-sheet .mf-thumb:last-child { margin-right: auto; }
      .mf-modal.mf-sheet .mf-modal-copy { flex: 1 1 auto; min-height: 0; display: block; overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; width: 100%; box-sizing: border-box; border: 0; border-top: 1px solid rgba(255,226,192,0.25); border-radius: 0; background: #101018; backdrop-filter: none; -webkit-backdrop-filter: none; padding: 14px 14px calc(24px + env(safe-area-inset-bottom, 0px)); }
      .mf-modal.mf-sheet .mf-modal-title { font-family: var(--font-head); font-weight: 700; text-transform: uppercase; font-size: 18px; letter-spacing: .03em; line-height: 1.1; color: var(--cream, #FFE2C0); background: none; -webkit-background-clip: border-box; background-clip: border-box; -webkit-text-fill-color: currentColor; margin: 0; }
      .mf-modal.mf-sheet .mf-modal-desc { font-family: var(--font-body); font-size: 16px; font-weight: 400; line-height: 1.4; color: rgb(217,219,244); margin: 0; padding: 4px 0 0; overflow: visible; flex: none; -webkit-mask-image: none; mask-image: none; }
      .mf-modal.mf-sheet .mf-modal-tags { display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; margin: 10px 0 0; }
      .mf-modal.mf-sheet .mf-modal-tags .lbl { flex-basis: 100%; color: var(--terra, #C47D6A); font-family: inherit; font-size: 16px; letter-spacing: 0.05em; text-transform: uppercase; line-height: 1.6; padding: 0 0 1px; }
      .mf-modal.mf-sheet .mf-modal-tags span:not(.lbl) { font-family: inherit; font-size: 16px; letter-spacing: 0.05em; text-transform: uppercase; color: var(--cream, #FFE2C0); border: 1px solid rgba(255,226,192,0.55); padding: 2px 7px; line-height: 1.3; white-space: normal; max-width: 100%; background: rgba(10,10,15,0.55); }
      .mf-modal.mf-sheet .mf-modal-tags span.tech { border-color: rgba(196,125,106,0.65); color: #F0C9BC; }
    }
    /* landscape phones: the 56.25vw viewer would exceed the height — cap it at 56vh, center it, and let the WHOLE sheet scroll */
    @media (max-width: 768px) and (max-height: 500px) {
      .mf-modal.mf-sheet .mf-modal-panel { overflow-y: auto; }
      .mf-modal.mf-sheet .mf-modal-layout { flex: 0 0 auto; }
      .mf-modal.mf-sheet .mf-modal-img { width: calc(56vh * 16 / 9); max-width: 100vw; height: 56vh; margin: 0 auto; }
      .mf-modal.mf-sheet .mf-modal-copy { flex: 0 0 auto; overflow: visible; }
    }
    @media (prefers-reduced-motion: reduce) { .mf-modal.mf-sheet .mf-modal-panel { transition: none !important; } }

    /* ── 2026-09-21 build 14 (Theresa, #pbl-website-dark): CARD-STYLE BOTTOM SHEET. Feedback on build 13: "the project is full screen and then you click and it's
       still full screen … not clear it's a pop up". The ≤768 sheet is now a CARD that slides up from the bottom over a dimmed, blurred page: scrim rgba(0,0,0,.6)
       + blur(6px) (tap closes), card height 92% (max 100dvh − 48px − safe-area-top → 520px at 320×568; 92% not 90% so the pinned copy region keeps ≥40% of the viewport
       height at 390×664 (42.7%); ≤600px tall portrait (320×568) falls back to a whole-card scroll), 20px top radius, 1px top border + inner highlight so the edge reads, grab handle (36×4 pill, 8px from the top edge). Drag-follow:
       f-js sets an inline translateY on the panel while the finger moves down on the handle/top-bar/viewer (.mf-dragging = no transition), snaps back when
       released short (<80px and not a flick), closes otherwise. Landscape (≤500px tall) keeps 100% height but the radius/handle stay. Inside the card nothing
       changes (viewer/arrows/thumbs/copy = build 13; viewer corners are clipped by the card radius via the panel's overflow:hidden). mf-sheet-card-0921 ── */
    @media (max-width: 768px) {
      .mf-modal.mf-sheet { background: transparent; justify-content: flex-end; }
      .mf-modal.mf-sheet .mf-modal-scrim { display: block; position: absolute; inset: 0; background: rgba(0,0,0,0.6); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); opacity: 0; transition: opacity .32s ease-out; }
      .mf-modal.mf-sheet.mf-sheet-in .mf-modal-scrim { opacity: 1; }
      .mf-modal.mf-sheet .mf-modal-panel { height: 92%; max-height: calc(100dvh - 48px - env(safe-area-inset-top, 0px)); border-top: 1px solid rgba(255,226,192,0.22); border-radius: 20px 20px 0 0; box-shadow: 0 -10px 36px rgba(0,0,0,0.55), inset 0 1px 0 rgba(255,255,255,0.06); transition: transform .32s ease-out; will-change: transform; }
      .mf-modal.mf-sheet.mf-dragging .mf-modal-panel, .mf-modal.mf-sheet.mf-dragging .mf-modal-scrim { transition: none; }
      .mf-modal.mf-sheet .mf-sheet-bar { position: relative; height: 48px; padding: 8px 60px 0 14px; box-sizing: border-box; }
      .mf-modal.mf-sheet .mf-sheet-bar::before { content: ''; position: absolute; top: 8px; left: 50%; width: 36px; height: 4px; margin-left: -18px; border-radius: 2px; background: rgba(255,226,192,0.45); }
      .mf-modal.mf-sheet .mf-modal-close { top: 4px; right: 8px; }
    }
    /* short portrait phones (≤600px tall, e.g. 320×568): the pinned copy region would drop under 40% of the viewport (measured 220/568) -> the WHOLE card scrolls instead */
    @media (max-width: 768px) and (max-height: 600px) and (min-height: 501px) {
      .mf-modal.mf-sheet .mf-modal-panel { overflow-y: auto; }
      .mf-modal.mf-sheet .mf-modal-layout { flex: 0 0 auto; }
      .mf-modal.mf-sheet .mf-modal-copy { flex: 0 0 auto; overflow: visible; min-height: calc(100% - 48px - 56.25vw - 60px); }
    }
    @media (max-width: 768px) and (max-height: 500px) {
      .mf-modal.mf-sheet .mf-modal-panel { height: 100%; max-height: none; }
    }
    @media (prefers-reduced-motion: reduce) { .mf-modal.mf-sheet .mf-modal-scrim { transition: none !important; } }

    /* ── 2026-09-21 build 15 (Theresa, #pbl-website-dark): INSET FLOATING CARD. Feedback on build 14: "when the cardsheet goes from end to end of the screen
       it's less obvious that it's a pop up". The ≤768 card is now inset 12px left/right and 12px (+ safe-area) from the bottom so the dimmed, blurred page shows
       on ALL sides; 20px radius on all four corners; 1px border all around; shadow all around. Height = calc(92% − 12px − safe-bottom) so the page peek above
       the card stays exactly 8% of the viewport (build 14 rule) and the pinned copy region keeps ≥40% at 390×664 (~43%: the narrower viewer gives back more
       than the 12px inset costs). Viewer width follows the card (100% of the panel; height = (100vw − 26px) × 9/16 — 24px inset + 2px border). The
       slide-out transform overshoots by the bottom inset so no 12px sliver lingers while closing. Landscape (≤500 tall): 100% height kept, sides inset 12px,
       bottom flush (top corners only). Handle, drag-follow, scrim tap-close, 320×568 whole-card scroll = build 14. mf-sheet-inset-0921 ── */
    @media (max-width: 768px) {
      .mf-modal.mf-sheet .mf-modal-panel { width: calc(100% - 24px); margin: 0 12px calc(12px + env(safe-area-inset-bottom, 0px)); height: calc(92% - 12px - env(safe-area-inset-bottom, 0px)); max-height: calc(100dvh - 60px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)); border: 1px solid rgba(255,226,192,0.22); border-radius: 20px; box-shadow: 0 8px 40px rgba(0,0,0,0.6), inset 0 1px 0 rgba(255,255,255,0.06); transform: translateY(calc(100% + 24px + env(safe-area-inset-bottom, 0px))); }
      .mf-modal.mf-sheet .mf-modal-img { width: 100%; height: calc((100vw - 26px) * 9 / 16); }
      .mf-modal.mf-sheet .mf-modal-copy { padding-bottom: 24px; }
    }
    @media (max-width: 768px) and (max-height: 600px) and (min-height: 501px) {
      .mf-modal.mf-sheet .mf-modal-copy { min-height: calc(100% - 48px - (100vw - 26px) * 9 / 16 - 60px); }
    }
    @media (max-width: 768px) and (max-height: 500px) {
      .mf-modal.mf-sheet .mf-modal-panel { height: 100%; max-height: none; margin-bottom: 0; border-bottom: 0; border-radius: 20px 20px 0 0; transform: translateY(100%); }
      .mf-modal.mf-sheet .mf-modal-img { width: calc(56vh * 16 / 9); max-width: 100%; height: 56vh; }
    }

    /* ── 2026-09-21 build 16 (Theresa, #pbl-website-dark): TITLE IN THE TOP BAR, FIG LABEL GONE. The ≤768 card's top bar (handle centered above) shows the
       concept title where the FIG label sat (left, next to the ×); the FIG number is not rendered anywhere inside the card. Title = the sheet's copy-title
       style (head font 700 uppercase 18px/1.1 cream), max 2 lines with an ellipsis, padding-right 60px so it never runs under the 44px ×; the bar grows
       from 48px (1 line) to 68px (2 lines). The copy region's own h3 is hidden on mobile so the copy starts with the description. aria-labelledby is
       switched by f-js to #mf-sheet-title while the sheet is up. Desktop (≥769) .mf-modal title/FIG untouched. mf-sheet-title-0921 ── */
    @media (max-width: 768px) {
      .mf-modal.mf-sheet .mf-sheet-bar { display: flex; align-items: flex-start; height: auto; min-height: 48px; padding: 18px 60px 8px 14px; font: inherit; letter-spacing: normal; text-transform: none; color: inherit; }
      .mf-modal.mf-sheet .mf-sheet-title { font-family: var(--font-head); font-weight: 700; text-transform: uppercase; font-size: 18px; letter-spacing: .03em; line-height: 1.1; color: var(--cream, #FFE2C0); margin: 0; padding: 0; min-width: 0; max-width: 100%; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; text-overflow: ellipsis; overflow-wrap: anywhere; background: none; -webkit-text-fill-color: currentColor; }
      .mf-modal.mf-sheet .mf-modal-copy .mf-modal-title { display: none; }
      .mf-modal.mf-sheet .mf-modal-desc { padding-top: 0; }
    }

    /* ── 2026-09-22 staging build 17 (Theresa, #pbl-website-dark thread 10:50): (a) WHOLE-CARD SCROLL on every ≤768 size — the pinned-viewer/scroll-inside-copy
       split (build 13) is gone: viewer, thumbs and copy are flow children of a vertically scrolling card, so the copy (description first) can never be clipped
       or pinned below a fixed region (iPhone SE report: "description missing"); the ≤600px-tall special case and its min-height math are neutralised.
       (b) NO horizontal thumb scroll: the 5 thumbs become a grid — a full-width 72px "Video" strip (poster, ▶ disc + label) above a 2×2 grid of the 4 concept
       images (16:9 cells, panel width minus 12px gutters, 8px gap). All 5 tappable with no scrolling. (c) .mf-thumb-lbl exists on the desktop video thumb too
       but is display:none there — desktop ≥901 renders byte-for-byte the same. Desktop rules above are untouched. mf-sheet-grid-0922 ── */
    .mf-thumb-lbl { display: none; }
    @media (max-width: 768px) {
      .mf-modal.mf-sheet .mf-modal-panel { overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
      .mf-modal.mf-sheet .mf-modal-layout { flex: 0 0 auto; min-height: 0; }
      .mf-modal.mf-sheet .mf-modal-copy { flex: 0 0 auto; overflow: visible; min-height: 0; overscroll-behavior: auto; }
      .mf-modal.mf-sheet .mf-thumbs { display: grid; grid-template-columns: 1fr 1fr; grid-auto-rows: auto; gap: 8px; justify-content: stretch; align-items: stretch; padding: 8px 12px 10px; overflow: visible; scroll-snap-type: none; }
      .mf-modal.mf-sheet .mf-thumbs[hidden] { display: none; }
      .mf-modal.mf-sheet .mf-thumb { flex: none; width: 100%; height: auto; aspect-ratio: 16 / 9; margin: 0; scroll-snap-align: none; opacity: 0.6; }
      .mf-modal.mf-sheet .mf-thumb[aria-pressed="true"] { opacity: 1; }
      .mf-modal.mf-sheet .mf-thumb:first-child, .mf-modal.mf-sheet .mf-thumb:last-child { margin: 0; }
      .mf-modal.mf-sheet .mf-thumb-video { grid-column: 1 / -1; aspect-ratio: auto; height: 72px; }
      .mf-modal.mf-sheet .mf-thumb-video img { filter: brightness(0.55); }
      .mf-modal.mf-sheet .mf-thumb-video::before { width: 32px; height: 32px; margin: -16px 0 0 -46px; }
      .mf-modal.mf-sheet .mf-thumb-video::after { margin: -6px 0 0 -34px; border-width: 6px 0 6px 10px; }
      .mf-modal.mf-sheet .mf-thumb-lbl { display: block; position: absolute; left: 50%; top: 50%; margin-left: -6px; transform: translateY(-50%); font-family: var(--font-body); font-weight: 400; font-size: 15px; letter-spacing: .1em; text-transform: uppercase; color: #FFE2C0; line-height: 1; text-shadow: 0 1px 3px rgba(0,0,0,0.8); pointer-events: none; }
    }

/* ── 2026-09-22 staging build 18 — wwo-arrows-0922b18 (Theresa, #pbl-website-dark thread): mobile ≤768 ONLY. The WWO slider's ‹ › chevrons were 52×77 translucent glyphs
   (opacity .55 over rgba(10,10,15,.35)) that read as decoration — visitors saw ONE concept, not 13. Now: 48×48 solid discs (rgba(0,0,0,.55) + hairline + shadow), 22px
   3px-stroke white chevron, full opacity always, vertically centred on the image (the .mnav overlay keeps the page's top:31vw / translateY(-50%) centre), inset 10px from the
   image edges, :active scale .94. Plus a "1 / 13" counter pill bottom-RIGHT over the image (the FIG chip is bottom-left, the title lives in .minfo below — no collision),
   filled by js (wwo-arrows-0922b18 block) from slick's real slideCount. Desktop: #wwo-mslider is display:none ≥769, and every rule here sits inside the ≤768 query. ── */
@media (max-width: 768px) {
  #wwo-mslider div.mnav { padding: 0 10px; align-items: center; }
  #wwo-mslider .mnav .wwo-mprev, #wwo-mslider .mnav .wwo-mnext {
    box-sizing: border-box; position: relative; width: 48px; height: 48px; min-width: 48px; min-height: 48px; padding: 0; margin: 0;
    border-radius: 50%; background: rgba(0,0,0,0.55); border: 1px solid rgba(255,255,255,0.35);
    box-shadow: 0 2px 10px rgba(0,0,0,0.35), 0 0 0 1px rgba(0,0,0,0.15);
    color: #fff; font-size: 0; line-height: 0; opacity: 1 !important; /* full opacity — no fade-on-idle; the glyph is drawn below */
    -webkit-tap-highlight-color: transparent; touch-action: manipulation;
    transition: transform .12s ease, background-color .12s ease;
  }
  #wwo-mslider .mnav .wwo-mprev::before, #wwo-mslider .mnav .wwo-mnext::before {
    content: ""; position: absolute; top: 50%; left: 50%; width: 17px; height: 17px; box-sizing: border-box;
    border-top: 3px solid #fff; border-left: 3px solid #fff; border-radius: 1px; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.55));
  }
  #wwo-mslider .mnav .wwo-mprev::before { transform: translate(-32%, -50%) rotate(-45deg); }
  #wwo-mslider .mnav .wwo-mnext::before { transform: translate(-68%, -50%) rotate(135deg); }
  #wwo-mslider .mnav .wwo-mprev:hover, #wwo-mslider .mnav .wwo-mnext:hover { opacity: 1; background: rgba(0,0,0,0.68); }
  #wwo-mslider .mnav .wwo-mprev:active, #wwo-mslider .mnav .wwo-mnext:active { transform: scale(0.94); background: rgba(0,0,0,0.72); color: #fff; }
  #wwo-mslider .mnav .wwo-mprev:focus-visible, #wwo-mslider .mnav .wwo-mnext:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
  /* counter pill: over the image, bottom-right (image = .mimg img, 62vw tall, top-aligned with #wwo-mslider) */
  #wwo-mslider .wwo-mcount {
    position: absolute; right: 10px; top: calc(62vw - 8px); transform: translateY(-100%); z-index: 6; pointer-events: none;
    font-family: var(--mono, ui-monospace, Menlo, monospace); font-size: 11px; letter-spacing: .14em; line-height: 1; font-variant-numeric: tabular-nums;
    color: #fff; background: rgba(0,0,0,0.55); border: 1px solid rgba(255,255,255,0.25); border-radius: 999px; padding: 5px 9px 4px;
    text-shadow: 0 1px 2px rgba(0,0,0,0.4); white-space: nowrap;
  }
  #wwo-mslider .wwo-mcount:empty { display: none; }
}

/* ── 2026-09-22 staging build 19 — mf-sheet-row-0922b19 (Theresa, #pbl-website-dark 11:30, mockup): mobile ≤768 ONLY. The 4 concept-image thumbs under the
   "Video" strip were a 2×2 grid (build 17); Theresa wants them in ONE row of 4 equal-width thumbs (~8px gaps) under the full-width Video strip. Grid → flex-wrap:
   the video strip is flex-basis 100% (row 1), every other thumb flex 1 1 0 (row 2 shared equally — a project with fewer images still fills the row). 4:3 crop keeps
   them tappable: ≈85×64 at 390 wide, ≈66×50 at 320 (floor 60×44). Active-thumb outline/opacity, whole-card scroll (b17) and arrows/counter (b18) untouched.
   Desktop ≥901: every rule sits inside the ≤768 query — renders byte-for-byte the same. ── */
@media (max-width: 768px) {
  .mf-modal.mf-sheet .mf-thumbs { display: flex; flex-wrap: wrap; flex-direction: row; grid-template-columns: none; justify-content: stretch; align-items: stretch; gap: 8px; }
  .mf-modal.mf-sheet .mf-thumbs[hidden] { display: none; }
  .mf-modal.mf-sheet .mf-thumb { flex: 1 1 0; min-width: 60px; min-height: 44px; width: auto; height: auto; aspect-ratio: 4 / 3; }
  .mf-modal.mf-sheet .mf-thumb-video { flex: 0 0 100%; width: 100%; aspect-ratio: auto; height: 72px; min-height: 72px; }
}

/* ── 2026-09-22 staging build 20 — wwo-b20-0922 (Theresa, #pbl-website-dark): mobile ≤768 ONLY, three changes. (1) POPUP: the concept title leaves the top bar (bar keeps
   the drag handle + ×) and becomes the first line of the copy region, under the video strip + 4-up thumb row, above the description — the copy's own h3 (hidden since
   b16) is shown again in the same head-font style; js points aria-labelledby at it. (2) HOME TILE: the FIG chip's rectangle now carries the concept TITLE (js swaps the text,
   adds .wwo-mtitle): same position/style, grows with the title, ellipsis before it could touch the counter pill (right 10px, ~52px wide). The .minfo copy (description +
   TECH USED / INDUSTRIES chips) is hidden; in its place a .mf-mact row = "View project →" (.mf-mcta, the desktop .mf-cta look: mono 16px terra uppercase) + a bordered ⤢
   button (.mf-mbadge, the desktop .mf-badge look at 44×44 for touch). Both open the sheet (js mtrack click handler). (3) PEEK (proposal, flag WWO_PEEK in js): slick
   centerMode carousel, centerPadding 20px → slides are viewport−40px wide with 4px side padding each (8px gap), so the image is ≈88% of the viewport and 16px of each
   neighbour peeks; neighbours dimmed to 55%. Image keeps a fixed 3:2 box (aspect-ratio — no adaptiveHeight, every slide the same height, no layout jump); the b18 ‹ ›
   discs / counter re-centre on that box. Desktop ≥901: #wwo-mslider is display:none ≥769 and .mf-sheet only exists ≤768 — every rule sits inside the ≤768 query. ── */
@media (max-width: 768px) {
  /* (1) popup title under the thumbs */
  .mf-modal.mf-sheet .mf-sheet-title { display: none; }
  .mf-modal.mf-sheet .mf-sheet-bar { min-height: 48px; padding: 18px 60px 8px 14px; }
  .mf-modal.mf-sheet .mf-modal-copy .mf-modal-title { display: block; margin: 0 0 8px; padding: 0; font-family: var(--font-head); font-weight: 700; text-transform: uppercase; font-size: 18px; letter-spacing: .03em; line-height: 1.15; color: var(--cream, #FFE2C0); overflow-wrap: anywhere; }
  .mf-modal.mf-sheet .mf-modal-desc { padding-top: 0; }

  /* (2) home tile: title in the chip, copy hidden, action row */
  #wwo-mslider .mimg .fig.wwo-mtitle { max-width: calc(100% - 92px); box-sizing: border-box; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-transform: uppercase; line-height: 1.6; }
  /* b28 2026-09-23 (Theresa): <=340px the 156px chip (100% - 92px badge/counter reservation) truncated 5/13 titles at 16px.
     No wrap: one shared smaller size sized to the longest titles ("Machine, Deconstructed"/"Your Path, Your Product" = 154px @12.5px). */
  @media (max-width: 340px) { #wwo-mslider .mimg .fig.wwo-mtitle { font-size: 12.5px !important; } }
  #wwo-mslider .mslide .minfo { display: none; }
  #wwo-mslider .mslide .mf-mact { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 14px 10px; background: #101018; border-top: 1px solid rgba(255,226,192,0.25); }
  #wwo-mslider .mf-mcta { -webkit-appearance: none; appearance: none; background: none; border: 0; border-radius: 0; margin: 0; padding: 8px 0; min-height: 44px; cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
    font-family: var(--mono, ui-monospace, Menlo, monospace); font-size: 16px; letter-spacing: 0.05em; text-transform: uppercase; line-height: 1; color: var(--terra, #C47D6A); -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
  #wwo-mslider .mf-mbadge { -webkit-appearance: none; appearance: none; box-sizing: border-box; flex: 0 0 auto; width: 44px; height: 44px; margin: 0; padding: 0; display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid rgba(255,226,192,0.7); border-radius: 0; background: rgba(8,8,12,0.55); color: var(--cream, #FFE2C0); font-size: 18px; line-height: 1; cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
  #wwo-mslider .mf-mbadge::before { content: '\2922'; }
  #wwo-mslider .mf-mcta:active { opacity: 0.7; }
  #wwo-mslider .mf-mbadge:active { border-color: var(--terra, #C47D6A); background: rgba(8,8,12,0.8); }
  #wwo-mslider .mf-mcta:focus-visible, #wwo-mslider .mf-mbadge:focus-visible { outline: 2px solid #C47D6A; outline-offset: 2px; }

  /* (3) peek carousel — only when js added .wwo-peek (WWO_PEEK flag) */
  #wwo-mslider.wwo-peek .mslide { box-sizing: border-box; padding: 0 4px; }
  #wwo-mslider.wwo-peek .mimg img { height: auto; aspect-ratio: 3 / 2; }
  #wwo-mslider.wwo-peek .mnav { top: calc((100vw - 72px) / 3); }          /* half of the 3:2 image: (100vw − 24px mosaic padding − 40px centerPadding − 8px gap) × 2/3 ÷ 2 */
  #wwo-mslider.wwo-peek .wwo-mcount { top: calc((100vw - 72px) * 2 / 3 - 8px); right: 34px; }
  #wwo-mslider.wwo-peek div.mnav { padding: 0 34px; }                     /* discs inset 10px from the CURRENT image edge (24px peek+gap) */
  #wwo-mslider.wwo-peek #wwo-mtrack .slick-slide { opacity: 0.55; transition: opacity .45s ease; }
  #wwo-mslider.wwo-peek #wwo-mtrack .slick-slide.slick-current { opacity: 1; }
  #wwo-mslider.wwo-peek #wwo-mtrack .slick-list { overflow: hidden; }
  #wwo-mslider.wwo-peek #wwo-mtrack .slick-slide:not(.slick-current) .mf-mact > * { visibility: hidden; } /* neighbours' buttons don't leak into the 16px peek strip */
}
@media (max-width: 768px) and (prefers-reduced-motion: reduce) { #wwo-mslider.wwo-peek #wwo-mtrack .slick-slide { transition: none; } }

/* ── 2026-09-22 staging build 21 — wwo-b21-0922 (Theresa, #pbl-website-dark 12:30, reference screenshot): mobile ≤768 PORTRAIT ONLY (min-height 501 — landscape ≤500
   keeps its b13/b15 whole-sheet scroll). "The mobile pop up needs to still be formatted with the video thumbnail full width and then the four image thumbnails across
   full width below, no scrolling." The MEDIA block (viewer + full-width Video strip + 4-up thumb row) is PINNED at the top of the card and never scrolls; only the copy
   region below it (title → description → chips) scrolls internally. This reverts the b17 whole-card scroll (and the b14/b15 ≤600px-tall whole-card fallback) for portrait.
   Height budget (card = 92% − 12px, bar 48): iPhone 13 390×664 → copy ≈189px (title + ~7 lines); SE 375×667 → ≈202px; 320×568 → ≈153px (title + ~5 lines). Safety: the
   viewer is capped at 32dvh (object-fit: contain letterboxes) so very short portrait viewports still leave the copy ≥ title + 2 lines. Thumb row: same full width as the
   Video strip (both live in the same 12px-gutter flex row; flex 1 1 0 each, 8px gaps — b19), edge to edge of the card's inner padding. ── */
@media (max-width: 768px) and (min-height: 501px) {
  .mf-modal.mf-sheet .mf-modal-panel { overflow: hidden; overflow-y: hidden; }
  .mf-modal.mf-sheet .mf-modal-layout { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
  .mf-modal.mf-sheet .mf-modal-img { flex: 0 0 auto; height: min(calc((100vw - 26px) * 9 / 16), 32dvh); }
  .mf-modal.mf-sheet .mf-thumbs { flex: 0 0 auto; padding: 8px 14px 10px; gap: 8px; } /* 14px gutters = the copy's text padding, so strip + thumbs align with the title */
  .mf-modal.mf-sheet .mf-thumb { flex: 1 1 0; min-width: 0; }
  .mf-modal.mf-sheet .mf-thumb-video { flex: 0 0 100%; }
  .mf-modal.mf-sheet .mf-modal-copy { flex: 1 1 auto; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
}

/* ── 2026-09-22 staging build 22 — wwo-b22-0922 (QA pass, Theresa "run qa" 13:5x): phone LANDSCAPE (≤768 wide, ≤500 tall) peek tile. With the b20 3:2 image box the
   current tile at 667×375 is 595×397 — taller than the viewport: title chip, counter and the VIEW PROJECT row all sit below the fold and the discs float mid-screen.
   Cap the image at 58vh (object-fit: cover crops top/bottom) and re-derive the disc / counter anchors from the same expression so they stay centred / bottom-right.
   Portrait (min-height 501) is untouched. Reversible: delete this block → b20/b21 landscape behaviour. ── */
@media (max-width: 768px) and (max-height: 500px) {
  #wwo-mslider.wwo-peek .mimg img { aspect-ratio: auto; height: min(calc((100vw - 72px) * 2 / 3), 58vh); }
  #wwo-mslider.wwo-peek .mnav { top: calc(min(calc((100vw - 72px) * 2 / 3), 58vh) / 2); }
  #wwo-mslider.wwo-peek .wwo-mcount { top: calc(min(calc((100vw - 72px) * 2 / 3), 58vh) - 8px); }
}

/* ── 2026-09-22 staging build 23 — wwo-b23-0922 (Theresa 14:12): "View project →" reads LIGHT LAVENDER on desktop tiles (#wwo-fs .mf-cta) and in the mobile tile action
   row (#wwo-mslider .mf-mcta). Site token --lavender is #7F83A7 (too dim for 16px text on #0a0a0f, 3.9:1); light tint of the same hue: #C8BEF5 (≈11:1), hover/active
   brighter #E4DEFF. Existing hover mechanics untouched (desktop CTA still fades in on tile hover / .is-active; mobile keeps :active opacity). ── */
:root { --wwo-lavender-light: #C8BEF5; --wwo-lavender-lighter: #E4DEFF; }
#wwo-fs .mf-cta { color: var(--wwo-lavender-light); transition: opacity .35s ease, color .2s ease; }
#wwo-fs .tile:hover .mf-cta, #wwo-fs .tile.is-active .mf-cta { color: var(--wwo-lavender-lighter); }
#wwo-mslider .mf-mcta { color: var(--wwo-lavender-light); }
#wwo-mslider .mf-mcta:hover, #wwo-mslider .mf-mcta:active { color: var(--wwo-lavender-lighter); }

/* ── 2026-09-22 staging build 24 — wwo-b24-0922 (Theresa 14:24): the ⤢ expand button pairs with "View project →" — on hover (desktop: tile hover / .is-active, the
   badge is pointer-events:none so the tile is its hover target; mobile: .mf-mbadge :hover/:active/:focus-visible) glyph AND border turn the same light lavender
   #E4DEFF (--wwo-lavender-lighter) instead of terra. Resting state unchanged (cream glyph, cream 70% hairline). Desktop transition keeps .3s ease, color added. ── */
#wwo-fs .mf-badge { transition: opacity .3s ease, border-color .3s ease, color .3s ease; }
#wwo-mosaic #wwo-fs .tile:hover .mf-badge, #wwo-mosaic #wwo-fs .tile.is-active .mf-badge { color: var(--wwo-lavender-lighter); border-color: var(--wwo-lavender-lighter); }
#wwo-mosaic #wwo-fs .tile.mf-no-hover:hover .mf-badge { color: var(--cream) !important; }
#wwo-mslider .mf-mbadge:hover, #wwo-mslider .mf-mbadge:active, #wwo-mslider .mf-mbadge:focus-visible { color: var(--wwo-lavender-lighter); border-color: var(--wwo-lavender-lighter); }
#wwo-mslider .mf-mbadge:focus-visible { outline-color: var(--wwo-lavender-lighter); }


/* ── b29 (2026-09-23, Theresa #pbl-website-dark) ─────────────────────────────────────────────────────────────────
   P3-8 FIG. 03 still: the in-image headline sits at the left edge; object-fit: cover (3:2 frame on a 1200×671 still) cropped it.
   Left-anchor that ONE still (desktop filmstrip tile, mobile mosaic source tile, mobile slider slide). Other stills untouched. */
#wfs-track .tile.wfs-slide[data-proj="3"] img:not(.full), #wm-grid .tile[data-proj="3"] img:not(.full), #wwo-mslider .mslide[data-proj="3"] .mimg img { object-position: left center; }

/* P3-4 WebKit: filmstrip tiles are role=button but #wwo-fs .tile has outline:none -> keyboard users got no focus indicator in Safari.
   Same ring as the site's a/button rule (2px solid var(--magenta)). Drawn as an inset ::before ring (z 6, above the .tags/.mf-lane overlays at z 3-5)
   because the tile is the slick slide itself (.slick-list overflow:hidden clips an outside outline) and its own outline paints under those overlays.
   :focus-visible only -> never on mouse/touch; the tile's ::before was unused (content:none). */
#wwo-fs .tile.wfs-slide[role="button"]:focus-visible::before { content: ''; position: absolute; inset: 3px; border: 2px solid var(--magenta, #C10644); z-index: 6; pointer-events: none; }

/* P3-2 prefers-reduced-motion: index.html already carries the global near-zero-duration block (@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms ... } },
   ~line 4438) — the 2026-09-23 QA count of "36 running" was the harness reading 0.00001s as "not 0s". The one real gap was the JS grain canvas rAF loop, fixed in index.html (b29). Nothing to add here. */

/* ── b30 (2026-09-23, Theresa #pbl-website-dark 12:43 — four popup cosmetics, greenlit) ─────────────────────────────────────────────
   (a) Tablet PORTRAIT (700–768 wide, orientation portrait, ≥501 tall — iPad Mini 768×1024): the b21 32dvh viewer cap pillarboxed the 16:9 video
       (742×417 needed, 328 allowed → dark side bars). Raise the cap to 42dvh for that band only, so the video fills the card width edge to edge;
       the copy region below shrinks and scrolls. Phones (≤699) keep 32dvh; desktop untouched. */
@media (min-width: 700px) and (max-width: 768px) and (min-height: 501px) and (orientation: portrait) {
  .mf-modal.mf-sheet .mf-modal-img { height: min(calc((100vw - 26px) * 9 / 16), 42dvh); }
}
/* (b) "more below" cue for the pinned-media portrait sheet: the copy region (.mf-modal-copy) is the scroller, so a sticky ::after gradient
       (height 34, margin-top −34 → zero layout change, pointer-events none) fades the bottom edge while content remains below.
       JS toggles .mf-copy-more on scroll/resize/open; the class is absent when scrolled to the bottom or when nothing overflows. */
@media (max-width: 768px) and (min-height: 501px) {
  .mf-modal.mf-sheet .mf-modal-copy::after { content: ''; display: block; position: sticky; bottom: 0; height: 34px; margin-top: -34px; pointer-events: none; background: linear-gradient(to bottom, rgba(16,16,24,0), #101018 90%); opacity: 0; transition: opacity .2s ease; }
  .mf-modal.mf-sheet .mf-modal-copy.mf-copy-more::after { opacity: 1; }
  @media (prefers-reduced-motion: reduce) { .mf-modal.mf-sheet .mf-modal-copy::after { transition: none; } }
}
/* (c) ‹ › viewer discs: rgba(10,10,15,.55) + cream .35 hairline read too faint on bright stills (FIG 03 / Table Is the Menu). Neutral black .45 fill +
       white .35 hairline; size, position, glyph, hover/focus states unchanged. */
.mf-viewer-arrow { background: rgba(0,0,0,0.45); border-color: rgba(255,255,255,0.35); }
/* (d) thumb-row gutter: portrait used 14px (b21), landscape 12px (b13) — unify to 12px. */
@media (max-width: 768px) and (min-height: 501px) {
  .mf-modal.mf-sheet .mf-thumbs { padding: 8px 12px 10px; }
}
