/* ---------------------------------------------------------
     TOKENS
  --------------------------------------------------------- */
  :root{
    --paper:#FAFAF5;
    --paper-dim:#EFECE0;
    --ink:#15161A;
    --ink-70:rgba(21,22,26,.72);
    --ink-55:rgba(21,22,26,.55);
    --ink-30:rgba(21,22,26,.3);
    --ink-14:rgba(21,22,26,.14);
    --orange:#005AFE;
    --orange-dark:#0047C7;
    --cmyk-c:#1688FB;
    --cmyk-m:#FB16B6;
    --cmyk-y:#EFFB16;
    --lime:#D6FF3F;
    --white:#FFFFFF;
    --measure:640px;
    --wrap:1220px;
    --font-d:'Poppins', system-ui, sans-serif;
    --font-b:'Google Sans', 'Product Sans', 'Manrope', system-ui, sans-serif;
    --font-hero:'Poppins', system-ui, sans-serif;
    --ease:cubic-bezier(.16,.84,.44,1);
  }

  *,*::before,*::after{box-sizing:border-box;}
  html{scroll-behavior:smooth;}
  @media (prefers-reduced-motion: reduce){
    html{scroll-behavior:auto;}
    *{animation-duration:.001ms !important; animation-iteration-count:1 !important; transition-duration:.001ms !important;}
  }
  body{
    margin:0;
    background:var(--paper);
    color:var(--ink);
    font-family:var(--font-b);
    font-size:17px;
    line-height:1.6;
    -webkit-font-smoothing:antialiased;
    overflow-x:hidden;
  }
  img{max-width:100%;display:block;}
  a{color:inherit;}
  h1,h2,h3,h4{
    font-family:var(--font-d);
    font-weight:700;
    line-height:1.02;
    letter-spacing:-.01em;
    margin:0;
  }
  p{margin:0 0 1em;}
  p:last-child{margin-bottom:0;}
  ul{margin:0;padding:0;list-style:none;}
  button{font:inherit;}
  .wrap{max-width:var(--wrap);margin:0 auto;padding:0 32px;}
  .prose{max-width:var(--measure);}
  section{padding:120px 0;position:relative;}
  @media(max-width:720px){
    section{padding:76px 0;}
    .wrap{padding:0 22px;}
  }

  /* grain overlay */
  .grain{
    position:fixed;inset:0;pointer-events:none;z-index:999;
    opacity:.035;mix-blend-mode:multiply;
    background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  }

  /* ---------------------------------------------------------
     UTILITIES
  --------------------------------------------------------- */
  .btn{
    display:inline-flex;align-items:center;gap:10px;
    padding:15px 26px;border-radius:100px;
    font-family:var(--font-b);font-weight:700;font-size:1rem;
    text-decoration:none;border:2px solid var(--ink);cursor:pointer;
    transition:transform .25s var(--ease), background .25s, color .25s;
    white-space:nowrap;
  }
  .btn svg{width:16px;height:16px;flex:none;}
  .btn-solid{background:var(--ink);color:var(--paper);}
  .btn-solid:hover{transform:translate(-2px,-2px);background:var(--orange);border-color:var(--orange);color:var(--white);}
  .btn-ghost{background:transparent;color:var(--ink);}
  .btn-ghost:hover{transform:translate(-2px,-2px);background:var(--ink);color:var(--paper);}

  .tag{
    display:inline-flex;align-items:center;gap:8px;
    font-size:1rem;font-weight:700;color:var(--ink-70);
    padding:6px 14px;border:1.5px solid var(--ink-14);border-radius:100px;
    background:var(--white);
  }
  .tag i{width:7px;height:7px;border-radius:50%;background:var(--orange);flex:none;}

  .chip{
    display:inline-block;padding:8px 16px;border-radius:100px;
    background:var(--paper-dim);font-size:1rem;font-weight:600;
    border:1.5px solid var(--ink-14);
  }

  .link-arrow{
    display:inline-flex;align-items:center;gap:8px;font-weight:700;
    text-decoration:none;border-bottom:2px solid var(--ink);padding-bottom:2px;
    transition:border-color .2s, color .2s, gap .2s;
  }
  .link-arrow svg{width:14px;height:14px;transition:transform .25s var(--ease);}
  .link-arrow:hover{color:var(--orange-dark);border-color:var(--orange-dark);}
  .link-arrow:hover svg{transform:translate(3px,-3px);}

  .dots{display:inline-flex;gap:5px;}
  .dot{width:9px;height:9px;border-radius:50%;display:inline-block;}
  .dot.c{background:var(--cmyk-c);}
  .dot.m{background:var(--cmyk-m);}
  .dot.y{background:var(--cmyk-y);}

  .kicker{display:flex;align-items:center;gap:14px;margin-bottom:18px;}
  .regmark{width:26px;height:26px;flex:none;color:var(--ink-55);}

  .section-head{margin-bottom:32px;}
  .section-head h2{font-size:clamp(2.1rem,4.4vw,3.2rem);margin-bottom:16px;}
  .section-head h2.hero-size{font-size:clamp(2.7rem,5.8vw,4.6rem);letter-spacing:-.015em;}
  .section-head .section-lead{max-width:520px;color:var(--ink-70);font-size:1.08rem;}
  .section-head + .case{padding-top:0;}

  /* ---------------------------------------------------------
     NAV
  --------------------------------------------------------- */
  .nav{
    position:fixed;top:0;left:0;right:0;z-index:500;
    border-bottom:2px solid rgba(250,250,245,.15);
    background:#000000;
  }
  .nav .wrap{display:flex;align-items:center;justify-content:space-between;height:78px;}
  .nav-brand{display:flex;align-items:center;text-decoration:none;color:var(--paper);}
  .nav-brand img{height:40px;width:auto;display:block;}
  .nav-links{display:flex;align-items:center;gap:34px;}
  .nav-links a{text-decoration:none;color:var(--paper);font-weight:700;font-size:1rem;position:relative;}
  .nav-links a:not(.btn)::after{
    content:"";position:absolute;left:0;right:0;bottom:-6px;height:2px;background:var(--orange);
    transform:scaleX(0);transform-origin:right;transition:transform .28s var(--ease);
  }
  .nav-links a:not(.btn):hover::after{transform:scaleX(1);transform-origin:left;}
  .nav-toggle{display:none;background:none;border:none;cursor:pointer;padding:8px;color:var(--paper);}
  .nav-toggle svg{width:26px;height:26px;}

  @media(min-width:881px){
    .nav-links .btn-solid{background:var(--paper);color:var(--ink);border-color:var(--paper);}
    .nav-links .btn-solid:hover{background:var(--orange);color:var(--white);border-color:var(--orange);}
  }

  @media(max-width:880px){
    .nav-links{
      position:fixed;inset:0;top:78px;background:var(--ink);color:var(--paper);
      flex-direction:column;justify-content:center;align-items:flex-start;gap:0;
      padding:20px 32px;transform:translateY(-8px);opacity:0;pointer-events:none;
      transition:opacity .3s var(--ease), transform .3s var(--ease);
    }
    body.nav-open .nav-links{opacity:1;pointer-events:auto;transform:translateY(0);}
    .nav-links a{color:var(--paper);font-family:var(--font-b);font-size:2.1rem;font-weight:700;padding:14px 0;border-bottom:1px solid rgba(250,250,245,.15);width:100%;}
    .nav-links a:not(.btn)::after{display:none;}
    .nav-links .btn{justify-content:center;margin-top:22px;border-color:var(--paper);color:var(--paper);}
    .nav-links .btn:hover{background:var(--orange);border-color:var(--orange);}
    .nav-toggle{display:block;}
  }

  /* ---------------------------------------------------------
     HERO
  --------------------------------------------------------- */
  .hero{padding:204px 0 50px;overflow:visible;}
  .hero .wrap{position:relative;display:grid;grid-template-columns:1.15fr .85fr;gap:56px;align-items:center;}

  .hero h1{
    font-family:var(--font-hero);
    font-weight:700;
    font-size:clamp(2.7rem,5.8vw,4.6rem);
    letter-spacing:-.015em;
  }
  .hero h1 .line{display:block;}
  .hero h1 .accent{color:var(--orange);}
  .hero .sub{margin-top:26px;max-width:480px;font-size:1.15rem;color:var(--ink-70);}
  .hero .cta-row{display:flex;flex-wrap:wrap;gap:14px;margin-top:38px;align-items:center;}
  .hero .award{display:flex;align-items:center;gap:10px;margin-top:34px;font-size:1rem;color:var(--ink-70);font-weight:600;text-decoration:none;transition:color .2s var(--ease);}
  .hero .award:hover{color:var(--orange-dark);}
  .hero .award svg{width:20px;height:20px;color:var(--orange);flex:none;}

  /* single hero artwork + stamp badge (replaces the old post-it collage).
     On desktop, top/height/right are set by sizeHeroArt() in main.js so the
     frame's top edge lines up with the h1 and its bottom edge lines up with
     the .sub paragraph beneath it — width just follows from the image's own
     aspect ratio at that height, so the whole photo shows uncropped in the
     normal case. If the text column runs tall (a longer headline/subtitle),
     that height-driven width could otherwise grow enough to run into the
     text — max-width is also set by JS, capped to whatever's left after the
     text column plus a guaranteed gap. When that cap actually bites, the
     frame's box briefly isn't 1290:900 anymore; object-fit:cover trims the
     photo's edges to fill it rather than showing paper-colored letterbox
     bars — a slight crop reads far better than that. Below the 980px
     breakpoint that JS backs off (see the media query) and this reverts to
     a plain static box sized by aspect-ratio instead. */
  .hero-art{position:absolute;top:0;right:0;height:100%;max-width:100%;}
  .hero-art .frame{
    background:var(--paper-dim);
    height:100%;width:auto;max-width:100%;overflow:hidden;
    aspect-ratio:1290/900; /* sizing hint only, so width isn't 0 before the image has loaded */
  }
  .hero-art .frame img{width:100%;height:100%;object-fit:cover;display:block;}
  .stamp{
    display:none; /* "OPEN FOR WORK" badge — turned off for now, not removed. Delete this line to bring it back. */
    position:absolute;width:150px;height:150px;left:-46px;bottom:-40px;
    transform:rotate(-10deg);color:var(--ink);
  }
  .stamp .ring{fill:none;stroke:var(--ink);stroke-width:2;stroke-dasharray:2.6 5;}
  .stamp .ring-inner{fill:var(--paper);stroke:var(--ink);stroke-width:1.2;}
  .stamp text{
    font-family:var(--font-b);font-weight:800;font-size:17px;letter-spacing:.5px;
    fill:var(--ink);
  }
  .stamp .star{fill:var(--orange);}

  /* Hand cursor toggle — a tiny label-switch-label control, tucked into
     the empty space below the hero photo (which stops at the .sub
     paragraph, see .hero-art above). top is set by main.js to line up
     with the .award row. Desktop-only by design (a swapped cursor image
     means nothing without a cursor to swap) — hidden outright below the
     980px breakpoint, see the media query further down. */
  .hand-toggle{
    display:inline-flex;align-items:center;gap:7px;margin-top:16px;
    background:none;border:none;padding:0;cursor:pointer;
    font-family:var(--font-b);font-weight:600;font-size:.7rem;letter-spacing:.02em;
    color:var(--ink-30);opacity:.7;
    transition:opacity .2s var(--ease), color .2s var(--ease);
  }
  .hand-toggle:hover{opacity:1;}
  .hand-toggle-track{
    position:relative;flex:none;width:26px;height:14px;border-radius:100px;
    background:var(--ink-14);
    transition:background .2s var(--ease);
  }
  .hand-toggle-knob{
    position:absolute;top:2px;left:2px;width:10px;height:10px;border-radius:50%;
    background:var(--ink-55);
    transition:transform .2s var(--ease), background .2s var(--ease);
  }
  .hand-toggle.is-active .hand-toggle-track{background:var(--ink-30);}
  .hand-toggle.is-active .hand-toggle-knob{transform:translateX(12px);background:var(--ink);}

  /* The custom cursor image itself, plus the override that hides the real
     one while it's active. !important on the descendant rule is needed
     because plenty of elements (buttons, links, photos…) set their own
     explicit `cursor` — without it those would win over the inherited
     `none` on body and the native pointer would show through alongside
     the hand icon. */
  .hand-cursor{
    position:fixed;top:-100px;left:-100px;z-index:10001;
    width:34px;height:34px;transform:translate(-50%,-50%);
    pointer-events:none;display:none;
  }
  body.hand-cursor-active{cursor:none;}
  body.hand-cursor-active .hand-cursor{display:block;}
  body.hand-cursor-active *{cursor:none !important;}

  @media(max-width:980px){
    .hero .wrap{grid-template-columns:1fr;}
    /* sizeHeroArt() (main.js) backs off below this breakpoint and clears its
       inline top/height/right — this reverts to a plain stacked box. */
    .hero-art{position:static;max-width:280px;height:auto;margin:8px auto 56px;}
    .hero-art .frame{aspect-ratio:1290/900;width:100%;height:auto;}
    .hero-art .frame img{width:100%;height:100%;object-fit:cover;}
    .stamp{width:120px;height:120px;left:-30px;bottom:-30px;}
    /* Not just "not positioned for desktop" — actually not shown at all.
       No cursor to swap on a touchscreen. */
    .hand-toggle{display:none;}
  }
  @media(min-width:981px){
    .hand-toggle{position:absolute;right:0;margin-top:0;}
  }
  @media(max-width:560px){
    .hero{padding-top:172px;}
  }

  /* wave banner — two angled, scroll-driven lines of repeating skill text,
     stacked (top:38%/62%) rather than one — see the comment on buildWaveLines()
     in main.js for why, and keep that split roughly matched to its rowGap. */
  .wave-section{position:relative;height:70px;overflow:hidden;background:var(--paper);}
  .wave-line{
    position:absolute;top:38%;left:-15%;width:130%;
    transform:translateY(-50%) rotate(-8deg) translateX(var(--wave-x,0px));
    white-space:nowrap;
    font-family:var(--font-hero);font-weight:800;
    font-size:clamp(1.8rem,4vw,3.2rem);
    letter-spacing:.01em;
    color:var(--orange);
  }
  .wave-line-2{top:62%;}
  @media(max-width:640px){
    .wave-section{height:55px;}
    .wave-line{font-size:clamp(1.1rem,6vw,1.8rem);top:34%;transform:translateY(-50%) rotate(-5deg) translateX(var(--wave-x,0px));}
    .wave-line-2{top:66%;}
  }

  /* No top padding (sits right against the wave banner above it) and no
     bottom padding either — the last case (Otto) already provides its own
     bottom padding via .case, and stacking the section's own on top of that
     was doubling up the gap before the Otto/Photography divider. */
  #work{padding-top:0;padding-bottom:0;}
  /* Matches .case's own top padding (below) rather than the default section
     padding, so the gap either side of the Otto/Photography divider reads
     the same as the gap between any two cases. */
  #photography{padding-top:88px;}

  /* ---------------------------------------------------------
     CASE STUDIES
  --------------------------------------------------------- */
  .case{padding:88px 0;border-bottom:2px solid var(--ink-14);}
  .case-top{margin-bottom:40px;}
  .case-title h3{font-size:clamp(2rem,4vw,2.9rem);margin-bottom:10px;}
  .case-title .tag{margin-bottom:0;}
  .case-lead{max-width:520px;font-size:1.08rem;color:var(--ink-70);margin-top:16px;}
  .case-links{display:flex;flex-wrap:wrap;gap:12px 24px;margin-top:26px;}
  .case-links a{font-size:1rem;}

  .gallery{display:grid;gap:14px;margin-bottom:40px;}
  .gallery img{width:100%;height:100%;object-fit:cover;border:1px solid var(--ink-14);background:var(--paper-dim);}
  .gallery-2{grid-template-columns:1.3fr 1fr;}
  .gallery-2 img{height:420px;}
  .gallery-3{grid-template-columns:repeat(3,1fr);}
  .gallery-3 img{height:300px;}
  .gallery-4{grid-template-columns:repeat(4,1fr);grid-auto-rows:220px;}
  .gallery-4 img:first-child{grid-column:span 2;grid-row:span 2;}
  .gallery-1{grid-template-columns:1fr;}
  .gallery-1 img{height:380px;}
  .gallery-43{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px;margin-bottom:40px;}
  .gallery-43 img, .gallery-43 video{width:100%;aspect-ratio:4/3;object-fit:cover;border:1px solid var(--ink-14);background:var(--paper-dim);}
  @media(max-width:760px){
    .gallery-2{grid-template-columns:1fr;}
    .gallery-2 img{height:260px;}
    .gallery-3{grid-template-columns:1fr 1fr;}
    .gallery-3 img{height:200px;}
    .gallery-4{grid-template-columns:1fr 1fr;grid-auto-rows:150px;}
    .gallery-1 img{height:240px;}
  }

  /* image carousel — one continuous row of images, peeking at the edge of
     the viewport when they don't all fit, rather than paged into discrete
     screens (which left a blank gap whenever the next photo didn't fully
     fit). Next/dots scroll exactly to the photo that was peeking in — see
     computeStops() in main.js. */
  .carousel{margin-bottom:40px;}
  .carousel-viewport{position:relative;}
  .carousel-track{
    display:flex;overflow-x:auto;scroll-behavior:smooth;
    scrollbar-width:none;-ms-overflow-style:none;
    /* Matches .cluster img/video height below so the carousel reserves its
       real space immediately instead of sitting collapsed at 0 height while
       photos are still being discovered (see buildAutoCarousel in main.js). */
    min-height:371px;
  }
  @media(max-width:640px){.carousel-track{min-height:211px;}}
  .carousel-track::-webkit-scrollbar{display:none;}
  /* fixed row height, natural width — every image in a cluster matches height
     (so the carousel never varies in height as you scroll), but each keeps
     its own aspect ratio instead of being force-cropped into identical
     boxes. No min-width: every image here is only ever created after being
     confirmed to exist (see buildAutoCarousel in main.js), so there's no
     "missing image" case to size a fallback for — and a min-width would
     force narrower-than-usual photos wider than their natural ratio,
     cropping their top/bottom to compensate. */
  .cluster{display:flex;gap:14px;}
  .cluster img, .cluster video{
    flex:none;height:371px;width:auto;
    object-fit:cover;border:1px solid var(--ink-14);background:var(--paper-dim);
  }
  @media(max-width:640px){.cluster img, .cluster video{height:211px;}}
  .carousel-arrow{
    position:absolute;top:50%;transform:translateY(-50%);
    width:40px;height:40px;border-radius:50%;padding:0;
    display:flex;align-items:center;justify-content:center;
    background:var(--paper);border:1.5px solid var(--ink-14);
    font-size:1.4rem;line-height:1;color:var(--ink);cursor:pointer;
    box-shadow:0 6px 16px rgba(21,22,26,.14);
    transition:background .2s var(--ease), color .2s var(--ease), opacity .2s var(--ease);
    z-index:2;
  }
  .carousel-arrow.prev{left:10px;}
  .carousel-arrow.next{right:10px;}
  .carousel-arrow:hover{background:var(--ink);color:var(--paper);}
  .carousel-arrow:disabled{opacity:0;pointer-events:none;}
  .carousel-nav{display:flex;justify-content:center;gap:8px;margin-top:18px;}
  .carousel-nav:empty{display:none;}
  .carousel-dot{
    width:8px;height:8px;border-radius:50%;padding:0;border:none;
    background:var(--ink-14);cursor:pointer;
    transition:background .2s var(--ease), transform .2s var(--ease);
  }
  .carousel-dot:hover{background:var(--ink-30);}
  .carousel-dot.active{background:var(--ink);transform:scale(1.3);}

  .case-body{display:grid;grid-template-columns:1fr 1fr;gap:56px;}
  .case-body .prose p{color:var(--ink-70);}
  .case-body .prose h4{font-size:1rem;margin:0 0 8px;font-weight:700;}
  blockquote{
    margin:0;padding:22px 0 0;border-top:2px solid var(--ink);
  }
  blockquote p{font-family:var(--font-b);font-weight:600;font-size:1.28rem;line-height:1.32;font-style:normal;color:var(--ink);}
  blockquote cite{display:block;margin-top:14px;font-style:normal;font-size:1rem;font-weight:700;color:var(--ink-55);}
  @media(max-width:820px){.case-body{grid-template-columns:1fr;gap:30px;}}

  /* Figma prototype embed (Down the Sneaker Hole) — 5:4 with scaling=contain
     in the embed URL is a deliberately-tuned combination: Figma's embed
     player only fills the box you give it up to the prototype's own pixel
     size unless scaling=contain is set, and even then a mismatched aspect
     ratio still leaves it letterboxed. 5:4 is what this specific prototype's
     frame is closest to — if you swap in a different Figma file, both the
     ratio here and the scaling param in the iframe's src may need retuning
     the same way (drop the iframe into a standalone test page and try a few
     heights) to get it filling the box again. */
  .figma-embed{position:relative;aspect-ratio:5/4;border:1px solid var(--ink-14);overflow:hidden;background:var(--paper-dim);}
  .figma-embed iframe{position:absolute;inset:0;width:100%;height:100%;border:none;}

  .video-frame{position:relative;padding-top:56.25%;border:1px solid var(--ink-14);background:var(--ink);}
  .video-frame iframe{position:absolute;inset:0;width:100%;height:100%;border:none;}
  /* fallback for videos with embedding disabled by the owner (YouTube error 153) —
     a clickable thumbnail that opens the video on YouTube instead */
  .video-frame.video-frame-fallback{display:block;text-decoration:none;}
  .video-frame-fallback img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}
  .video-play{
    position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
    width:72px;height:72px;border-radius:50%;
    background:rgba(21,22,26,.75);
    display:flex;align-items:center;justify-content:center;
    transition:background .2s var(--ease), transform .2s var(--ease);
  }
  .video-play svg{width:26px;height:26px;fill:var(--paper);margin-left:3px;}
  .video-frame-fallback:hover .video-play{background:var(--orange);transform:translate(-50%,-50%) scale(1.08);}

  /* browser-window mockup (Unlucky Otto) */
  .browser-window{
    max-width:640px;margin:0 auto 40px;
    border:1px solid var(--ink-14);border-radius:12px;overflow:hidden;
    background:var(--paper-dim);
  }
  /* Otto's site is built for a full 1920x1080 browser window (fixed-resolution
     art assets, vh/vw layout), but the actual character+buttons artwork only
     occupies a small, roughly 384x690 region of that canvas (measured directly
     from the rendered page) — centered near x:776-1160, y:228-918. Rather than
     showing the whole mostly-blank 1920x1080 canvas shrunk down, the iframe is
     rendered at native size and then scaled+translated so a 16:9 crop centered
     on that content region fills the window — see sizeOttoFrame() in main.js.
     If Otto's art ever moves, these numbers need remeasuring. */
  .browser-frame-scale{position:relative;width:100%;aspect-ratio:16/9;overflow:hidden;background:var(--white);}
  .browser-frame{
    position:absolute;top:0;left:0;
    width:1920px;height:1080px;border:none;
    transform-origin:0 0;
    transform:scale(var(--otto-scale, .2)) translate(-248px,-168px);
  }

  /* more work strip */
  .more-strip{display:grid;grid-template-columns:1fr 1fr;gap:2px;background:var(--ink-14);border:2px solid var(--ink-14);margin-top:64px;}
  .more-card{background:var(--paper-dim);padding:32px;display:flex;flex-direction:column;justify-content:space-between;min-height:200px;}
  .more-card h5{font-family:var(--font-d);font-weight:700;font-size:1.15rem;margin-bottom:10px;}
  .more-card p{font-size:1rem;color:var(--ink-70);margin-bottom:16px;}
  .more-card ul{display:flex;flex-direction:column;gap:8px;}
  .more-card .link-arrow{font-size:1rem;}
  @media(max-width:820px){.more-strip{grid-template-columns:1fr;}}

  /* ---------------------------------------------------------
     PHOTOGRAPHY — a set of small sub-sections (event/portrait/misc),
     each just a short label + line of text above its own auto-discovery
     carousel (see .carousel / .cluster above, and buildAutoCarousel in
     main.js — the same machinery St Joseph etc. use).
  --------------------------------------------------------- */
  .photo-sub{margin-bottom:56px;}
  .photo-sub:last-child{margin-bottom:0;}
  .photo-sub h3{font-family:var(--font-d);font-weight:700;font-size:1.3rem;margin-bottom:6px;}
  .photo-sub p{font-size:1rem;color:var(--ink-70);max-width:520px;margin-bottom:22px;}

  /* ---------------------------------------------------------
     ABOUT
  --------------------------------------------------------- */
  .about-grid{display:grid;grid-template-columns:.8fr 1.2fr;gap:64px;}
  .about-photo{position:relative;}
  .about-photo img{width:100%;border:1px solid var(--ink-14);}
  .about-photo figcaption{margin-top:12px;font-size:1rem;color:var(--ink-55);}
  .about-copy h2{font-size:clamp(2.1rem,4.4vw,3.2rem);margin-bottom:20px;}
  .about-copy p{color:var(--ink-70);font-size:1.05rem;}
  .about-copy .lede{font-family:var(--font-b);font-weight:600;font-size:1.5rem;color:var(--ink);line-height:1.35;margin-bottom:22px;}
  .chips{display:flex;flex-wrap:wrap;gap:10px;margin-top:26px;}

  .timeline-cols{display:grid;grid-template-columns:1fr 1fr;gap:40px;margin-top:56px;}
  .timeline-cols h4{font-size:1.05rem;margin-bottom:20px;padding-bottom:12px;border-bottom:2px solid var(--ink);}
  .tl-item{padding:16px 0;border-bottom:1px solid var(--ink-14);}
  .tl-item:last-child{border-bottom:none;}
  .tl-item .role{font-weight:700;font-size:1.05rem;}
  .tl-item .org{color:var(--ink-70);font-size:1.02rem;}
  .tl-item .yr{color:var(--ink-55);font-size:1rem;font-weight:600;margin-top:4px;}
  @media(max-width:900px){.about-grid{grid-template-columns:1fr;}.timeline-cols{grid-template-columns:1fr;gap:36px;}}

  /* ---------------------------------------------------------
     CONTACT
  --------------------------------------------------------- */
  #contact{background:var(--paper-dim);}
  .contact-inner{text-align:left;}
  #contact h2{font-size:clamp(2.6rem,6.5vw,4.6rem);max-width:820px;}
  #contact .sub{max-width:480px;color:var(--ink-70);font-size:1.1rem;margin-top:22px;}
  .contact-grid{display:flex;flex-direction:column;gap:32px;margin-top:56px;}

  /* ---------------------------------------------------------
     CURSOR TRAIL — a light scatter of random characters that
     follows the pointer. See main.js for the spawn logic.
  --------------------------------------------------------- */
  .cursor-trail-layer{position:fixed;inset:0;overflow:hidden;pointer-events:none;z-index:9000;}
  .cursor-trail-char{
    position:fixed;left:0;top:0;
    transform:translate(-50%,-50%) rotate(var(--rot,0deg));
    font-family:'Courier New',ui-monospace,monospace;
    font-size:13px;font-weight:700;
    color:var(--ink-30);
    will-change:transform,opacity;
    animation:cursor-trail-fade .9s var(--ease) forwards;
  }
  @keyframes cursor-trail-fade{
    0%{opacity:.85;transform:translate(-50%,-50%) rotate(var(--rot,0deg)) translateY(0) scale(1);}
    100%{opacity:0;transform:translate(-50%,-50%) rotate(var(--rot,0deg)) translateY(var(--drift,-14px)) scale(.8);}
  }

  /* ---------------------------------------------------------
     IMAGE LOADING OVERLAY — a small ring spinner shown over a
     photo while it loads, its ring spelling out "BAS" as it
     spins. Wired up per-image in main.js (attachImageLoader).
  --------------------------------------------------------- */
  .img-loader-wrap{display:block;position:relative;}
  .img-loader-overlay{
    position:absolute;inset:0;z-index:1;
    display:flex;align-items:center;justify-content:center;
    background:var(--paper-dim);
    transition:opacity .35s var(--ease);
    pointer-events:none;
  }
  .img-loader-overlay.is-hidden{opacity:0;}
  .img-loader-ring{width:34px;height:34px;animation:img-loader-spin 1.8s linear infinite;}
  .img-loader-ring text{font-size:9.5px;font-weight:700;letter-spacing:3.5px;fill:var(--ink-30);}
  @keyframes img-loader-spin{to{transform:rotate(360deg);}}

  /* ---------------------------------------------------------
     LIGHTBOX — click any photo to see it larger. See main.js for
     the click-delegation and open/close logic.
  --------------------------------------------------------- */
  #work img, .hero-art img, .about-photo img{cursor:zoom-in;}
  #work .video-frame-fallback img{cursor:pointer;}
  .lightbox-overlay{
    position:fixed;inset:0;z-index:10000;
    display:flex;align-items:center;justify-content:center;
    padding:60px;
    background:rgba(21,22,26,.92);
    opacity:0;visibility:hidden;
    transition:opacity .25s var(--ease), visibility 0s linear .25s;
  }
  .lightbox-overlay.is-open{opacity:1;visibility:visible;transition:opacity .25s var(--ease);}
  .lightbox-img{max-width:100%;max-height:100%;object-fit:contain;box-shadow:0 20px 60px rgba(0,0,0,.4);}
  .lightbox-close{
    position:fixed;top:24px;right:24px;
    width:44px;height:44px;border-radius:50%;padding:0;
    display:flex;align-items:center;justify-content:center;
    background:var(--paper);border:none;color:var(--ink);cursor:pointer;
    box-shadow:0 6px 20px rgba(0,0,0,.25);
    transition:background .2s var(--ease), color .2s var(--ease), transform .2s var(--ease);
  }
  .lightbox-close svg{width:18px;height:18px;}
  .lightbox-close:hover{background:var(--orange);color:var(--white);transform:scale(1.06);}
  /* Prev/next only show on wide-enough screens with room either side of the
     photo — narrower viewports still get swipe and (on a keyboard) the
     arrow keys, just no on-screen buttons. Hidden outright unless the open
     photo actually belongs to a group of more than one. */
  .lightbox-nav-btn{
    display:none;position:fixed;top:50%;transform:translateY(-50%);
    width:52px;height:52px;border-radius:50%;padding:0;
    align-items:center;justify-content:center;
    background:var(--paper);border:none;color:var(--ink);cursor:pointer;
    font-size:1.8rem;line-height:1;
    box-shadow:0 6px 20px rgba(0,0,0,.25);
    transition:background .2s var(--ease), color .2s var(--ease), opacity .2s var(--ease);
  }
  .lightbox-prev{left:28px;}
  .lightbox-next{right:28px;}
  .lightbox-nav-btn:hover{background:var(--orange);color:var(--white);}
  .lightbox-nav-btn:disabled{opacity:0;pointer-events:none;}
  @media(min-width:900px){
    .lightbox-overlay.has-multiple .lightbox-nav-btn{display:flex;}
  }
  body.lightbox-locked{overflow:hidden;}
  @media(max-width:640px){
    .lightbox-overlay{padding:20px;}
    .lightbox-close{top:14px;right:14px;}
  }
  .contact-main a.mail{
    font-family:var(--font-d);font-weight:800;font-size:clamp(1.6rem,3.6vw,2.6rem);
    text-decoration:none;border-bottom:3px solid var(--orange);display:inline-block;word-break:break-word;
  }
  .contact-main a.mail:hover{color:var(--orange-dark);}
  .contact-details{display:flex;flex-direction:column;gap:18px;}
  .contact-details .row{display:flex;align-items:center;gap:12px;}
  .contact-details svg{width:20px;height:20px;color:var(--ink-55);flex:none;}
  .contact-details a{text-decoration:none;font-weight:600;}
  .contact-details a:hover{color:var(--orange-dark);}

  /* ---------------------------------------------------------
     FOOTER
  --------------------------------------------------------- */
  footer{border-top:2px solid var(--ink);padding:38px 0;}
  footer .wrap{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:16px;}
  footer .fbrand{font-family:var(--font-d);font-weight:700;}
  footer .socials{display:flex;gap:18px;}
  footer .socials a{color:var(--ink-55);}
  footer .socials a:hover{color:var(--orange);}
  footer .socials svg{width:20px;height:20px;}
  footer .fyear{color:var(--ink-55);font-size:1rem;}

  ::selection{background:var(--lime);color:var(--ink);}

  img.img-broken{
    object-fit:none !important;
    background:
      repeating-linear-gradient(135deg, var(--paper-dim), var(--paper-dim) 10px, var(--paper) 10px, var(--paper) 20px);
  }
