    /* =====================
       CSS VARIABLES
    ======================== */
    :root {
      --bg:              #080808;
      --surface:         #0E0E0D;
      --border:          #1E1E1B;
      --text-primary:    #E8E4DC;
      --text-secondary:  #9E9A94;
      --text-muted:      #7E7B77;
      --accent:          #9B7EFF;
      --ice:             #9FD7FF;
      --ice-meta:        #6FBFFF;
      --teal:            #46C6C0;
      --text-body-bright: #D9D5CD;   /* slightly brighter body copy — used on cs-outcome, about-body, exp-desc */
    }

    /* =====================
       RESET & BASE
    ======================== */
    *, *::before, *::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    html { scroll-behavior: smooth; }

    body {
      background: var(--bg);
      color: var(--text-primary);
      font-family: 'DM Sans', sans-serif;
      overflow-x: hidden;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
    }

    a { text-decoration: none; color: inherit; }

    /* =====================
       GRAIN OVERLAY
    ======================== */
    body::before {
      content: '';
      position: fixed;
      inset: 0;
      z-index: 1000;
      pointer-events: none;
      background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.04'/%3E%3C/svg%3E");
      opacity: 0.35;
    }

    /* =====================
       CUSTOM CURSOR
       Hidden by default (touch/coarse-pointer); only shown on devices with
       a real mouse/trackpad (hover + fine pointer).
    ======================== */
    .cursor,
    .cursor-ring {
      display: none;
      pointer-events: none;
    }

    @media (hover: hover) and (pointer: fine) {
      body { cursor: none; }

      .cursor {
        display: block;
        position: fixed;
        width: 8px;
        height: 8px;
        background: var(--accent);
        border-radius: 50%;
        pointer-events: none;
        z-index: 9999;
        transform: translate(-50%, -50%);
        will-change: left, top;
        transition: width 0.2s ease, height 0.2s ease;
      }

      .cursor-ring {
        display: block;
        position: fixed;
        width: 34px;
        height: 34px;
        border: 1px solid rgba(155, 126, 255, 0.35);
        border-radius: 50%;
        pointer-events: none;
        z-index: 9998;
        transform: translate(-50%, -50%);
        will-change: left, top;
        transition: width 0.3s ease, height 0.3s ease;
      }

      body.cursor-hover .cursor { width: 14px; height: 14px; }
      body.cursor-hover .cursor-ring { width: 60px; height: 60px; }
    }

    /* =====================
       ACCESSIBILITY UTILITIES
       Skip link, screen-reader-only text, and a zero-box <h1> wrapper
       (display:contents) so the new heading adds no visual layout of its own.
    ======================== */
    .skip-link {
      position: fixed;
      top: -60px;
      left: 12px;
      z-index: 9999;
      background: var(--accent);
      color: #080808;
      font-family: 'DM Sans', sans-serif;
      font-size: 13px;
      font-weight: 600;
      letter-spacing: 0.03em;
      padding: 12px 18px;
      border-radius: 4px;
      text-decoration: none;
      transition: top 0.2s ease;
    }
    .skip-link:focus {
      top: 12px;
      outline: 2px solid #080808;
      outline-offset: 2px;
    }

    .sr-only {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
      border: 0;
    }

    .hero-id { display: contents; }

    /* =====================
       NAVIGATION
    ======================== */
    nav {
      position: fixed;
      inset: 0 0 auto 0;
      z-index: 500;
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 30px 52px;
      transition: padding 0.35s ease, background 0.35s ease, border-color 0.35s ease;
      border-bottom: 1px solid transparent;
    }

    nav.scrolled {
      padding: 20px 52px;
      background: rgba(8, 8, 8, 0.96);
      backdrop-filter: blur(16px);
      -webkit-backdrop-filter: blur(16px);
      border-bottom-color: var(--border);
    }

    .nav-logo {
      font-family: 'Bebas Neue', sans-serif;
      font-size: 26px;
      font-weight: 400;
      letter-spacing: 0.12em;
      color: var(--accent);
      line-height: 1;
    }

    .nav-links {
      display: flex;
      gap: 44px;
      list-style: none;
      margin-left: auto;
    }

    .nav-links a {
      font-family: 'DM Sans', sans-serif;
      font-size: 12px;
      font-weight: 500;
      letter-spacing: 0.1em;
      text-transform: uppercase;
      color: var(--text-primary);
      transition: color 0.2s ease;
      position: relative;
    }

    .nav-links a::after {
      content: '';
      position: absolute;
      bottom: -3px;
      left: 0;
      width: 0;
      height: 1px;
      background: var(--accent);
      transition: width 0.25s ease;
    }

    .nav-links a:hover { color: var(--accent); }
    .nav-links a:hover::after { width: 100%; }

    /* =====================
       HERO SECTION
    ======================== */
    .hero {
      min-height: 0;                 /* content-led — no full-viewport reservation that creates voids */
      display: flex;
      flex-direction: column;
      justify-content: flex-start;   /* stack from top; padding positions the content, not flex-end voids */
      padding: clamp(168px, 16vh, 200px) 52px clamp(64px, 7vh, 96px);
      position: relative;
      overflow: hidden;
    }

    /* Subtle radial glow behind the text */
    .hero::after {
      content: '';
      position: absolute;
      bottom: -10%;
      left: -5%;
      width: 60%;
      height: 80%;
      background: radial-gradient(ellipse, rgba(155,126,255,0.04) 0%, transparent 70%);
      pointer-events: none;
    }

    .hero-badge {
      position: absolute;
      top: clamp(84px, 10vh, 116px);
      left: 52px;
      display: flex;
      align-items: center;
      gap: 10px;
      font-family: 'DM Sans', sans-serif;
      font-size: 11px;
      letter-spacing: 0.1em;
      text-transform: uppercase;
      color: var(--text-primary);
      opacity: 0;
      animation: fadeUp 0.5s ease 0.2s forwards;
    }

    .badge-dot {
      width: 6px;
      height: 6px;
      background: var(--teal);
      border-radius: 50%;
      flex-shrink: 0;
      animation: pulse 2.8s ease infinite;
    }

    @keyframes pulse {
      0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(70,198,192,0.4); }
      50%       { opacity: 0.5; box-shadow: 0 0 0 6px rgba(70,198,192,0); }
    }

    /* Name + title block */
    .hero-content { position: relative; z-index: 1; }

    .hero-name {
      display: inline-flex;
      align-items: center;
      gap: 12px;
      font-family: 'IBM Plex Mono', monospace;
      font-size: 12px;
      font-weight: 500;
      color: var(--text-primary);
      letter-spacing: 0.26em;
      text-transform: uppercase;
      margin-bottom: 22px;
      opacity: 0;
      animation: fadeUp 0.6s ease 0.3s forwards;
    }
    .hero-name::before {
      content: '';
      width: 24px;
      height: 1px;
      background: var(--accent);
      flex-shrink: 0;
    }

    .hero-display {
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(78px, 11.5vw, 188px);
      line-height: 0.86;
      letter-spacing: 0.01em;
      color: var(--text-primary);
      display: block;
    }

    .hero-display .line-designer {
      position: relative;
      display: inline-block;
    }

    .hero-display .line-designer::after {
      content: '';
      position: absolute;
      bottom: 6px;
      left: 0;
      width: 0;
      height: 3px;
      background: var(--accent);
      animation: growLine 0.55s cubic-bezier(0.4,0,0.2,1) 1.1s forwards;
    }

    @keyframes growLine {
      to { width: 100%; }
    }

    .hero-dot { color: var(--accent); }          /* purple full stop */
    .hero-dot-white { color: var(--text-primary); }  /* white full stop */
    .hero-w-ice { color: var(--ice); }
    .hero-w-purple { color: var(--accent); }

    /* Supporting positioning line */
    .hero-lead {
      font-family: 'DM Sans', sans-serif;
      font-size: clamp(16px, 1rem + 0.45vw, 20px);
      font-weight: 300;
      line-height: 1.6;
      color: var(--text-body-bright);
      max-width: 56ch;
      margin-top: clamp(22px, 3vw, 32px);
      opacity: 0;
      animation: fadeUp 0.6s ease 0.55s forwards;
    }

    /* Meta row */
    .hero-meta {
      display: flex;
      align-items: flex-end;
      gap: 0;
      margin-top: 52px;
      padding-top: 28px;
      border-top: 1px solid var(--border);
      opacity: 0;
      animation: fadeUp 0.6s ease 0.65s forwards;
    }

    .meta-block {
      flex: 0 0 auto;
      padding-right: 40px;
      border-right: 1px solid var(--border);
      margin-right: 40px;
    }

    .meta-block:last-of-type {
      border-right: none;
      margin-right: 0;
    }

    .meta-label {
      display: block;
      font-family: 'IBM Plex Mono', monospace;
      font-size: 9px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--text-secondary);
      margin-bottom: 7px;
    }

    .meta-value {
      display: block;
      font-family: 'DM Sans', sans-serif;
      font-size: 13px;
      font-weight: 400;
      color: var(--text-primary);
      letter-spacing: 0.01em;
      white-space: nowrap;
    }

    .meta-scroll {
      display: flex;
      align-items: center;
      gap: 14px;
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.14em;
      text-transform: uppercase;
      color: var(--text-secondary);
      margin-left: auto;
      flex-shrink: 0;
    }

    .scroll-bar {
      width: 44px;
      height: 1px;
      background: var(--border);
      position: relative;
      overflow: hidden;
    }

    .scroll-bar::after {
      content: '';
      position: absolute;
      inset: 0;
      background: var(--accent);
      transform: translateX(-100%);
      animation: scanBar 2.2s ease 1.4s infinite;
    }

    @keyframes scanBar {
      0%   { transform: translateX(-100%); }
      45%  { transform: translateX(0%); }
      55%  { transform: translateX(0%); }
      100% { transform: translateX(100%); }
    }

    @keyframes fadeUp {
      from { opacity: 0; transform: translateY(18px); }
      to   { opacity: 1; transform: translateY(0); }
    }

    /* =====================
       MARQUEE STRIP
    ======================== */
    .marquee-strip {
      border-top: 1px solid var(--border);
      border-bottom: 1px solid var(--border);
      padding: 13px 0;
      overflow: hidden;
      white-space: nowrap;
      position: relative;
      z-index: 2;
    }

    .marquee-track {
      display: inline-flex;
      align-items: center;
      animation: marqueeScroll 90s linear infinite;
    }

    /* logo marquee — grey SVG brand/client/platform logos, used as-is (no recolouring).
       Normalised by optical height only; width is intrinsic per logo (wide logos stay
       wider, narrow logos stay narrower) — quiet/editorial, not a uniform sponsor grid.
       Each logo sits inside a fixed-height, flex-centred wrap so visual marks line up
       even when source SVGs have different internal viewBox padding/whitespace. */
    .brand-logo-wrap {
      height: 28px;
      margin: 0 30px;
      flex-shrink: 0;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .brand-logo {
      height: 18px;
      width: auto;
      object-fit: contain;
      display: block;
    }

    /* Per-logo optical size adjustments — small artwork or thin marks read smaller
       than neighbours at the shared 18px height, so these nudge a few logos up while
       leaving the base .brand-logo rule (and every logo not listed here) untouched. */
    .brand-logo--subtle  { height: 20px; }   /* MangaHigh, Bupa, Freely, Virgin Media */
    .brand-logo--strong  { height: 22px; }   /* Royal London Group */
    .brand-logo--latus   { height: 19px; }   /* Latus Health — very slight nudge only */
    .brand-logo--asos    { height: 16px; }   /* ASOS reads larger than neighbours at default height */

    @keyframes marqueeScroll {
      from { transform: translateX(0); }
      to   { transform: translateX(-50%); }
    }

    /* Pinned in-strip label — sits above the scrolling track via z-index;
       aria-hidden so screen readers use the sr-only paragraph instead.
       Easy to revert: remove this rule + the .marquee-label HTML span. */
    .marquee-label {
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      z-index: 3;
      display: flex;
      align-items: center;
      padding: 0 72px 0 52px;   /* right padding pushes logos clear of the label text */
      font-family: 'IBM Plex Mono', monospace;
      font-size: 9px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--text-muted);
      white-space: nowrap;
      /* left-to-right fade masks logos scrolling under/past the label */
      background: linear-gradient(
        to right,
        var(--bg) 0%,
        var(--bg) 80%,
        transparent 100%
      );
    }

    /* =====================
       BACK TO TOP BUTTON
    ======================== */
    .back-to-top {
      position: fixed;
      bottom: 36px;
      right: 36px;
      z-index: 200;
      width: 44px;
      height: 44px;
      background: var(--surface);
      border: 1px solid var(--border);
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 18px;
      color: var(--text-secondary);
      text-decoration: none;
      opacity: 0;
      transform: translateY(12px);
      transition: opacity 0.3s ease, transform 0.3s ease, border-color 0.2s, color 0.2s;
      pointer-events: none;
    }

    .back-to-top.visible {
      opacity: 1;
      transform: translateY(0);
      pointer-events: auto;
    }

    .back-to-top:hover {
      border-color: var(--accent);
      color: var(--accent);
    }

    /* =====================
       WORK SECTION
    ======================== */
    .section-work {
      padding: 100px 52px 0;
    }

    /* Tier 1 section heading — benchmark from the testimonials title */
    /* shared heavy heading treatment — Testimonials is the source of truth */
    .tcar-title,
    .section-title,
    .about-headline,
    .exp-headline,
    .contact-headline,
    .hero-display {
      font-family: 'Bebas Neue', sans-serif;
      font-weight: 400;
      letter-spacing: 0.01em;
      -webkit-font-smoothing: auto;       /* keep full stroke density (not thinned) */
      -moz-osx-font-smoothing: auto;
      text-rendering: optimizeLegibility;
      /* add genuine stroke weight to single-weight Bebas; paint-order keeps it crisp */
      -webkit-text-stroke: 1px currentColor;
      paint-order: stroke fill;
    }

    .section-title {
      font-size: clamp(52px, 8vw, 120px);
      line-height: 0.86;
      color: var(--text-primary);
    }
    .section-title .hl { color: var(--accent); }

    .work-header {
      padding-bottom: clamp(28px, 4vw, 44px);
      margin-bottom: clamp(28px, 4vw, 48px);
    }

    /* Case Study Card */
    .cs-card {
      display: grid;
      grid-template-columns: 0.62fr 1.38fr;
      min-height: 560px;
      border: 1px solid var(--border);
      margin-bottom: 3px;
      position: relative;
      overflow: hidden;
      transition: border-color 0.3s ease;

      /* Scroll reveal start state */
      opacity: 0;
      transform: translateY(28px);
    }

    .cs-card.revealed {
      opacity: 1;
      transform: translateY(0);
      transition: border-color 0.3s ease, opacity 0.65s ease, transform 0.65s ease;
    }

    .cs-card:hover { border-color: rgba(232, 228, 220, 0.2); }

    /* Left text panel */
    .cs-left {
      padding: 48px 52px;
      display: flex;
      flex-direction: column;
      justify-content: flex-start;   /* desktop: top-align content against the media column
                                         instead of spreading it across the full card height —
                                         reads cleaner now the visual panel holds a real image */
      gap: clamp(28px, 4vw, 44px);   /* preserves generous, editorial spacing without relying
                                         on space-between's auto-distributed gap */
      background: var(--surface);
      border-right: 1px solid var(--border);
      position: relative;
    }

    .cs-num {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 11px;
      letter-spacing: 0.1em;
      color: var(--text-primary);
      font-weight: 500;
    }

    .cs-body { padding: 36px 0; }

    .cs-company {
      display: block;
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--ice-meta);
      margin-bottom: 18px;
    }

    .cs-title {
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(40px, 4.5vw, 68px);
      line-height: 0.9;
      color: var(--text-primary);
      margin-bottom: 22px;
      letter-spacing: 0.01em;
    }

    /* Default: second word of the title sits on its own line, matching the old <br> behaviour.
       Tablet overrides this to inline so the title fits on one line without truncation. */
    .cs-title .cs-title-b { display: block; }

    .cs-outcome {
      font-family: 'DM Sans', sans-serif;
      font-size: 16.5px;
      font-weight: 300;
      line-height: 1.62;
      color: var(--text-body-bright);
      max-width: 380px;
    }


    /* Right visual panel */
    .cs-visual {
      position: relative;
      overflow: hidden;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .cs-visual-bg {
      position: absolute;
      inset: 0;
    }

    .visual-asos .cs-visual-bg {
      background: radial-gradient(ellipse at 65% 35%, rgba(255,100,0,0.08) 0%, var(--bg) 65%);
    }

    .visual-topshop .cs-visual-bg {
      background: radial-gradient(ellipse at 35% 65%, rgba(180,0,255,0.07) 0%, var(--bg) 65%);
    }

    .visual-itvx .cs-visual-bg {
      background: radial-gradient(ellipse at 60% 40%, rgba(0,200,190,0.07) 0%, var(--bg) 65%);
    }

    .visual-copy-companion .cs-visual-bg {
      background: radial-gradient(ellipse at 40% 60%, rgba(155,126,255,0.05) 0%, var(--bg) 65%);
    }

    /* Dot grid pattern */
    .cs-visual::before {
      content: '';
      position: absolute;
      inset: 0;
      background-image: radial-gradient(circle, rgba(255,255,255,0.06) 1px, transparent 1px);
      background-size: 28px 28px;
      z-index: 1;
    }

    /* ASOS hero video — 16:9 frame sitting in the card's themed panel */
    .visual-asos .cs-visual { padding: clamp(16px, 2vw, 28px); }
    .cs-video {
      position: relative;
      z-index: 2;
      width: 100%;
      max-height: 100%;
      aspect-ratio: 16 / 9;     /* stable frame — never collapses */
      object-fit: cover;
      display: block;
      background: #000;
      border: 1px solid var(--border);
      border-radius: 2px;
    }

    /* Topshop/Topman and ITVX real project images — sit in the same padded,
       themed panel as the ASOS video. object-fit: contain (not cover) keeps the
       full screenshot visible with no cropping, since these are UI screenshots
       where every part of the image carries meaning. */
    .visual-topshop .cs-visual,
    .visual-itvx .cs-visual,
    .visual-copy-companion .cs-visual {
      padding: clamp(16px, 2vw, 28px);
    }
    /* Static image media wrappers ([data-viewable]) — in-flow (not absolutely
       positioned) so the image inside them drives the panel height naturally. The
       panel expands to hug the rendered image, eliminating fixed-height empty space.
       ASOS video is not wrapped in .cs-media so this rule never affects it.
       Mobile overrides this per-card where needed (CC already done; TSTM/ITVX mobile
       rules in the mobile @media block below). */
    .visual-topshop .cs-media,
    .visual-itvx .cs-media {
      position: relative;
      width: 100%;
      height: auto;
      display: block;
    }
    .cs-image {
      position: relative;
      z-index: 2;
      width: 100%;
      height: auto;          /* let the image's natural aspect ratio drive height rather than
                                stretching/shrinking to fill a fixed panel — the panel adapts instead */
      max-width: 100%;
      max-height: 100%;
      object-fit: contain;
      display: block;
      border: 1px solid var(--border);
      border-radius: 2px;
    }
    /* The media wrapper fills the panel's content box (inside the panel's existing
       padding), so the wrapped image keeps exactly the same framing/size it had —
       no resize or reframe for TSTM/ITVX/Copy Companion. The shared vx-* viewer
       (script.js + [data-viewable] CSS) injects the trigger button and modal. */


    /* =====================
       ABOUT SECTION
    ======================== */
    .section-about {
      padding: 120px 52px 156px;
      border-top: 1px solid var(--border);
      margin-top: 80px;
    }

    .about-grid {
      display: grid;
      grid-template-columns: 1fr;
      gap: clamp(28px, 4vw, 64px);
      align-items: start;
    }
    @media (min-width: 880px) {
      .about-grid { grid-template-columns: 1.1fr 0.9fr; column-gap: clamp(48px, 5vw, 88px); }
    }

    /* copy sits in two readable columns beneath the full-width heading */
    .about-copy { display: flex; flex-direction: column; gap: clamp(20px, 2.5vw, 28px); }
    .about-copy .about-body { max-width: 60ch; }


    .section-eyebrow {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--text-secondary);
    }

    .about-headline {
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(52px, 8vw, 120px);
      font-weight: 400;
      line-height: 0.86;
      letter-spacing: 0.01em;
      color: var(--text-primary);
      margin-bottom: clamp(24px, 3vw, 36px);
    }

    .about-headline .hl { color: var(--accent); }

    .about-body {
      font-family: 'DM Sans', sans-serif;
      font-size: clamp(15px, 1.4vw, 17px);
      font-weight: 300;
      line-height: 1.75;
      color: var(--text-body-bright);
      max-width: 56ch;
      margin-bottom: 0;
    }


    /* =====================
       WHERE I'VE WORKED (Experience)
       Editorial work-history snapshot — sits between About and Testimonials.
       .exp-headline shares the Tier-1 major-heading treatment (see line ~516);
       .exp-desc matches .about-body's size/line-height/colour. New .exp-* classes
       cover the repeating entry layout, which has no existing equivalent.
    ======================== */
    .section-experience {
      padding: 100px 52px 120px;
      border-top: 1px solid var(--border);
    }

    .exp-head { margin-bottom: clamp(36px, 5vw, 56px); }

    .exp-headline {
      font-size: clamp(52px, 8vw, 120px);
      line-height: 0.86;
      color: var(--text-primary);
    }
    .exp-headline .hl { color: var(--accent); }

    .exp-list {
      display: flex;
      flex-direction: column;
    }

    .exp-entry {
      display: grid;
      grid-template-columns: 0.72fr 1.28fr;
      gap: clamp(20px, 2.4vw, 32px);
      padding: clamp(28px, 3.4vw, 38px) 0;
      border-top: 1px solid var(--border);
    }

    .exp-meta { padding-top: 2px; }

    /* Accordion trigger: above mobile this renders as plain, unstyled content —
       identical to the original static .exp-meta wrapper. Mobile-only accordion
       visuals/affordance are added inside the 767px query below. */
    .exp-trigger {
      display: block;
      width: 100%;
      background: none;
      border: none;
      padding: 0;
      margin: 0;
      font: inherit;
      color: inherit;
      text-align: left;
      cursor: default;
    }
    .exp-toggle { display: none; }

    .exp-company {
      display: block;
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(24px, 2.2vw, 32px);
      letter-spacing: 0.01em;
      color: var(--text-primary);
      line-height: 1.1;
      margin-bottom: 8px;
    }

    .exp-role {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.14em;
      text-transform: uppercase;
      color: var(--ice-meta);
    }

    .exp-years {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.14em;
      text-transform: uppercase;
      color: var(--text-secondary);
    }

    .exp-sep { color: var(--text-muted); margin: 0 2px; }

    .exp-desc {
      font-family: 'DM Sans', sans-serif;
      font-size: clamp(15px, 1.4vw, 17px);
      font-weight: 300;
      line-height: 1.75;
      color: var(--text-body-bright);
      max-width: 62ch;
    }

    /* =====================
       TESTIMONIAL
    ======================== */
    .section-testimonial {
      padding: 80px 52px 100px;
      border-top: 1px solid var(--border);
    }

    .author-name {
      display: block;
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--text-primary);
      margin-bottom: 6px;
    }

    .author-role {
      display: block;
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.1em;
      text-transform: uppercase;
      color: var(--text-secondary);
    }

    /* ---- Testimonials carousel (dot-driven, peeking side cards) ---- */
    .tcar { margin: 0 auto; }
    .tcar-head { text-align: center; margin-bottom: clamp(44px, 6vw, 84px); }
    .tcar-title {
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(52px, 8vw, 120px);
      line-height: 0.86;
      letter-spacing: 0.01em;
      color: var(--text-primary);
    }
    .tcar-title .hl { color: var(--accent); }

    /* full-bleed viewport — transform-driven continuous testimonial track */
    .tcar-viewport {
      position: relative;
      left: 50%;
      width: 100vw;
      margin-left: -50vw;
      overflow: hidden;
      touch-action: pan-y;
    }

    .tcar-track {
      display: flex;
      gap: 20px;
      padding: 6px 0 18px;
      will-change: transform;
    }

    /* Drag affordance: only on devices with a real mouse/trackpad (hover + fine pointer).
       Touch/coarse-pointer devices (mobile, most tablets) get no grab cursor — tap/swipe only. */
    @media (hover: hover) and (pointer: fine) {
      .tcar-viewport { cursor: grab; }
      .tcar-viewport:active { cursor: grabbing; }
    }

    .tcard {
      flex: 0 0 min(86%, 440px);            /* mobile: one card + peek */
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: 18px;
      padding: clamp(26px, 3.5vw, 40px);
      display: flex;
      flex-direction: column;
    }
    .tcard-quote {
      font-family: 'DM Sans', sans-serif;
      font-size: clamp(15px, 1.25vw, 17px);
      font-weight: 300;
      line-height: 1.7;
      color: var(--text-body-bright);
      margin: 0 0 24px;
    }
    .tcard-foot { margin-top: auto; padding-top: 18px; border-top: 1px solid var(--border); }

    /* indicator dots — functional, editorial, not a generic slider */
    .tcar-dots {
      display: flex;
      justify-content: center;
      gap: 0;   /* 44px buttons are self-spacing — no extra gap needed; dot centres
                   are 44px apart which keeps hit areas flush but non-overlapping */
      margin-top: clamp(28px, 4vw, 44px);
    }
    .tcar-dot {
      /* Hit area: 44×44px transparent button — meets WCAG 2.5.8 touch target size.
         display:grid + place-items:center keeps the visible ::before dot perfectly
         centred regardless of surrounding spacing. */
      position: relative;
      width: 44px;
      height: 44px;
      padding: 0;
      border: none;
      border-radius: 0;
      background: transparent;
      cursor: pointer;
      display: grid;
      place-items: center;
      transition: none;    /* transitions belong on ::before, not the button */
    }
    /* Visible indicator — horizontal line centred inside the 44px hit area via grid centering above */
    .tcar-dot::before {
      content: '';
      width: 36px;
      height: 2px;
      border-radius: 999px;
      background: var(--text-muted);
      transition: background 0.25s ease, width 0.25s ease, height 0.25s ease;
      display: block;
    }
    .tcar-dot:hover::before { background: var(--text-secondary); }
    .tcar-dot.is-active::before {
      background: var(--accent);
      width: 43px;
      height: 3px;
    }
    .tcar-dot:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 2px;
      border-radius: 4px;
    }

    /* desktop: narrower, taller-feeling quote cards — more of them visible at once
       rather than a couple of wide flat strips. Still leaves a partial neighbour
       in view (peek), same as the tablet/mobile treatment. */
    @media (min-width: 1025px) {
      .tcard { flex: 0 0 min(30%, 380px); }
    }

    /* Reduced motion: contact/footer reveal animations disabled; carousel drift is handled in JS */
    @media (prefers-reduced-motion: reduce) {
      .contact-headline.reveal .cw-line { opacity: 1; animation: none; }
      .contact-links { opacity: 1; transform: none; animation: none; }
      .contact-aside { opacity: 1; transform: none; animation: none; }
    }

    /* =====================
       CONTACT SECTION
    ======================== */
    .section-contact {
      padding: 80px 52px 90px;
      border-top: 1px solid var(--border);
    }

    .contact-headline {
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(64px, 10vw, 150px);
      line-height: 0.87;
      color: var(--text-primary);
      margin-bottom: 32px;
    }

    /* restore confident density to the contact/footer title.
       Bebas Neue is single-weight, so visual thickness comes from smoothing plus a
       hairline same-colour stroke. currentColor keeps CONNECT off-white, COLLAB ice,
       CHAT purple and the full stops white. Placed after the shared heading rule so
       it overrides the thinner treatment without altering the other headings. */
    .contact-headline {
      -webkit-font-smoothing: subpixel-antialiased;
      -moz-osx-font-smoothing: auto;
      -webkit-text-stroke: 1.35px currentColor;  /* benchmark — thickest, most confident */
      paint-order: stroke fill;
      margin-left: -0.02em;   /* optical: align Bebas glyph edge to the links/copyright */
    }

    .contact-headline .cw-line { display: block; opacity: 0; }

    /* clean, staggered snap-up (restrained ease-out, no overshoot); ~1.73s whole sequence */
    .contact-headline.reveal .cw-line {
      opacity: 0;
      transform: translateY(34px);
      animation: snapUp 0.45s cubic-bezier(0.22, 1, 0.36, 1) forwards;
      animation-delay: var(--d, 0s);
    }

    @keyframes snapUp {
      0%   { opacity: 0; transform: translateY(34px); }
      45%  { opacity: 1; }
      100% { opacity: 1; transform: translateY(0); }
    }

    .contact-links {
      display: flex;
      gap: 40px;
      flex-wrap: wrap;
      margin-bottom: 28px;   /* breathing room before the closing line of copy */
      opacity: 0;
      transform: translateY(14px);
    }

    /* Links and the supporting line arrive together as one group, right after
       CHAT lands — not a slow one-by-one cascade. */
    .contact-links.reveal {
      animation: copyFadeUp 0.3s ease forwards;
      animation-delay: 1.73s;
    }

    .contact-link {
      display: inline-flex;
      align-items: center;
      gap: 9px;
      font-family: 'DM Sans', sans-serif;
      font-size: 12px;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      color: var(--text-primary);
      transition: color 0.2s;
    }

    .contact-link svg {
      width: 16px;
      height: 16px;
      color: var(--accent);
      flex-shrink: 0;
    }
    .contact-link svg.ico-li { width: 14px; height: 14px; }

    .contact-link:hover,
    .contact-link:focus-visible {
      color: var(--accent);
    }

    /* Quiet closing line beneath the links — no longer a competing right-side block */
    .contact-aside {
      max-width: 62ch;
      text-align: left;
      opacity: 0;
      transform: translateY(14px);
    }

    /* Copy lands together with the links — same group, same moment */
    .contact-aside.reveal {
      animation: copyFadeUp 0.3s ease forwards;
      animation-delay: 1.73s;
    }

    @keyframes copyFadeUp {
      from { opacity: 0; transform: translateY(14px); }
      to   { opacity: 1; transform: translateY(0); }
    }

    .contact-aside p {
      font-family: 'DM Sans', sans-serif;
      font-size: 15px;
      font-weight: 300;
      line-height: 1.6;
      color: var(--text-secondary);
    }

    /* =====================
       FOOTER
    ======================== */
    footer {
      padding: 26px 52px;
      border-top: 1px solid var(--border);
      display: flex;
      align-items: center;
      justify-content: flex-start;
    }

    .footer-copy {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--text-muted);
    }

    .footer-links {
      display: flex;
      gap: 26px;
    }

    .footer-links a {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.08em;
      color: var(--text-secondary);
      transition: color 0.2s;
    }

    .footer-links a:hover { color: var(--accent); }

    /* =====================
       CONTACT/FOOTER — LIGHT PROTOTYPE (reversible, scoped override)
       Warm off-white "page turn" closing moment. All declarations below are
       additive overrides on Contact/footer-only selectors — no shared/global
       rules (tokens, .hero-dot-white, .hero-w-ice, .hero-w-purple) are edited.
    ======================== */
    .section-contact {
      background: #F4F1EA;
      border-top-color: #DEDAD0;
    }

    .contact-headline { color: #161512; }                 /* CONNECT — warm near-black */
    .contact-headline .hero-w-ice { color: #2ABBFF; }      /* COLLAB — brighter blue, contact-scoped only */
    .contact-headline .hero-w-purple { color: #7C5CE8; }   /* CHAT — deepened purple, contact-scoped only */

    /* New contact-only full-stop class — keeps .hero-dot-white (used in hero) untouched */
    .contact-dot { color: #161512; }

    .contact-link { color: #161512; text-decoration: underline; text-underline-offset: 3px; text-decoration-color: rgba(22,21,18,0.35); }
    .contact-link svg { color: #7C5CE8; }
    .contact-link:hover,
    .contact-link:focus-visible {
      color: #7C5CE8;
      outline-color: #7C5CE8;
      text-decoration-color: #7C5CE8;
    }

    .contact-aside p { color: #5A564E; }

    footer {
      background: #F4F1EA;
      border-top-color: #DEDAD0;
    }
    .footer-copy { color: #6B6657; }

    /* "giggles" audio trigger — renders as plain footer text, no button chrome */
    .giggle-btn {
      background: none;
      border: none;
      padding: 0;
      margin: 0;
      font: inherit;
      color: inherit;
      letter-spacing: inherit;
      text-transform: inherit;
      cursor: pointer;
      display: inline;
    }
    .footer-links a { color: #5A564E; }
    .footer-links a:hover { color: #7C5CE8; }

    /* =====================
       HAMBURGER (mobile nav)
    ======================== */
    .nav-hamburger {
      display: none;
      flex-direction: column;
      gap: 5px;
      cursor: pointer;
      padding: 4px;
      background: none;
      border: none;
    }

    .nav-hamburger span {
      display: block;
      width: 22px;
      height: 1px;
      background: var(--text-primary);
      transition: transform 0.3s ease, opacity 0.3s ease;
    }

    .nav-hamburger.open span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
    .nav-hamburger.open span:nth-child(2) { opacity: 0; }
    .nav-hamburger.open span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

    .nav-hamburger:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 3px;
    }

    .nav-mobile-menu {
      display: none;
      position: fixed;
      inset: 0;
      z-index: 490;
      background: rgba(8,8,8,0.98);
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 40px;
    }

    .nav-mobile-menu.open { display: flex; }

    .nav-mobile-menu a {
      font-family: 'Bebas Neue', sans-serif;
      font-size: 52px;
      letter-spacing: 0.05em;
      color: var(--text-primary);
      text-decoration: none;
      transition: color 0.2s;
    }

    .nav-mobile-menu a:hover { color: var(--accent); }

    .nav-mobile-menu a:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 4px;
    }

    /* =====================
       RESPONSIVE — NARROW DESKTOP (1025–1440px)
       The base hero uses position:absolute for the badge + justify-content:flex-end
       which collapses at short viewport heights. This range converts the hero to a
       natural stacking layout: nav clearance → badge → title content → bottom padding.
       Height is content-led; no flex-end redistribution; overlap is structurally impossible.
    ======================== */
    @media (min-width: 1025px) and (max-width: 1440px) {
      .hero {
        min-height: 0;                  /* content-led height — no vh assumptions */
        justify-content: flex-start;   /* stack from top, no redistribution */
        padding-top: clamp(100px, 10vh, 130px);   /* clear fixed nav (~80px) + space for badge */
        padding-bottom: clamp(48px, 5vh, 64px);
      }
      .hero-badge {
        position: static;   /* in-flow: sits above hero-content in DOM order */
        left: auto;
        top: auto;
        margin-bottom: 72px;   /* tight but visible separation before the name line */
      }
      .hero-display {
        font-size: clamp(78px, 9.5vw, 148px);
      }
      .hero-meta {
        margin-top: 28px;   /* tighter than the base 52px — enough rhythm, no gap bloat */
        padding-top: 20px;
      }
    }

    /* =====================
       RESPONSIVE — WIDE DESKTOP (1441px+) — badge in-flow
       The base rule is the only place .hero-badge is still position:absolute, with a
       top offset (clamp(100px,12vh,132px)) decoupled from the content's padding-top.
       Mirror the in-flow pattern every other breakpoint already uses so the badge can
       never sit across the title. padding-top is trimmed to keep the same vertical
       rhythm (badge now occupies that top zone in flow) — no void, no downward shift.
    ======================== */
    @media (min-width: 1441px) {
      .hero { padding-top: clamp(120px, 13vh, 150px); }
      .hero-badge {
        position: static;   /* in-flow above hero-content — overlap structurally impossible */
        left: auto;
        top: auto;
        margin-bottom: clamp(36px, 3.5vh, 48px);
      }

      /* Wide-desktop content containment — keeps copy, cards and headings within a
         1600px reading/content band while all section backgrounds, border-top hairlines,
         nav glass and footer remain full viewport-width.
         Uses responsive padding instead of max-width so full-bleed elements (section
         backgrounds, marquee strip, tcar-viewport full-bleed trick) are unaffected.
         Formula: max(52px, (viewport − 1600px) / 2) — at exactly 1441px the calc resolves
         to a negative value which falls below the 52px floor, so the original gutter is preserved
         until the viewport is wide enough that the wider padding takes over (~1704px). */
      nav,
      nav.scrolled {
        padding-left:  max(52px, calc((100% - 1600px) / 2));
        padding-right: max(52px, calc((100% - 1600px) / 2));
      }
      .hero,
      .section-work,
      .section-about,
      .section-experience,
      .section-testimonial,
      .section-contact,
      .pd-section,
      footer {
        padding-left:  max(52px, calc((100% - 1600px) / 2));
        padding-right: max(52px, calc((100% - 1600px) / 2));
      }
      .marquee-label { padding-left: max(52px, calc((100% - 1600px) / 2)); }
      /* Project nav uses its own grid rather than .pd-section, so it needs
         explicit horizontal containment to match the case section column. */
      .pd-project-nav {
        padding-left:  max(52px, calc((100% - 1600px) / 2));
        padding-right: max(52px, calc((100% - 1600px) / 2));
      }
      /* Items already carry 52px horizontal padding at narrower viewports;
         zero it out here so the outer nav padding is the sole inset. */
      .pd-project-nav-item {
        padding-left:  0;
        padding-right: 0;
      }
    }

    /* =====================
       RESPONSIVE — TABLET
    ======================== */
    @media (max-width: 1024px) {
      nav, nav.scrolled { padding: 24px 36px; }

      .hero {
        padding: clamp(80px, 7vh, 100px) 36px 48px;   /* top clears nav; lower vh ceiling prevents
                                                          excess void on tall narrow viewports */
        min-height: 0;          /* content-led height — no vh assumption that could cause overlap */
        justify-content: flex-start;   /* stack from top, badge then content */
      }
      .hero-badge {
        position: static;   /* in-flow above hero-content — overlap structurally impossible */
        left: auto;
        top: auto;
        margin-bottom: 64px;
      }

      .hero-meta { gap: 0; flex-wrap: wrap; }
      .meta-block { padding-right: 28px; margin-right: 28px; }
      .hero-display { font-size: clamp(88px, 12vw, 140px); }   /* tablet landscape + portrait base; portrait-only override below */

      .marquee-strip { padding: 12px 0; }
      .marquee-label { padding-left: 36px; }

      .section-work { padding: 80px 36px 0; }

      .cs-card { min-height: 360px; grid-template-columns: 0.95fr 1.05fr; }
      .cs-left { padding: 36px 40px; }
      .cs-title { font-size: clamp(36px, 4vw, 56px); }

      .section-about { padding: 80px 36px; }
      .about-grid { grid-template-columns: 1fr; gap: 32px; }

      .section-experience { padding: 70px 36px 84px; }

      .section-testimonial { padding: 60px 36px 80px; }

      .section-contact { padding: 60px 36px 72px; }

      footer { padding: 20px 36px; }

      .back-to-top { bottom: 24px; right: 24px; }
    }

    /* =====================
       RESPONSIVE — TABLET PORTRAIT (hero polish only)
    ======================== */
    @media (min-width: 768px) and (max-width: 1024px) and (orientation: portrait) {
      .hero { padding-bottom: clamp(48px, 8vw, 80px); }   /* generous bottom — no vh min-height needed */
      .hero-display { font-size: clamp(96px, 14vw, 148px); }

      /* Experience: portrait tablet keeps the stacked single-column layout;
         landscape tablet stays on the two-column base rule above. */
      .exp-entry { grid-template-columns: 1fr; gap: 10px; }

      /* ITVX visual on portrait tablet — the zoom button is now in-flow so the image
         drives the panel height naturally; no fixed min-height needed. */

      /* Brow → title breathing room: the tablet block sets margin-bottom:0 on .cs-company
         because its grid rewrite controls spacing via grid rows, not margin. On portrait
         tablet that layout is still active but 0 margin reads too tight; 6px adds
         a clear visual separation without disrupting the stacked masthead rhythm. */
      .cs-card:not(.cs-mini) .cs-company { margin-bottom: 6px; }
      /* body copy parity — tablet portrait: match project description size */
      .about-body,
      .exp-desc { font-size: 16.5px; }
    }

    /* =====================
       RESPONSIVE — MOBILE
    ======================== */
    @media (max-width: 767px) {
      /* Nav */
      nav, nav.scrolled { padding: 20px 24px; }
      .nav-links { display: none; }
      .nav-hamburger { display: flex; }
      .marquee-label { display: none; }

      /* Hero */
      .hero {
        padding: clamp(96px, 16vh, 130px) 24px 48px;   /* explicit top clears fixed nav now base is flex-start */
        min-height: min(100svh, 780px);   /* cap prevents flex-end void growing on tall narrow desktop windows
                                             while still filling real phone screens (which are ≤780px tall) */
        justify-content: flex-end;   /* mobile keeps content low in the viewport (intended mobile feel) */
      }
      .hero-badge {
        position: static;
        margin-bottom: 60px;
        font-size: 10px;
      }

      /* Intro/meta line — controlled two-line wrap instead of an arbitrary mid-phrase break */
      .hero-name {
        position: relative;
        align-items: flex-start;
        padding-left: 18px;
        font-size: 10.5px;
        letter-spacing: 0.12em;
        line-height: 1.2;
        margin-bottom: 14px;
      }
      /* mobile-specific accent: a vertical rule beside the brow text,
         instead of the desktop horizontal line (which can't align cleanly against wrapped text) */
      .hero-name::before {
        content: '';
        position: absolute;
        left: 0;
        top: 2px;
        bottom: 2px;
        width: 2px;
        height: auto;
        background: var(--accent);
        flex-shrink: 0;
      }
      /* Mobile brow: hide · UK — name + role read cleanly without it at this scale */
      .hero-name-sep,
      .hero-name-loc { display: none; }

      .hero-display {
        font-size: clamp(72px, 18.5vw, 104px);
      }

      /* Supporting paragraph — lighter, tighter, reads as supporting copy not a second headline */
      .hero-lead {
        font-size: 15px;
        line-height: 1.55;
        margin-top: 16px;
      }

      /* Stats/details — compact two-up grid, pulled closer so it reads as part of the hero */
      .hero-meta {
        display: grid;
        grid-template-columns: 1fr 1fr;
        align-items: start;
        column-gap: 20px;
        row-gap: 14px;
        margin-top: 24px;
        padding-top: 16px;
      }
      .meta-block {
        border-right: none;
        border-bottom: 1px solid var(--border);
        padding-right: 0;
        padding-bottom: 14px;
        margin-right: 0;
      }
      .meta-block:nth-child(3) { grid-column: 1 / -1; }
      .meta-value { white-space: normal; }
      .meta-block:last-of-type { border-bottom: none; padding-bottom: 0; }

      /* Marquee */
      .brand-item { padding: 0 24px; }

      /* Work cards — single column */
      .section-work { padding: 60px 24px 0; }

      .cs-card {
        grid-template-columns: 1fr;
        min-height: auto;
      }

      .cs-left { padding: 32px 28px; border-right: none; border-bottom: 1px solid var(--border); }
      .cs-body { padding: 24px 0; }
      .cs-title { font-size: clamp(40px, 10vw, 60px); }
      .cs-outcome { font-size: 15px; max-width: 100%; }

      .cs-visual {
        min-height: 200px;    /* safe floor for ASOS video which needs container height */
        display: block;
        position: relative;
      }
      /* Static image panels (TSTM, ITVX, CC) — no forced min-height on mobile;
         image is width:100% height:auto so it fills the available width and scales
         proportionally. The panel's display:block + auto height lets the image
         define the container height naturally. */
      .visual-topshop .cs-visual,
      .visual-itvx .cs-visual,
      .visual-copy-companion .cs-visual {
        min-height: 0;
      }
      /* Keep the media wrapper in-flow on mobile so image height drives the
         container rather than collapsing to zero. */
      .visual-topshop .cs-media,
      .visual-itvx .cs-media,
      .visual-copy-companion .cs-media {
        position: relative;
        width: 100%;
        height: auto;
        display: block;
      }
      .cs-visual-bg { position: absolute; }

      /* About */
      .section-about {
        padding: 60px 24px;
        scroll-margin-top: 84px;   /* clears the fixed mobile nav (~66px) plus breathing room when scrolled to */
      }
      .about-grid {
        grid-template-columns: 1fr;
        gap: 28px;
      }
      .about-label-col { position: static; }
      .about-headline { font-size: clamp(42px, 12.5vw, 50px); }
      .about-body { font-size: 15px; }

      /* Selected Experience */
      .section-experience {
        padding: 56px 24px 64px;
        scroll-margin-top: 84px;
      }
      .exp-headline { font-size: clamp(42px, 12.5vw, 50px); }
      .exp-entry { grid-template-columns: 1fr; gap: 0; padding: 0; }
      .exp-desc { font-size: 15px; max-width: none; }

      /* Mobile-only accordion: trigger becomes an interactive control with a
         minimal +/− affordance; panel collapses via [hidden]. Restrained,
         editorial — no boxed/FAQ-style chrome, divider lines preserved. */
      .exp-trigger {
        display: flex;
        align-items: flex-start;
        justify-content: space-between;
        gap: 16px;
        cursor: pointer;
        padding: 24px 0;
      }
      .exp-trigger:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: 4px;
      }
      .exp-toggle {
        display: block;
        position: relative;
        flex-shrink: 0;
        width: 16px;
        height: 16px;
        margin-top: 6px;
      }
      .exp-toggle::before,
      .exp-toggle::after {
        content: '';
        position: absolute;
        top: 50%;
        left: 50%;
        background: var(--text-secondary);
        transition: transform 0.25s ease, background 0.2s ease;
      }
      .exp-toggle::before { width: 11px; height: 1px; transform: translate(-50%, -50%); }
      .exp-toggle::after  { width: 1px; height: 11px; transform: translate(-50%, -50%); }
      .exp-trigger[aria-expanded="true"] .exp-toggle::after { transform: translate(-50%, -50%) rotate(90deg); opacity: 0; }
      .exp-trigger[aria-expanded="true"] .exp-toggle::before,
      .exp-trigger[aria-expanded="true"] .exp-toggle::after { background: var(--accent); }

      .exp-desc { padding-bottom: 24px; }
      .exp-desc[hidden] { display: none; }

      /* Testimonial — one full card at a time, no peeking side cards */
      .section-testimonial { padding: 48px 24px 60px; }
      .tcard { flex: 0 0 min(calc(100vw - 40px), 360px); }

      /* Contact */
      .section-contact { padding: 48px 24px 60px; text-align: center; }
      .contact-aside-br { display: none; }
      .contact-headline {
        font-size: clamp(56px, 16vw, 102px);
        margin-bottom: 20px;
        margin-left: 0;
      }
      .contact-links { justify-content: center; }
      .contact-aside { text-align: center; max-width: 38ch; margin: 0 auto; }

      /* Footer */
      footer {
        flex-direction: column;
        gap: 16px;
        align-items: flex-start;
        padding: 20px 24px;
      }

      /* Back to top */
      .back-to-top { bottom: 20px; right: 20px; width: 40px; height: 40px; }
    }

    /* Mobile landscape — reduce oversized text/spacing that makes the stacked
       project cards feel uncomfortably large in landscape orientation.
       Only touches font scale and section padding — no structural changes. */
    /* =====================
       NARROW DESKTOP / BROWSER-WINDOW-AT-MOBILE-WIDTH
       Targets a real mouse/trackpad device (hover:hover + pointer:fine) whose window
       has been resized to ≤767px — a desktop browser, not a phone. On these devices
       the mobile-portrait flex-end + min-height combo produces a large void because
       the viewport is tall but the content doesn't fill it. Switch to top-aligned,
       content-led height so the hero reads like a tight desktop layout.
       Does NOT affect real phones (touch/coarse pointer — they don't match pointer:fine).
    ======================== */
    @media (max-width: 767px) and (hover: hover) and (pointer: fine) {
      .hero {
        min-height: auto;
        justify-content: flex-start;
        padding-top: 72px;   /* clears fixed nav + a breath of space */
      }
      /* Typography hierarchy: in portrait orientation on a narrow desktop window,
         the landscape block doesn't fire, so heading sizes fall back to base/portrait
         values where .cs-title (60px) exceeds .section-title (53px). Pin correct order. */
      .section-title,
      .about-headline,
      .exp-headline,
      .tcar-title { font-size: clamp(48px, 8vw, 64px); }
      .cs-title { font-size: clamp(28px, 6vw, 38px); }
    }


    /* ===================== PAGE LOADER — FAANG ======================== */
    #pageLoader {
      position: fixed; inset: 0; z-index: 9800;
      background: #080808;
      display: flex; align-items: center; justify-content: center;
      flex-direction: column; gap: 0;
      transition: opacity 0.5s ease 0.1s;
      pointer-events: all;
    }
    #pageLoader.hide { opacity: 0; pointer-events: none; }
    .pl-mono {
      font-family: 'Bebas Neue', sans-serif;
      font-size: 64px; letter-spacing: 0.18em;
      color: var(--accent); line-height: 1;
      opacity: 0; transform: translateY(8px);
      animation: plFadeUp 0.5s ease 0.15s forwards;
    }
    .pl-name {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 9px; letter-spacing: 0.22em;
      text-transform: uppercase; color: var(--text-muted);
      margin-top: 10px; margin-bottom: 28px;
      opacity: 0;
      animation: plFadeUp 0.4s ease 0.35s forwards;
    }
    .pl-track {
      width: 200px; height: 1px;
      background: var(--border); overflow: hidden;
      opacity: 0;
      animation: plFadeUp 0.4s ease 0.45s forwards;
    }
    .pl-bar {
      height: 100%; width: 0%;
      background: var(--accent);
      animation: plFill 1.3s cubic-bezier(0.4,0,0.2,1) 0.5s forwards;
    }
    @keyframes plFadeUp {
      from { opacity: 0; transform: translateY(6px); }
      to   { opacity: 1; transform: translateY(0); }
    }
    @keyframes plFill { from { width: 0%; } to { width: 100%; } }


    /* smaller supporting callout — reuses the card structure at reduced weight */
    /* "Also built" kicker — frames Copy Companion as secondary, sits above its divider line.
       More top margin reads as an intentional section break from the ITVX card above;
       --text-secondary (vs the previous --text-muted) keeps it subtle but legible. */
    .also-built-label {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--text-secondary);
      margin: clamp(48px, 5.5vw, 72px) 0 14px;
    }

    /* Copy Companion — full-width lighter editorial strip (not a boxed fourth card).
       Spans the same width as the main cards instead of a narrower max-width, removing
       the accidental empty void that previously sat to its right on desktop. The visual
       now takes a proportional ~45/55 share of the strip (not a fixed small column) and
       the strip has real height, so the prototype gets genuine presence — while staying
       well under the main cards' 560px so it still reads as secondary. */
    .cs-card.cs-mini {
      grid-template-columns: 450px 1fr;   /* fixed text column ~450px on desktop; visual takes rest */
      column-gap: clamp(28px, 3.5vw, 48px);
      min-height: 0;         /* image is in-flow (.cs-media wrapper is not absolute), so the image
                                drives height — no forced floor needed on the card */
      margin-top: 0;
      max-width: none;
      background: transparent;
      border: none;
      border-top: 1px solid var(--border);   /* connects it to the work wall as a strip */
      padding-top: clamp(20px, 2.4vw, 28px);
      align-items: start;    /* top-align both columns — image starts from the same point as text */
    }
    .cs-card.cs-mini .cs-num { display: none; }
    .cs-card.cs-mini .cs-left {
      padding: clamp(22px, 2.6vw, 30px) clamp(26px, 3vw, 38px);
      /* mirrors the main cards: space-between anchors proof points toward the bottom of the
         panel (using whatever real height the strip has) instead of sitting a fixed distance
         below the description. gap guarantees a minimum spacing for shorter containers
         (tablet, and mobile's content-sized stacked layout) where there's little/no extra
         height for space-between to distribute. */
      justify-content: space-between;
      gap: 26px;
      border-right: none;              /* lighter, no hard divider — editorial strip, not a boxed card */
    }
    /* Copy Companion — visual breakout: the image is already a composed, annotated
       artefact, so it doesn't need the main cards' padded+bordered "specimen frame".
       Reduce the panel padding and drop the inner border/radius so the image fills
       more of the panel and reads confidently, while the green/dotted background
       still frames it. Scoped to .cs-mini only — main cards keep their framing.
       The media wrapper is in-flow (not absolute) so the image drives panel height,
       eliminating fixed-height empty space on desktop and tablet landscape. */
    .cs-card.cs-mini .cs-visual { padding: clamp(4px, 0.5vw, 8px); border: 1px solid rgba(255,255,255,0.10); }
    .cs-card.cs-mini .cs-media {
      position: relative;
      width: 100%;
      height: auto;
      display: block;
    }
    .cs-card.cs-mini .cs-image {
      width: 100%;
      height: auto;          /* natural aspect ratio, not panel-height driven */
      object-fit: contain;
      border: none;
      border-radius: 3px;
    }
    .cs-card.cs-mini .cs-body { padding: 0; }
    /* metadata sits tight against the title (proportional to its smaller size, matching
       the main cards' visual tightness), then the title gets more room before the description */
    .cs-card.cs-mini .cs-company { margin-bottom: 18px; }
    .cs-card.cs-mini .cs-title {
      font-size: clamp(40px, 4.5vw, 68px);
      margin-bottom: 18px;
    }
    .cs-card.cs-mini .cs-company { color: var(--ice-meta); }
    .cs-card.cs-mini .cs-outcome { max-width: 46ch; }

    /* Copy Companion brow → title gap on tablet portrait — placed after the base
       .cs-card.cs-mini .cs-company rule so this later declaration wins the cascade. */
    @media (min-width: 768px) and (max-width: 1024px) and (orientation: portrait) {
      .cs-card.cs-mini .cs-company { margin-bottom: 6px; }
    }


    /* Copy Companion — tablet: compact two-column (content left, visual right) instead of
       a disconnected full-width stacked block. Slightly more text share than desktop since
       the column is narrower. Scoped to .cs-mini only — independent of the main-card tablet rules. */
    @media (min-width: 768px) and (max-width: 1024px) {
      .cs-card.cs-mini {
        grid-template-columns: 1.1fr 1fr;   /* slightly less text share (was 1.2fr) → more visual room */
        column-gap: clamp(16px, 2.2vw, 24px);   /* tighter gap (was clamp(20px,3vw,32px)) */
        min-height: 0;         /* image is in-flow, so image drives height — no fixed floor needed */
        max-width: none;
        align-items: start;
      }
    }

    /* Copy Companion — mobile rescue: stack vertically (text full-width, visual below).
       Placed after the rules above so it correctly overrides the unscoped two-column grid at mobile widths.
       min-height is explicitly reset to 0 here so the desktop strip height above doesn't leak down. */
    @media (max-width: 767px) {
      .cs-card.cs-mini {
        grid-template-columns: 1fr;
        max-width: 100%;
        min-height: 0;
      }
      .cs-card.cs-mini .cs-visual {
        margin-top: clamp(16px, 4vw, 22px);
        min-height: 0;    /* image is height:auto so no fixed floor needed; image drives the height */
      }
      /* CC media wrapper: in-flow on mobile so image height drives the panel */
      .cs-card.cs-mini .cs-media {
        position: relative;
        width: 100%;
        height: auto;
        display: block;
      }
    }

    /* ===== visual-led Selected Work: proof points + composed placeholders ===== */
    .cs-proof { display: flex; flex-wrap: wrap; align-items: center; gap: 9px 20px; }
    .cs-proof span {
      font-family: 'IBM Plex Mono', monospace; font-size: 10.5px;
      letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-secondary);
      display: inline-flex; align-items: center; gap: 8px;
    }
    .cs-proof span::before { content: '\2726'; color: var(--accent); font-size: 8px; }
    .cs-proof .cs-metric { color: var(--text-primary); font-weight: 600; }



    /* ===== subtle one-time title reveals ===== */
    .hero-display > div { opacity: 0; animation: fadeUp 0.6s ease forwards; }
    .hero-display > div:nth-child(1) { animation-delay: 0.42s; }
    .hero-display > div:nth-child(2) { animation-delay: 0.54s; }
    .hero-display > div:nth-child(3) { animation-delay: 0.66s; }

    .reveal-seq > .rw { display: inline-block; opacity: 0; }
    .reveal-seq.in > .rw { animation: fadeUp 0.5s ease forwards; }
    .reveal-seq.in > .rw:nth-of-type(1){ animation-delay: 0s; }
    .reveal-seq.in > .rw:nth-of-type(2){ animation-delay: .09s; }
    .reveal-seq.in > .rw:nth-of-type(3){ animation-delay: .18s; }
    .reveal-seq.in > .rw:nth-of-type(4){ animation-delay: .27s; }
    .reveal-seq.in > .rw:nth-of-type(5){ animation-delay: .36s; }
    .reveal-seq.in > .rw:nth-of-type(6){ animation-delay: .45s; }

    @media (prefers-reduced-motion: reduce) {
      .hero-display > div,
      .reveal-seq > .rw { opacity: 1 !important; animation: none !important; }
      .marquee-track { animation: none !important; }
    }

    /* ===== tablet: project hierarchy (meta+title above visual), About polish ===== */
    @media (min-width: 768px) and (max-width: 1024px) {
      .tcar-head { margin-bottom: clamp(36px, 5vw, 60px); }
      .tcard { flex: 0 0 min(58%, 420px); }   /* tablet: ~1.7 cards visible + peek */

      /* Meta + title introduce the visual; description + proof follow it.
         .cs-left/.cs-body are promoted via display:contents so their children become direct
         grid items of .cs-card — no markup changes, desktop/mobile untouched. Meta sits
         directly above title in a single stacked column (mobile's logic), so they read as
         one composed project header instead of two blocks forced onto one row. */
      .cs-card:not(.cs-mini) {
        display: grid;
        grid-template-columns: 1fr;
        grid-template-areas:
          "meta"
          "title"
          "visual"
          "desc"
          "proof";
        min-height: 0;
        background: var(--surface);
      }
      .cs-card:not(.cs-mini) .cs-left,
      .cs-card:not(.cs-mini) .cs-body { display: contents; }

      .cs-card:not(.cs-mini) .cs-num { display: none; }
      .visual-asos    .cs-company::before { content: "01 · "; }
      .visual-topshop .cs-company::before { content: "02 · "; }
      .visual-itvx    .cs-company::before { content: "03 · "; }

      .cs-card:not(.cs-mini) .cs-company {
        grid-area: meta;
        align-self: start;
        margin-bottom: 0;
        padding: clamp(22px, 3.2vw, 32px) clamp(22px, 3.2vw, 32px) 0;
      }
      .cs-card:not(.cs-mini) .cs-title {
        grid-area: title;
        align-self: start;
        text-align: left;
        white-space: nowrap;
        font-size: clamp(28px, 3.8vw, 44px);   /* more presence — reads as a title, not a label */
        letter-spacing: 0.03em;   /* tablet-only: eases the squish on condensed Bebas at this size */
        margin-bottom: 0;
        padding: 6px clamp(22px, 3.2vw, 32px) 0;
      }
      .cs-card:not(.cs-mini) .cs-title .cs-title-b { display: inline; }

      .cs-card:not(.cs-mini) .cs-visual {
        grid-area: visual;
        min-height: 300px;
        margin-top: clamp(20px, 3vw, 28px);
      }

      /* let the description breathe instead of feeling squeezed */
      .cs-card:not(.cs-mini) .cs-outcome {
        grid-area: desc;
        max-width: 680px;
        margin-top: clamp(20px, 3vw, 28px);
        padding: 0 clamp(22px, 3.2vw, 32px);
      }
      .cs-card:not(.cs-mini) .cs-proof {
        grid-area: proof;
        margin-top: clamp(26px, 3.4vw, 36px);
        padding: 0 clamp(22px, 3.2vw, 32px) clamp(22px, 3.2vw, 32px);
      }

      /* About: deliberate spacing for a more intentional tablet read.
         padding-left lives in a separate query below — it must only apply once
         .about-grid is actually two-column (min-width: 880px), otherwise the
         768–879px single-column range gets an indent with nothing to justify it. */
      .about-headline { margin-bottom: clamp(32px, 4.5vw, 48px); }
      .about-copy { max-width: 64ch; gap: clamp(20px, 2.6vw, 26px); }
    }

    /* About tablet indent — scoped to match .about-grid's two-column breakpoint exactly */
    @media (min-width: 880px) and (max-width: 1024px) {
      .about-copy { padding-left: 24px; }
    }

    /* =====================
       PHONE LANDSCAPE (orientation:landscape, max-height:500px)
       Height-based query catches all phone landscape viewports regardless of width
       (iPhone SE: 375px tall; iPhone 13 Pro: 390px; iPhone 15 Plus: 430px).
       Tablets in landscape are excluded because their short edge is ≥744px.
       Placed last in the stylesheet so it wins the cascade over the earlier
       tablet block (min-width:768–1024px) which also fires at 844px landscape.
    ======================== */
    @media (orientation: landscape) and (max-height: 500px) {
      .hero {
        min-height: auto;
        justify-content: flex-start;
        padding-top: clamp(72px, 18vh, 92px);   /* clears fixed nav (~60px), no large void */
        padding-bottom: 28px;
      }
      .hero-display { font-size: clamp(64px, 14vw, 88px); }
      .hero-lead { margin-top: 12px; font-size: 16px; line-height: 1.6; }
      .hero-meta { margin-top: 16px; padding-top: 12px; }

      .section-title,
      .about-headline,
      .exp-headline,
      .tcar-title { font-size: clamp(48px, 13vw, 64px); }

      .about-body,
      .exp-desc,
      .tcard-quote { font-size: 13px; line-height: 1.6; color: var(--text-secondary); }

      /* Section vertical spacing — tablet block fires at 844px wide and sets generous
         padding that was designed for a tall viewport; override here for the short landscape one. */
      .section-about    { padding: 40px 36px; margin-top: 0; }
      .section-experience { padding: 36px 36px 40px; }
      .section-testimonial { padding: 36px 36px 40px; }

      /* Experience rows: base ~29px per side is disproportionate at 13px copy */
      .exp-entry { padding: 12px 0; }

      /* Testimonial: tcar-head gap and tcard inner padding drive visual mass more than font-size */
      .tcar-head { margin-bottom: 20px; }
      .tcard { padding: 16px; flex: 0 0 min(72%, 380px); }
      .tcard-quote { margin-bottom: 12px; }

      .section-work { padding: 40px 24px 0; }

      /* Card titles: phone-landscape scale + single-line unwrap */
      .cs-title { font-size: clamp(28px, 6vw, 38px); }
      .cs-title .cs-title-b { display: inline; }

      /* Card layout: restore two-column and padding; counteract tablet display:contents
         rewrite (.cs-left/.cs-body) which fires at 768–1024px and would otherwise
         flatten the card structure on wider phones (844px+). */
      .cs-card:not(.cs-mini) {
        display: grid;
        grid-template-columns: 0.62fr 1.38fr;
        grid-template-areas: none;
        min-height: 0;
      }
      .cs-card:not(.cs-mini) .cs-left,
      .cs-card:not(.cs-mini) .cs-body { display: flex; }
      .cs-card:not(.cs-mini) .cs-body { flex-direction: column; }
      .cs-card:not(.cs-mini) .cs-visual { min-height: 0; }
      .cs-card:not(.cs-mini) .cs-company,
      .cs-card:not(.cs-mini) .cs-outcome,
      .cs-card:not(.cs-mini) .cs-proof {
        grid-area: auto;
        padding: 0;
        margin-top: 0;
        max-width: 100%;
      }

      .cs-outcome { font-size: 13px; }
      .cs-body { padding: 16px 0; }
      .cs-left { padding: 24px 28px; }
    }

    /* =====================
       PROJECT DETAIL PAGE
       Used by /drafts/*.html — .pd- prefix only.
       No changes to existing homepage selectors.
    ======================== */

    /* Back link */
    .pd-back {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10.5px;
      letter-spacing: 0.1em;
      text-transform: uppercase;
      color: rgba(232, 228, 220, 0.72);
      transition: color 0.2s ease;
      margin-bottom: 28px;
    }

    .pd-back-arrow {
      font-size: 1.2em;
      line-height: 1;
    }

    .pd-back:hover,
    .pd-back:focus-visible { color: var(--text-primary); }

    .pd-back:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 3px;
      border-radius: 2px;
    }

    /* Shared section wrapper — receives wide-desktop containment padding */
    .pd-section {
      padding: 80px 52px;
    }

    .pd-title-accent { color: var(--accent); }

    /* Header section */
    .pd-eyebrow {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 12px;
      font-weight: 400;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: var(--ice-meta);
      margin-bottom: 16px;
    }

    .pd-title {
      font-family: 'Bebas Neue', sans-serif;
      font-weight: 400;
      font-size: clamp(56px, 9vw, 140px);
      line-height: 0.87;
      letter-spacing: 0.01em;
      color: var(--text-primary);
      -webkit-font-smoothing: auto;
      -moz-osx-font-smoothing: auto;
      -webkit-text-stroke: 1px currentColor;
      paint-order: stroke fill;
      margin-bottom: clamp(48px, 5vw, 72px);
    }

    /* Shared content band — 1440px max, centred within section padding */
    .pd-container {
      max-width: 1600px;
      margin-inline: auto;
      width: 100%;
    }

    /* Primary video container */
    .pd-visual {
      width: 100%;
      background: var(--surface);
      border: 1px solid var(--border);
      overflow: hidden;
      position: relative;
    }

    .pd-visual .cs-video {
      display: block;
      width: 100%;
      height: auto;
    }

    .pd-visual img {
      display: block;
      width: 100%;
      height: auto;
    }

    .pd-cs-img-block img {
      display: block;
      width: 100%;
      height: 100%;
      object-fit: cover;
    }

    .pd-cs-img-block--natural {
      aspect-ratio: unset;
      background: transparent;
      border: none;
      display: block;
    }

    .pd-cs-img-block--natural img {
      height: auto;
      object-fit: initial;
    }

    /* Summary block */
    .pd-outcome {
      font-family: 'DM Sans', sans-serif;
      font-size: clamp(14px, 1.25vw, 16px);
      line-height: 1.65;
      color: var(--text-body-bright);
      max-width: 68ch;
      margin-bottom: 28px;
    }

    .pd-proof {
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
    }

    .pd-proof span {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10.5px;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--text-primary);
      background: rgba(155, 126, 255, 0.06);
      border: 1px solid rgba(155, 126, 255, 0.25);
      padding: 5px 10px;
      border-radius: 2px;
    }

    /* Placeholder sections */
    .pd-placeholder {
      border: 1px solid var(--border);
      border-radius: 2px;
      padding: 40px 36px;
      display: flex;
      flex-direction: column;
      gap: 8px;
      cursor: default;
    }

    .pd-placeholder:hover {
      border-color: var(--border);
    }

    .pd-placeholder-label {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--ice-meta);
    }

    .pd-placeholder-note {
      font-family: 'DM Sans', sans-serif;
      font-size: 13px;
      color: var(--text-body-bright);
      line-height: 1.5;
      padding-left: 16px;
      margin: 0;
    }

    .pd-placeholder-grid {
      display: grid;
      grid-template-columns: 1fr 1fr 1fr;
      gap: 3px;
    }

    /* Responsive — tablet */
    @media (max-width: 1024px) {
      .pd-section { padding: 60px 36px; }
      .pd-placeholder-grid { grid-template-columns: 1fr; }
      .pd-placeholder { padding: 28px 32px; }
    }

    /* Responsive — mobile */
    @media (max-width: 767px) {
      .pd-section { padding: 48px 24px; }
      .pd-eyebrow { font-size: 12px; margin-bottom: 12px; }
      .pd-title { font-size: clamp(52px, 14vw, 88px); margin-bottom: 32px; }
      .pd-placeholder-grid { grid-template-columns: 1fr; }
      .pd-placeholder {
        padding: 20px 0;
        border: none;
        border-radius: 0;
        position: relative;
      }
      .pd-placeholder:not(:last-child)::after {
        content: '';
        display: block;
        position: absolute;
        bottom: 0;
        left: 12px;
        right: 12px;
        height: 1px;
        background: var(--border);
      }
    }

    /* Desktop — spacing overrides */
    @media (min-width: 1025px) {
      .pd-back    { margin-bottom: 56px; }
      .pd-eyebrow { margin-bottom: 20px; }
      .pd-title   { margin-bottom: 76px; }
    }

    /* Per-section vertical rhythm — placed after responsive blocks so these
       longhand overrides win over the .pd-section shorthand at every breakpoint.
       Horizontal gutters still come from .pd-section at each breakpoint. */
    .pd-header          { padding-top: clamp(96px, 9vh, 128px); padding-bottom: 0; }
    .pd-visual-section  { padding-top: 0; padding-bottom: 0; }
    .pd-summary-section { padding-top: 40px; padding-bottom: 0; }
    .pd-detail-section  { padding-top: 36px; padding-bottom: 80px; }

    /* Desktop — pd-header override placed after base rule to win the cascade */
    @media (min-width: 1025px) {
      .pd-header { padding-top: 168px; }
      /* Reduce the last case section's internal bottom padding and push the nav
         away with margin-top — total gap from paragraph text to nav border ≈ 168px. */
      .pd-case-section--last { padding-bottom: 48px; }
      .pd-project-nav        { margin-top: 80px; }
      /* Breathing room between intro cards and Section 01 (+64px over global 80px) */
      .pd-detail-section     { padding-bottom: 144px; }
      /* Watermark: top edge at 28px so MANUAL WORK isn't clipped by overflow:hidden */
      .pd-exp-watermark      { top: -104px; }
    }

    /* =====================
       CASE STUDY BODY SECTIONS
    ======================== */

    .pd-case-section {
      padding-top: 64px;
      padding-bottom: 64px;
    }

    .pd-case-section--last {
      padding-bottom: 96px;
    }

    .pd-cs-label {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--ice-meta);
      margin-bottom: 20px;
    }

    .pd-cs-body {
      font-family: 'DM Sans', sans-serif;
      font-size: clamp(14px, 1.2vw, 16px);
      line-height: 1.7;
      color: var(--text-body-bright);
      max-width: 62ch;
      margin-bottom: 40px;
    }

    .pd-cs-img-block {
      width: 100%;
      background: var(--surface);
      border: 1px solid rgba(158, 154, 148, 0.10);
      aspect-ratio: 16 / 7;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .pd-cs-img-text {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10.5px;
      letter-spacing: 0.1em;
      text-transform: uppercase;
      color: var(--text-muted);
      padding: 0 16px;
      text-align: center;
    }

    /* =====================
       PROJECT NAVIGATION
    ======================== */

    .pd-project-nav {
      /* Reset every property the bare `nav {}` tag rule sets.
         That rule uses position:fixed + inset:0 for the main navbar —
         without these overrides the project nav is pinned to the top
         of the viewport and layered over all case study content. */
      position: static;
      inset: auto;
      z-index: auto;
      align-items: stretch;
      justify-content: normal;
      padding: 0;
      border-bottom: none;
      transition: none;
      /* Project nav layout */
      border-top: 1px solid var(--border);
      display: grid;
      grid-template-columns: 1fr 1fr;
    }

    .pd-project-nav-item {
      display: flex;
      flex-direction: column;
      gap: 0;
      padding: 56px 52px;
      transition: background 0.2s ease;
    }

    .pd-project-nav-item:first-child {
      border-right: 1px solid var(--border);
    }

    .pd-project-nav-item--next {
      align-items: flex-end;
      text-align: right;
    }

    .pd-project-nav-item:hover {
      background: rgba(155, 126, 255, 0.03);
    }

    .pd-project-nav-dir {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--text-muted);
      margin-bottom: 20px;
    }

    .pd-project-nav-brow {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--ice-meta);
      margin-bottom: 6px;
    }

    .pd-project-nav-name {
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(34px, 3.7vw, 56px);
      font-weight: 400;
      line-height: 0.9;
      letter-spacing: 0.01em;
      text-transform: uppercase;
      color: var(--text-primary);
      transition: color 0.2s ease;
    }

    .pd-project-nav-item:hover .pd-project-nav-name {
      color: var(--text-primary);
    }

    .pd-project-nav-item:focus-visible {
      outline: none;
      box-shadow: inset 0 0 0 2px var(--accent), 0 0 12px rgba(155, 126, 255, 0.12);
    }

    /* Case section responsive — tablet */
    @media (max-width: 1024px) {
      .pd-case-section { padding-top: 48px; padding-bottom: 48px; }
      .pd-case-section--last { padding-bottom: 72px; }
      .pd-project-nav-item { padding: 44px 36px; }
    }

    /* Case section responsive — mobile */
    @media (max-width: 767px) {
      .pd-case-section { padding-top: 40px; padding-bottom: 40px; }
      .pd-case-section--last { padding-bottom: 64px; }
      .pd-cs-body { font-size: 14px; margin-bottom: 24px; }
      .pd-cs-img-block { aspect-ratio: 4 / 3; }
      .pd-project-nav { grid-template-columns: 1fr; }
      .pd-project-nav-item { padding: 36px 24px; }
      .pd-project-nav-item:first-child {
        border-right: none;
        border-bottom: 1px solid var(--border);
      }
      .pd-project-nav-item--next {
        align-items: flex-start;
        text-align: left;
      }
    }

    /* Project nav wide-desktop containment — must come AFTER the base
       .pd-project-nav and .pd-project-nav-item rules (which reset padding)
       so this block wins on source order.
       Logic: outer nav stays full-width (no padding on the container);
       items get a viewport-proportional gutter that breaks wider than the
       1600px case-study content band, but caps at 120px so titles never
       hug the viewport edges on zoomed-out or ultra-wide displays. */
    @media (min-width: 1441px) {
      .pd-project-nav-item {
        padding-left:  clamp(56px, 4vw, 84px);
        padding-right: clamp(56px, 4vw, 84px);
      }
    }

    /* =====================================================================
       EXPERIMENT — ASOS storytelling exploration
       To remove entirely: delete from this comment to END EXPERIMENT below.
       No existing selectors were modified — all rules use .pd-exp-* prefix.
    ===================================================================== */

    /* Positional context for sections with absolutely-positioned experiment layers */
    .pd-exp-s01 {
      position: relative;
      overflow: hidden;
    }

    /* Utility: hides original content temporarily replaced by experiment.
       Original markup is preserved in DOM for easy revert.
       !important needed — some .pd-exp-* rules set display later in source. */
    .pd-exp-hidden { display: none !important; }

    /* --- S01: Background watermark --- */
    .pd-exp-watermark {
      position: absolute;
      top: 22%;
      left: 50%;
      width: min(100%, 2200px);
      transform: translateX(-50%);
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(140px, 14vw, 280px);
      line-height: 0.85;
      letter-spacing: 0.01em;
      color: var(--text-primary);
      opacity: 0.025;
      pointer-events: none;
      user-select: none;
      z-index: 0;
    }

    .pd-exp-watermark span { display: block; white-space: nowrap; }
    .pd-exp-watermark span:first-child { text-align: left; }
    .pd-exp-watermark span:last-child  { text-align: right; }
    /* Per-word wrappers stay inline so they flow exactly like the original text
       nodes did (overriding the descendant span{display:block} above by
       specificity). Purely a targeting hook — no visual change at any breakpoint. */
    .pd-exp-watermark .wm-word { display: inline; }

    /* Mid-width override — placed AFTER base rule to win the cascade */
    @media (min-width: 768px) and (max-width: 1024px) {
      .pd-exp-watermark { top: 0; opacity: 0.048; }
      .pd-exp-s01 .pd-container { padding-top: 112px; }
    }

    /* Desktop overrides — placed AFTER base rules to win the cascade */
    @media (min-width: 1025px) {
      .pd-exp-watermark      { top: 36px; }
      .pd-exp-s01 .pd-cs-body { max-width: 54ch; }
    }

    .pd-exp-s01 .pd-container { position: relative; z-index: 1; }

    @media (min-width: 1025px) {
      .pd-exp-s01 .pd-container { padding-top: 136px; }
    }

    /* Mobile watermark — large stacked layout, foreground pushed below by container padding */
    @media (max-width: 767px) {
      .pd-exp-watermark {
        top: 20px;
        left: 0;
        width: 100%;
        transform: none;
        opacity: 0.04;
      }
      /* white-space without text-align (generic span loses to :first/:last-child specificity) */
      .pd-exp-watermark span { white-space: normal; }
      /* Explicit overrides at matching specificity — win by source order */
      .pd-exp-watermark span:first-child { text-align: center; }
      .pd-exp-watermark span:last-child  { text-align: center; }
      /* Push all foreground content below the full four-line watermark block */
      .pd-exp-s01 .pd-container { padding-top: 480px; }
    }

    /* --- S01 experiment: mobile-portrait sequential watermark word emphasis ---
       As the watermark scrolls into view (JS adds .wm-seq), each word briefly
       lifts ~25% above the resting opacity in reading order — MANUAL, WORK, a
       short pause, DOESN'T, SCALE — then settles back to rest, echoing the
       homepage contact-word timing. Scoped to portrait phones with motion
       allowed only: tablet, desktop, landscape and reduced-motion users are
       untouched (they keep the static resting watermark defined above). */
    @media (max-width: 767px) and (orientation: portrait) and (prefers-reduced-motion: no-preference) {
      /* Move the opacity ceiling off the container and onto the words so a single
         word can brighten past the resting value (container opacity would cap every
         child). Resting appearance is unchanged: each word rests at 0.04. */
      .pd-exp-watermark { opacity: 1; }
      .pd-exp-watermark .wm-word { opacity: 0.04; }

      .pd-exp-watermark.wm-seq .wm-word {
        animation: wmWordEmphasis 1.2s ease-in-out both;
      }
      .pd-exp-watermark.wm-seq > span:first-child > .wm-word:first-child { animation-delay: 0s; }
      .pd-exp-watermark.wm-seq > span:first-child > .wm-word:last-child  { animation-delay: 0.22s; }
      .pd-exp-watermark.wm-seq > span:last-child  > .wm-word:first-child { animation-delay: 1.15s; }
      .pd-exp-watermark.wm-seq > span:last-child  > .wm-word:last-child  { animation-delay: 1.37s; }
    }

    /* Resting 0.04 → 0.16 peak → back to rest. Both-fill keeps
       the word at the resting 0.04 before its delay elapses and after it ends.
       Timing reads as: MANUAL + WORK quickly, pause, DOESN'T + SCALE quickly. */
    @keyframes wmWordEmphasis {
     0%   { opacity: 0.04; }
     12%  { opacity: 0.16; }
     58%  { opacity: 0.16; }
     100% { opacity: 0.04; }
    }

    /* --- S01: THEN / NOW visual evidence panel --- */
    .pd-exp-evidence {
      /* isolation: isolate creates a local stacking context so z-index values inside
         are self-contained — this scopes the video's GPU compositing layer and ensures
         the overlay always renders above it regardless of browser compositing behaviour */
      isolation: isolate;
      position: relative;
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: clamp(4px, 0.5vw, 8px);
      margin-top: 40px;
      align-items: start;
    }

    /* Slight downward offset on the video side creates the editorial diagonal:
       eye travels THEN (top-left) → VS (centre) → NOW (bottom-right) */
    .pd-exp-evidence-item--now {
      margin-top: clamp(16px, 2vw, 28px);
    }

    /* Collage scaled fractionally larger to counter the solid-rectangle weight of the video */
    .pd-exp-evidence-item--then .pd-cs-img-block--natural {
      transform: scale(1.05);
      transform-origin: center;
    }

    /* Overlay: fills the full composition area and sits definitively above the video.
       pointer-events: none passes all interactions (video controls) through to the layers below. */
    .pd-exp-evidence-overlay {
      position: absolute;
      inset: 0;
      overflow: visible;
      pointer-events: none;
      z-index: 5;
    }

    .pd-exp-evidence-word {
      position: absolute;
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(52px, 6vw, 80px);
      letter-spacing: 0.02em;
      line-height: 1;
      pointer-events: none;
      user-select: none;
    }

    .pd-exp-evidence-word--then {
      left: 0;
      bottom: 8%;
      color: var(--text-body-bright);
      opacity: 0.55;
    }

    .pd-exp-evidence-word--now {
      right: -18px;
      bottom: 4%;
      color: #38BDF8;
      text-shadow: 0 0 8px rgba(56, 189, 248, 0.18);
    }

    /* VS: optically balanced between the two visuals — left of mathematical centre
       so perceived overlap accounts for the collage's transparent outer edges */
    .pd-exp-evidence-vs {
      position: absolute;
      left: 47%;
      top: 50%;
      transform: translate(-50%, -50%);
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(110px, 12vw, 176px);
      letter-spacing: 0.05em;
      color: var(--accent);
      line-height: 1;
      pointer-events: none;
      user-select: none;
    }

    /* Evidence panel: frameless, shared 16:9 aspect ratio for balance */
    .pd-exp-evidence .pd-visual,
    .pd-exp-evidence .pd-cs-img-block--natural {
      aspect-ratio: 16 / 9;
      border: none;
      background: transparent;
    }

    /* Collage: contain so the full transparent composition shows, no cropping */
    .pd-exp-evidence .pd-cs-img-block--natural img {
      width: 100%;
      height: 100%;
      object-fit: contain;
    }

    /* Video: fill its 16:9 frame */
    .pd-exp-evidence .cs-video {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }

    @media (max-width: 640px) {
      .pd-exp-evidence {
        grid-template-columns: 1fr;
        gap: clamp(12px, 4vw, 20px);
      }
      .pd-exp-evidence-item--now { margin-top: 0; }
      .pd-exp-evidence-item--then .pd-cs-img-block--natural { transform: none; }
      /* Overlay is desktop-only — decorative labels don't adapt well to narrow stacked layout */
      .pd-exp-evidence-overlay { display: none; }
    }

    /* --- S01: Old World / New World contrast exhibit --- */
    .pd-exp-world-contrast {
      display: grid;
      grid-template-columns: 1fr auto 1fr;
      align-items: start;
      border: 1px solid var(--border);
      padding: clamp(32px, 4vw, 56px);
      margin-top: 40px;
      gap: 0 clamp(32px, 4vw, 64px);
    }

    .pd-exp-world-col {
      display: flex;
      flex-direction: column;
      gap: 14px;
    }

    .pd-exp-world-heading {
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(28px, 3vw, 46px);
      letter-spacing: 0.01em;
      color: var(--text-muted);
      margin-bottom: 16px;
      display: block;
      line-height: 1;
    }

    .pd-exp-world-item {
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(22px, 2.2vw, 36px);
      letter-spacing: 0.01em;
      line-height: 1;
    }

    .pd-exp-world-item--old {
      color: var(--text-muted);
      opacity: 0.55;
      text-decoration: line-through;
      text-decoration-color: rgba(126, 123, 119, 0.45);
    }

    .pd-exp-world-item--new {
      color: var(--text-primary);
    }

    .pd-exp-world-item--new:first-of-type { color: var(--ice); }

    .pd-exp-world-heading--then { color: var(--text-muted); }
    .pd-exp-world-heading--now  { color: var(--ice-meta); }

.pd-exp-world-divider {
      display: flex;
      align-items: center;
      justify-content: center;
      align-self: center;
      padding: 0 clamp(16px, 2.5vw, 36px);
    }

    .pd-exp-world-divider-arrow {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 20px;
      color: var(--accent);
    }

    /* --- S02: System flow diagram --- */
    .pd-exp-flow {
      display: flex;
      flex-direction: column;
      align-items: center;
      margin-top: 40px;
      border: 1px solid var(--border);
      padding: clamp(40px, 5vw, 72px) clamp(32px, 4vw, 56px);
    }

    .pd-exp-flow-node {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 5px;
      text-align: center;
    }

    .pd-exp-flow-node-name {
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(28px, 3vw, 48px);
      letter-spacing: 0.01em;
      color: var(--text-primary);
      line-height: 1;
    }

    .pd-exp-flow-node-label {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 9px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--text-secondary);
    }

    .pd-exp-flow-connector {
      display: flex;
      flex-direction: column;
      align-items: center;
      padding: 10px 0;
    }

    .pd-exp-flow-line {
      width: 1px;
      height: 22px;
      background: transparent;
      display: block;
    }

    .pd-exp-flow-arrow {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 11px;
      color: var(--accent);
      line-height: 1;
      animation: pd-exp-flow-pulse 2.6s ease-in-out infinite;
    }

    @keyframes pd-exp-flow-pulse {
      0%, 100% { opacity: 0.35; }
      50%       { opacity: 1; }
    }

    /* --- S03: Guardrail background typography --- */
    .pd-exp-guardrail-bg {
      position: absolute;
      top: 50%;
      right: -2%;
      transform: translateY(-50%);
      display: flex;
      flex-direction: column;
      gap: 0;
      pointer-events: none;
      user-select: none;
      z-index: 0;
      opacity: 0.045;
      text-align: right;
    }

    .pd-exp-guardrail-line {
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(52px, 5.5vw, 96px);
      letter-spacing: 0.01em;
      color: var(--text-primary);
      line-height: 0.9;
      white-space: nowrap;
      display: block;
    }

    .pd-exp-s03 .pd-container { position: relative; z-index: 1; }

    /* --- S04: Bold outcome statement --- */
    .pd-exp-outcome-statement {
      margin-top: 48px;
      display: flex;
      flex-direction: column;
      gap: 0;
    }

    .pd-exp-outcome-word {
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(80px, 10vw, 160px);
      line-height: 0.87;
      letter-spacing: 0.01em;
      color: var(--text-primary);
      display: block;
    }

    .pd-exp-outcome-word--accent { color: var(--accent); }

    .pd-exp-outcome-note {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 10px;
      letter-spacing: 0.14em;
      text-transform: uppercase;
      color: var(--ice-meta);
      margin-top: 32px;
      margin-bottom: 48px;
      line-height: 1.6;
    }

    /* --- S05: Future architecture tags --- */
    .pd-exp-arch {
      display: flex;
      flex-wrap: wrap;
      gap: 3px;
      margin-top: 40px;
    }

    .pd-exp-arch-tag {
      font-family: 'IBM Plex Mono', monospace;
      text-transform: uppercase;
      letter-spacing: 0.06em;
      color: var(--text-muted);
      border: 1px solid var(--border);
      line-height: 1;
      transition: color 0.2s ease, border-color 0.2s ease;
    }

    .pd-exp-arch-tag--lg {
      font-size: clamp(20px, 2.4vw, 38px);
      padding: 14px 22px;
    }

    .pd-exp-arch-tag--sm {
      font-size: clamp(13px, 1.4vw, 20px);
      padding: 14px 18px;
      color: rgba(126, 123, 119, 0.5);
      border-color: rgba(30, 30, 27, 0.5);
    }

    .pd-exp-arch-tag:hover {
      color: var(--text-secondary);
      border-color: rgba(155, 126, 255, 0.2);
    }

    /* --- S05: Proven / Next two-column layout (replaces pd-exp-arch tags) --- */
    .pd-exp-proven-next {
      display: grid;
      grid-template-columns: 1fr 1fr;
      margin-top: 48px;
      border: 1px solid var(--border);
    }

    .pd-exp-proven-col {
      padding: clamp(32px, 4vw, 56px);
    }

    .pd-exp-proven-col:first-child {
      border-right: 1px solid var(--border);
    }

    .pd-exp-proven-heading {
      font-family: 'Bebas Neue', sans-serif;
      font-size: clamp(48px, 5.5vw, 88px);
      line-height: 0.9;
      letter-spacing: 0.01em;
      color: var(--text-primary);
      display: block;
      margin-bottom: clamp(20px, 2.5vw, 32px);
    }

    .pd-exp-proven-heading--next { color: var(--accent); }

    .pd-exp-proven-list {
      list-style: none;
      padding: 0;
      margin: 0;
      display: flex;
      flex-direction: column;
      gap: 14px;
    }

    .pd-exp-proven-item {
      font-family: 'DM Sans', sans-serif;
      font-size: clamp(14px, 1.3vw, 17px);
      font-weight: 300;
      line-height: 1.4;
      color: var(--text-body-bright);
    }

    .pd-exp-proven-item--next { color: var(--text-secondary); }

    @media (min-width: 1025px) and (max-width: 1320px) {
      .pd-exp-card-fix .pd-placeholder {
        padding: 24px 20px;
        border-color: rgba(30, 30, 27, 0.6);
      }
    }

    /* ===== END EXPERIMENT ===== */


    /* =====================================================================
       "Full view" — reusable media viewer
       ---------------------------------------------------------------------
       Any element marked [data-viewable] that contains an <img> or <video>
       gains a hover affordance and opens the media in a shared fullscreen
       modal. Everything here is namespaced (vx-*) so it never touches an
       existing layout. The JS (script.js) injects the .vx-trigger button
       and the single #vxModal — pages only need the data-viewable attribute.
       Reused across every project (ASOS, Topshop, ITVX, …); nothing here is
       project-specific.
       ===================================================================== */

    /* Only used as the positioning context for the injected trigger; relative
       is a no-op for layout on the media wrappers this is applied to. */
    [data-viewable] { position: relative; }

    /* Injected overlay button — the single interactive/focusable layer.
       z-index 3 keeps it above the media but below decorative evidence
       overlays (z-index 5, pointer-events:none), so those labels stay on top
       while clicks still land on the button. */
    .vx-trigger {
      position: absolute;
      inset: 0;
      z-index: 3;
      display: flex;
      align-items: center;
      justify-content: center;
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
      border: 1px solid transparent;
      background: none;
      cursor: pointer;
      font: inherit;
      color: var(--text-primary);
      transition: border-color 0.35s ease;
    }

    /* Subtle darkening wash — fades in on hover/focus */
    .vx-trigger-overlay {
      position: absolute;
      inset: 0;
      background: rgba(8, 8, 8, 0.42);
      opacity: 0;
      transition: opacity 0.35s ease;
    }

    /* Centred editorial affordance — icon only (⤢), larger than the old text but restrained */
    .vx-trigger-label {
      position: relative;
      z-index: 1;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      font-size: clamp(64px, 6.4vw, 88px);
      line-height: 1;
      letter-spacing: normal;
      color: var(--text-primary);
      opacity: 0;
      transform: translateY(6px);
      transition: opacity 0.35s ease, transform 0.35s ease;
    }

    .vx-trigger:hover .vx-trigger-overlay,
    .vx-trigger:focus-visible .vx-trigger-overlay { opacity: 1; }
    .vx-trigger:hover .vx-trigger-label,
    .vx-trigger:focus-visible .vx-trigger-label { opacity: 1; transform: none; }

    /* Border gains a little contrast on hover/focus */
    .vx-trigger:hover,
    .vx-trigger:focus-visible { border-color: rgba(232, 228, 220, 0.32); }
    .vx-trigger:focus-visible {
      outline: none;
      box-shadow: inset 0 0 0 2px rgba(155, 126, 255, 0.45);
    }

    /* Reduced motion: no slide, keep only the opacity change */
    @media (prefers-reduced-motion: reduce) {
      .vx-trigger-label { transform: none; transition: opacity 0.35s ease; }
    }

    /* Touch / no-hover devices: there is no hover to reveal the centred icon, so
       surface a small, persistent ⤢ cue in the media's bottom-right corner so the
       "openable" affordance is discoverable. The whole media stays one tap target —
       tapping anywhere still opens the modal. Desktop hover/focus design above is
       untouched (this only applies where the primary pointer can't hover). */
    @media (hover: none) {
      .vx-trigger {
        align-items: flex-end;
        justify-content: flex-end;
        padding: clamp(8px, 2.2vw, 14px);
      }
      .vx-trigger-label {
        opacity: 0.9;
        transform: none;
        font-size: clamp(18px, 4.4vw, 24px);
        padding: 3px 6px;
        background: rgba(8, 8, 8, 0.5);
        border: 1px solid rgba(151, 113, 255, 0.45);
        border-radius: 4px;
        backdrop-filter: blur(4px);
        -webkit-backdrop-filter: blur(4px);
        box-shadow: 0 0 16px rgba(151, 113, 255, 0.16);
      }
    }

    /* ---- Shared fullscreen modal ---- */
    .vx-modal {
      position: fixed;
      inset: 0;
      z-index: 9800;               /* sits above page chrome (nav, back-to-top) */
      display: none;
      align-items: center;
      justify-content: center;
      padding: clamp(12px, 2vw, 24px);   /* small safe margin only — media does the filling */
    }
    .vx-modal:not([hidden]) { display: flex; }

    .vx-modal-backdrop {
      position: absolute;
      inset: 0;
      background: rgba(4, 4, 4, 0.94);
      backdrop-filter: blur(8px);
      -webkit-backdrop-filter: blur(8px);
    }

    .vx-modal-inner {
      position: relative;
      z-index: 1;
      max-width: 100%;
      max-height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    /* The element hugs the media's own bounds: auto width/height keep the intrinsic
       aspect ratio, while max-width/height let it scale up close to the viewport
       (95vw × 92vh) without ever cropping. No fixed envelope and no #000 fill, so
       there's no black letterbox around the asset. object-fit: contain is a harmless
       safeguard; no border, which would detach from the media edge. */
    .vx-media {
      display: block;
      width: auto;
      height: auto;
      max-width: 95vw;
      max-height: 92vh;
      object-fit: contain;
      border-radius: 3px;
    }

    .vx-modal-close {
      position: absolute;
      top: clamp(16px, 3vw, 28px);
      right: clamp(16px, 3vw, 28px);
      z-index: 2;
      width: 44px;
      height: 44px;
      display: flex;
      align-items: center;
      justify-content: center;
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: 50%;
      color: var(--text-primary);
      cursor: pointer;
      transition: border-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
    }
    .vx-modal-close svg { width: 16px; height: 16px; }
    .vx-modal-close:hover { border-color: var(--accent); color: var(--accent); transform: scale(1.05); }
    .vx-modal-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

    /* Restrained entrance — gated for reduced motion */
    @media (prefers-reduced-motion: no-preference) {
      .vx-modal.vx-anim .vx-modal-backdrop { animation: vxModalFade 0.24s ease; }
      .vx-modal.vx-anim .vx-modal-inner    { animation: vxModalRise 0.30s cubic-bezier(0.22, 1, 0.36, 1); }
    }
    @keyframes vxModalFade { from { opacity: 0; } to { opacity: 1; } }
    @keyframes vxModalRise {
      from { opacity: 0; transform: translateY(12px) scale(0.98); }
      to   { opacity: 1; transform: translateY(0) scale(1); }
    }
