    body { background-color: var(--bg-off); position: relative; }
    html.skip-splash { scroll-behavior: auto; }
    html.skip-splash [style*="z-index: 9999"] { display: none !important; }
    #work { scroll-margin-top: var(--nav-height); }


    /* Liquid-glass pill. Replaces the full-width band + hairline rule:
       the pill is the anchor now, so the old border-bottom goes. */
    .section-label {
      display: inline-block;
      color: var(--black);
      padding: 11px 22px;
      border: 1px solid color-mix(in srgb, var(--black) 12%, transparent);
      border-radius: 980px;                       /* matches .skill-tag */
      background: color-mix(in srgb, var(--bg-off) 55%, transparent);
      -webkit-backdrop-filter: blur(16px) saturate(180%);
      backdrop-filter: blur(16px) saturate(180%);
      box-shadow:
        0 1px 2px rgb(0 0 0 / .05),
        0 10px 28px rgb(0 0 0 / .07),
        inset 0 1px 0 rgb(255 255 255 / .75);     /* top highlight = the "glass" */
    }
    [data-theme=dark] .section-label {
      border-color: rgb(255 255 255 / .12);
      box-shadow:
        0 1px 2px rgb(0 0 0 / .4),
        0 10px 28px rgb(0 0 0 / .35),
        inset 0 1px 0 rgb(255 255 255 / .08);
    }

    /* Desktop-style draggable icons */
    .desktop-icon {
      position: absolute;   /* scrolls away with the hero */
      z-index: 50;
      opacity: 0;           /* revealed behind the splash, so they're in place when it lifts */
      pointer-events: none;
      cursor: grab;
      /* Touch pans the page over icons (they only drag with a mouse); double-tap
         zoom stays off so double-tap opens Quick Look. Ignored for mouse input. */
      touch-action: manipulation;
      user-select: none;
      -webkit-user-drag: none;
      -webkit-touch-callout: none;  /* iOS: no "Save Image" sheet on long-press */
      filter: drop-shadow(0 6px 14px rgb(0 0 0 / .25));
    }
    body.desk-on .desktop-icon {
      opacity: 1;
      pointer-events: auto;
      animation: desk-in .45s cubic-bezier(.32,1.4,.52,1) both;
    }
    @keyframes desk-in { from { opacity: 0; transform: scale(.92) translateY(8px) } to { opacity: 1 } }
    .desktop-icon:active { cursor: grabbing; }
    /* Finder's selected-icon look: darker, bluer */
    .desktop-icon.selected {
      filter: drop-shadow(0 6px 14px rgb(0 0 0 / .25)) brightness(.82) saturate(1.4) hue-rotate(-8deg);
    }

    /* Scattered desktop defaults. 100vw/svh, not % — body is wider than the
       viewport, so a % left would sit off-screen. */
    #desktop-folder { left: 2.3vw; top: 13.9svh; }
    .desktop-icon[data-full$="5494.jpg"] { left: 9.7vw; top: 31.5svh; }
    .desktop-icon[data-full$="5496.jpg"] { left: 2.3vw; top: 51.1svh; }
    .desktop-icon[data-full*="Psychiatric"] { left: 22.5vw; top: 78.5svh; }
    .desktop-icon[data-full$="resume.pdf"] { left: 32.2vw; top: 78.5svh; }
    .desktop-icon[data-full$="chicago.mp4"] { left: 61vw; top: 13.5svh; }
    .desktop-icon[data-full$=".mp3"] { left: 84.8vw; top: 49.7svh; }
    .desktop-icon[data-full="/videos/go.mp4"] { left: 69.2vw; top: 84.7svh; }
    /* Song name wraps at spaces, not mid-letter like the photo filenames. */
    .desktop-icon[data-full$=".mp3"] figcaption {
      word-break: normal;
      overflow-wrap: break-word;
    }
    #desktop-folder img {
      width: 80px;
      max-width: none;
      max-height: none;
    }

    /* Image files: Finder renders the photo itself, name underneath */
    .desktop-file {
      margin: 0;
      width: 92px;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 5px;
    }
    .desktop-file img {
      display: block;
      max-width: 72px;
      max-height: 80px;
      border-radius: 6px;
    }
    .desktop-file figcaption {
      font: 500 11.5px/1.25 var(--sans);
      color: #fff;
      text-align: center;
      padding: 1px 5px;
      border-radius: 4px;
      /* White-on-shadow, like Finder — the only pairing that survives both the
         dark hero and the white sections further down the page. */
      text-shadow: 0 1px 3px rgb(0 0 0 / .9), 0 0 2px rgb(0 0 0 / .8);
      word-break: break-all;
    }
    /* Selection tints the thumbnail and pills the filename, same as Finder */
    .desktop-file.selected { filter: drop-shadow(0 6px 14px rgb(0 0 0 / .25)); }
    .desktop-file.selected img { filter: brightness(.86) saturate(1.15); }
    .desktop-file.selected figcaption {
      background: var(--accent);
      color: #fff;
      text-shadow: none;
    }

    /* PDF: page 1 as the icon */
    .pdf-icon {
      display: block;
      width: 56px;
      height: 72px;
      overflow: hidden;
      background: #fff;
      border-radius: 2px;
    }
    .pdf-icon img {
      width: 56px;
      height: 72px;
      max-width: none;
      max-height: none;
      object-fit: cover;
      object-position: top;
    }
    .desktop-pdf { width: 108px; }
    .desktop-pdf figcaption {
      word-break: normal;
      overflow-wrap: break-word;
    }
    .desktop-pdf.selected img { filter: none; }
    .desktop-pdf.selected .pdf-icon { filter: brightness(.86); }

    /* Quick Look — liquid glass, same vocabulary as .section-label: a tinted
       translucent fill, a hairline, and an inset top highlight for the specular
       edge. Dark tint throughout so photos, video and audio share one chrome. */
    #quicklook[hidden] { display: none; }
    #quicklook {
      position: fixed;
      inset: 0;
      z-index: 999;
      display: grid;
      place-items: center;
      padding: 48px 24px;
      /* Scrim lives on ::before so fading it doesn't put opacity on the
         panel — that traps the title bar's backdrop-filter and it flashes. */
      animation: none;
    }
    #quicklook::before {
      content: "";
      /* Cover behind the iOS toolbar: visual viewport (inset:0) stops short. */
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100vh;
      height: 100lvh;
      background: rgb(0 0 0 / .28);
      -webkit-backdrop-filter: blur(18px) saturate(140%);
      backdrop-filter: blur(18px) saturate(140%);
      animation: ql-in .3s cubic-bezier(.2,.8,.2,1);
      pointer-events: none;
    }
    @keyframes ql-in { from { opacity: 0 } }
    /* Child combinator: the folder view nests <figure> file cards inside this
       panel, and a descendant selector would paint each one as its own panel. */
    #quicklook > figure {
      position: relative;
      margin: 0;
      width: fit-content;
      max-width: 100%;
      max-height: 100%;
      display: flex;
      flex-direction: column;
      border-radius: 8px;
      overflow: hidden;
      background: rgb(28 28 30 / .52);
      -webkit-backdrop-filter: blur(40px) saturate(180%);
      backdrop-filter: blur(40px) saturate(180%);
      box-shadow:
        0 40px 90px -18px rgb(0 0 0 / .62),
        0 2px 10px rgb(0 0 0 / .3),
        inset 0 0 0 .5px rgb(255 255 255 / .11),    /* hairline */
        inset 0 1px 0 rgb(255 255 255 / .2);        /* specular top edge */
      /* Overshoot past 1 and settle: the panel pops rather than fades in. */
      animation: ql-pop .44s cubic-bezier(.32,1.5,.52,1);
    }
    @keyframes ql-pop {
      from { transform: scale(.9) translateY(12px); opacity: 0; filter: blur(6px) }
    }
    /* Sheen: one soft diagonal wipe across the glass, above the content but
       inert. Kept at 7% so it reads as a highlight, not a scrim over photos. */
    #quicklook > figure::after {
      content: "";
      position: absolute;
      inset: 0;
      z-index: 5;
      pointer-events: none;
      border-radius: inherit;
      background: linear-gradient(148deg, rgb(255 255 255 / .07), transparent 46%);
    }
    /* Toolbar: round glass buttons, then the filename in bold — Quick Look's
       own chrome, left-aligned like the reference. */
    #quicklook > figure > figcaption {
      position: relative;
      z-index: 6;
      flex: none;
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 11px 12px;
      font: 700 15px/1.2 var(--sans);
      letter-spacing: -.015em;
      color: #fff;
      border-bottom: .5px solid rgb(255 255 255 / .1);
    }
    #ql-name {
      flex: 1;
      min-width: 0;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }
    #ql-page {
      flex: none;
      font: 500 13px/1 var(--sans);
      font-variant-numeric: tabular-nums;
      color: rgb(255 255 255 / .62);
    }
    #ql-page[hidden] { display: none; }
    #ql-close {
      flex: none;
      width: 12px;
      height: 12px;
      padding: 0;
      border: .5px solid rgb(0 0 0 / .28);
      border-radius: 50%;
      background: #ff5f57;
      box-shadow: inset 0 .5px 0 rgb(255 255 255 / .28);
      cursor: pointer;
      transition: scale .15s;
    }
    #ql-close:active { scale: .9; }
    /* Opaque photos/video flatten the panel's backdrop-filter, so the title
       bar goes solid. Glass the caption itself and let the media sit below. */
    #quicklook > figure:has(#ql-img:not([hidden])),
    #quicklook > figure:has(#ql-video:not([hidden])),
    #quicklook > figure:has(#ql-pdf:not([hidden])) {
      overflow: visible;
      background: transparent;
      -webkit-backdrop-filter: none;
      backdrop-filter: none;
      /* Don't fade this box: opacity (like transform) traps the caption's
         backdrop-filter, so the bar paints solid then flashes to glass. */
      animation: none;
      box-shadow: 0 40px 90px -18px rgb(0 0 0 / .62), 0 2px 10px rgb(0 0 0 / .3);
    }
    #quicklook > figure:has(#ql-img:not([hidden]))::after,
    #quicklook > figure:has(#ql-video:not([hidden]))::after,
    #quicklook > figure:has(#ql-pdf:not([hidden]))::after { display: none; }
    #quicklook > figure:has(#ql-img:not([hidden])) > figcaption,
    #quicklook > figure:has(#ql-video:not([hidden])) > figcaption,
    #quicklook > figure:has(#ql-pdf:not([hidden])) > figcaption {
      border-radius: 8px 8px 0 0;
      background: rgb(28 28 30 / .52);
      -webkit-backdrop-filter: blur(40px) saturate(180%);
      backdrop-filter: blur(40px) saturate(180%);
      box-shadow:
        inset 0 0 0 .5px rgb(255 255 255 / .11),
        inset 0 1px 0 rgb(255 255 255 / .2);
    }
    /* The credit rides at the foot of the photo itself — no bottom bar — on a
       gradient so it stays legible over a bright frame. */
    #ql-credit {
      position: absolute;
      z-index: 6;
      left: 0;
      right: 0;
      bottom: 0;
      padding: 32px 14px 11px;
      font: 500 12px/1.3 var(--sans);
      letter-spacing: -.01em;
      color: rgb(255 255 255 / .88);
      text-shadow: 0 1px 2px rgb(0 0 0 / .45);
      background: linear-gradient(transparent, rgb(0 0 0 / .52));
      border-radius: 0 0 8px 8px;
      pointer-events: none;
    }
    #ql-credit[hidden] { display: none; }
    #ql-pdf {
      position: relative;
      overflow: auto;
      overscroll-behavior: contain;
      flex: none;
      width: min(62vw, calc((100dvh - 160px) * .81));
      max-height: calc(100dvh - 160px);
      background: #fff;
      border-radius: 0 0 8px 8px;
    }
    #ql-pdf img { display: block; width: 100%; }
    #ql-img, #ql-video {
      display: block;
      border-radius: 0 0 8px 8px;
      /* Shrink-wrap to the media's aspect ratio so contain doesn't paint
         letterbox/pillarbox bars inside a too-wide flex child. */
      width: auto;
      height: auto;
      /* Don't shrink: as a flex item in this column panel the media's base size
         is its intrinsic height, and shrinking it drags the width down with the
         aspect ratio. Opting out leaves the two max-* rules as the only limits. */
      flex: none;
      max-width: min(76vw, 900px);
      /* Overlay padding (~96) + title bar (~52). Too tall and overflow:hidden
         on the figure clips the video's native control bar. */
      max-height: calc(100dvh - 160px);
      object-fit: contain;
    }
    #ql-video {
      max-width: min(92vw, 1280px);
    }

    /* display:block above beats the UA [hidden] rule, so restate it */
    #ql-img[hidden], #ql-video[hidden], #ql-folder[hidden], #ql-audio[hidden], #ql-pdf[hidden] { display: none; }

    /* Folder window: glass tiles that pop in one after another */
    #ql-folder {
      display: grid;
      grid-template-columns: repeat(2, 124px);
      justify-content: center;
      align-items: stretch;
      gap: 12px;
      padding: 20px;
    }
    #ql-folder .desktop-file {
      width: 124px;
      gap: 10px;
      padding: 14px 8px 12px;
      border-radius: 16px;
      background: rgb(255 255 255 / .05);
      box-shadow: inset 0 .5px 0 rgb(255 255 255 / .13);
      cursor: pointer;
      transition: background .22s, scale .3s cubic-bezier(.34,1.4,.5,1);
      /* backwards fill so the staggered tiles start invisible, not at full size */
      animation: ql-tile-pop .46s cubic-bezier(.32,1.5,.52,1) backwards;
    }
    @keyframes ql-tile-pop { from { scale: .82; opacity: 0 } }
    #ql-folder .desktop-file:nth-child(2) { animation-delay: .06s; }
    #ql-folder .desktop-file:nth-child(3) { animation-delay: .12s; }
    #ql-folder .desktop-file:nth-child(4) { animation-delay: .18s; }
    #ql-folder .desktop-file:hover,
    #ql-folder .desktop-file:focus-visible {
      background: rgb(255 255 255 / .13);
      outline: none;
      scale: 1.04;
    }
    #ql-folder .desktop-file:active { scale: .97; }
    #ql-folder .desktop-file img {
      max-width: 84px;
      max-height: 84px;
      border-radius: 8px;
      filter: drop-shadow(0 8px 16px rgb(0 0 0 / .35));
    }
    /* Caption sits on the glass here, not the wallpaper. break-all would split
       mid-token; these names are meant to wrap at their spaces. */
    #ql-folder figcaption {
      color: #fff;
      text-shadow: none;
      font: 600 12.5px/1.35 var(--sans);
      letter-spacing: -.01em;
      word-break: normal;
      overflow-wrap: break-word;
    }
    #ql-folder .dur {
      display: block;
      margin-top: 4px;
      font-weight: 500;
      color: rgb(255 255 255 / .5);
      font-variant-numeric: tabular-nums;
    }

    /* Audio Quick Look. The chrome is shared with the other views; what's local
       to audio is the floating glass controls — volume and transport each ride
       in their own pill rather than sitting flat on the panel. */
    #ql-open-music[hidden], #ql-download[hidden] { display: none; }
    #ql-open-music, #ql-download {
      flex: none;
      padding: 6px 13px;
      border-radius: 980px;
      background: rgb(255 255 255 / .15);
      box-shadow: inset 0 .5px 0 rgb(255 255 255 / .22);
      font: 600 12.5px/1 var(--sans);
      letter-spacing: -.01em;
      color: #fff;
      text-decoration: none;
    }
    #ql-open-music { pointer-events: none; }
    #ql-audio {
      display: flex;
      flex-direction: column;
      /* 48px = #quicklook's own horizontal padding. A plain vw here overshoots
         the panel, and the transport pill gets clipped on a phone. */
      width: min(calc(100vw - 48px), 700px);
      color: #fff;
      animation: ql-audio-in .4s cubic-bezier(.32,1.4,.52,1);
    }
    /* Runs on unhide, so stepping folder -> track pops the player in too */
    @keyframes ql-audio-in { from { scale: .96; opacity: 0 } }
    #ql-audio-main {
      display: grid;
      grid-template-columns: auto 1fr;
      gap: 26px;
      padding: 24px 20px 16px;
    }
    #ql-art {
      width: 208px;
      height: 208px;
      object-fit: cover;
      border-radius: 4px;
      background: #f2f2f2;
      box-shadow: 0 20px 44px rgb(0 0 0 / .45), inset 0 0 0 .5px rgb(0 0 0 / .06);
    }
    /* Volume pinned top-right; title / artist / album / time sit left, like Finder. */
    #ql-audio-side { display: flex; flex-direction: column; min-width: 0; }
    #ql-meta { margin: auto 0; min-width: 0; }
    #ql-title {
      margin: 0 0 10px;
      font: 700 22px/1.15 var(--sans);
      letter-spacing: -.02em;
      color: #fff;
    }
    #ql-meta .kv {
      margin: 3px 0 0;
      font: 500 16px/1.4 var(--sans);
      color: rgb(255 255 255 / .55);
      font-variant-numeric: tabular-nums;
    }
    #ql-meta .kv b { font-weight: 700; color: #fff; }

    /* The two glass pills */
    #ql-vol, #ql-transport {
      display: flex;
      align-items: center;
      border-radius: 980px;
      background: rgb(255 255 255 / .13);
      -webkit-backdrop-filter: blur(20px) saturate(180%);
      backdrop-filter: blur(20px) saturate(180%);
      box-shadow:
        0 2px 8px rgb(0 0 0 / .22),
        inset 0 0 0 .5px rgb(255 255 255 / .1),
        inset 0 .5px 0 rgb(255 255 255 / .22);
    }
    #ql-vol {
      align-self: flex-end;
      gap: 11px;
      padding: 9px 15px;
      color: #fff;
    }
    #ql-vol input { width: 124px; }
    #ql-transport {
      gap: 12px;
      margin: 0 14px 14px;
      padding: 7px 15px;
      font: 600 12.5px/1 var(--sans);
      letter-spacing: -.01em;
      color: rgb(255 255 255 / .62);
      font-variant-numeric: tabular-nums;
    }
    #ql-transport button {
      display: grid;
      place-items: center;
      flex: none;
      width: 32px;
      height: 32px;
      padding: 0;
      border: none;
      border-radius: 50%;
      background: transparent;
      color: #fff;
      cursor: pointer;
      transition: background .2s, scale .2s;
    }
    #ql-transport button:hover { background: rgb(255 255 255 / .15); }
    #ql-transport button:active { scale: .88; }
    #ql-transport text { font: 700 8.5px var(--sans); }
    #ql-play .i-pause, #ql-play[data-playing] .i-play { display: none; }
    #ql-play[data-playing] .i-pause { display: inline; }
    #ql-seek { flex: 1; min-width: 0; }

    /* --p is written from JS: the played portion is an opaque white layer sized
       over the translucent track, since neither browser fills a range for us. */
    #ql-audio input[type=range] {
      -webkit-appearance: none;
      appearance: none;
      height: 6px;
      border-radius: 980px;
      background:
        linear-gradient(#fff, #fff) left / var(--p, 0%) 100% no-repeat,
        rgb(255 255 255 / .2);
    }
    #ql-audio input[type=range]::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 16px;
      height: 16px;
      border: none;
      border-radius: 50%;
      background: #fff;
      box-shadow: 0 1px 4px rgb(0 0 0 / .4);
      cursor: pointer;
    }
    #ql-audio input[type=range]::-moz-range-thumb {
      width: 16px;
      height: 16px;
      border: none;
      border-radius: 50%;
      background: #fff;
      box-shadow: 0 1px 4px rgb(0 0 0 / .4);
    }

    @media (max-width: 560px) {
      #ql-audio-main { grid-template-columns: 1fr; justify-items: center; gap: 8px; padding: 18px; }
      #ql-art { width: min(100%, 240px); height: auto; aspect-ratio: 1; }
      #ql-vol { align-self: center; margin-bottom: 18px; }
      #ql-meta { margin: 0; text-align: center; }
      #ql-title { font-size: 20px; }
      #ql-transport { gap: 8px; padding: 7px 11px; }
      /* The duration is already spelled out in the Time readout above, so drop
         the repeat here — otherwise the seek bar shrinks to ~40px. */
      #ql-total { display: none; }
    }

    @media (prefers-reduced-motion: reduce) {
      #quicklook, #quicklook > figure, #ql-audio, #ql-folder .desktop-file { animation: none; }
      body.desk-on .desktop-icon { animation: none; opacity: 1; }
    }

    /* Phones: same icons, re-laid out into the empty sky above the dock so they
       don't sit on top of the hero. !important because the initial left/top are
       inline (the drag writes there too, so it wins once you actually move one). */
    @media (max-width: 900px) {
      .desktop-icon { width: 92px; }
      .desktop-file img { max-width: 72px; max-height: 66px; }
      .pdf-icon img { max-width: none; max-height: none; }
      /* Page margins in the PNG letterbox the text; zoom so the resume fills the paper. */
      .desktop-icon[data-full$="resume.pdf"] .pdf-icon img {
        transform: scale(1.18);
        transform-origin: center;
      }
      .desktop-file figcaption { font-size: 10.5px; }
      /* px, not %: body runs wider than the viewport here, so a % left lands
         off-screen. These three fit even a 320px phone. */
      #desktop-folder { left: 10px !important; top: 96px !important; }
      .desktop-icon[data-full] { top: 196px !important; }
      .desktop-icon[data-full*="Psychiatric"] { display: none; }
      .desktop-icon[data-full$="resume.pdf"] { left: 310px !important; top: calc(100svh - 148px) !important; }
      [data-full$="5494.jpg"] { left: 10px !important; }
      [data-full$="5496.jpg"] { left: 110px !important; }
      .desktop-icon[data-full$=".mp3"] { left: calc(100vw - 102px) !important; }
      /* Videos sit on the hero floor, under the photos / dock. */
      .desktop-icon[data-full$=".mp4"] { top: calc(100svh - 148px) !important; }
      [data-full$="chicago.mp4"] { left: 110px !important; }
      [data-full="/videos/go.mp4"] { left: 210px !important; }

      /* Photo/video Quick Look. The panel gets a definite width and the media
         fills it, rather than the panel shrink-wrapping the media — left to
         shrink-wrap, iOS resolves a tall photo to a fraction of its max-width (a
         933x1400 shot came out 159px wide on an iPhone) because the panel's width
         depends on the media whose height depends on the panel. The .85 pulls the
         media in from the screen edges; it's on both axes so the photo scales
         evenly whichever limit it hits. The 88px leaves headroom for the title
         bar so the video control strip isn't clipped by overflow:hidden. */
      #quicklook { padding: 12px 8px; }
      #quicklook > figure:has(#ql-img:not([hidden])),
      #quicklook > figure:has(#ql-video:not([hidden])),
      #quicklook > figure:has(#ql-pdf:not([hidden])) {
        width: calc((100vw - 16px) * .85);
      }
      #ql-img, #ql-video, #ql-pdf {
        width: 100%;
        max-width: none;
        max-height: calc((100dvh - 88px) * .85);
      }
      /* Full width: the transport pill needs every pixel it can get. Definite
         length rather than a % so the panel still shrink-wraps to it cleanly. */
      #ql-audio { width: calc(100vw - 16px); }
    }

    /* iPhone: remaining videos sit on the hero floor — chicago right, go left. */
    @media (max-width: 430px) {
      .desktop-icon[data-full$=".mp3"] { left: calc(100vw - 102px) !important; top: 96px !important; }
      .desktop-icon[data-full$="resume.pdf"] { left: 110px !important; top: calc(100svh - 148px) !important; }
      .desktop-icon[data-full$=".mp4"] { left: calc(100vw - 102px) !important; }
      .desktop-icon[data-full="/videos/go.mp4"] { left: 10px !important; }
    }

    .card-wrap--lines { cursor: pointer; }
    .card-wrap--lines .box8-track--b,
    .card-wrap--lines .ngc2-logo { display: none !important; }
    .card-wrap--lines::after,
    .card-wrap--lines .card::before,
    .card-wrap--lines .card::after {
      content: none !important;
      display: none !important;
      animation: none !important;
      background: none !important;
    }
    .card-wrap--lines .card { background: #e6e6e3; }
    .card-wrap--lines .ngc2-copy { color: #111; }
    .card-wrap--lines .box8-track img { filter: brightness(0); }
    .card-wrap--lines .ngc2-field canvas { filter: invert(1); }
    [data-theme=dark] .card-wrap--lines .card { background: #000; }
    [data-theme=dark] .card-wrap--lines .ngc2-copy { color: #f5f5f2; }
    [data-theme=dark] .card-wrap--lines .box8-track img { filter: brightness(0) invert(1); }
    [data-theme=dark] .card-wrap--lines .ngc2-field canvas { filter: none; }

    .card-wrap--tv .card__mock-video { object-fit: contain; }

    .card-wrap.card-wrap--tv .card,
    .card-wrap[href="/sayclip/"] .card {
      border-radius: .5rem;
    }

    .card-wrap[href="/sayclip/"] .card {
      background: #f6f6f8;
      border-color: rgb(0 0 0 / .08);
      container-type: inline-size;
      isolation: isolate;
    }
    .card-wrap[href="/sayclip/"] .card__img {
      position: absolute !important;
      inset: 0;
    }
    .card-wrap[href="/sayclip/"] .gradients-container {
      filter: blur(18px) saturate(2) !important;
    }
    .card-wrap[href="/sayclip/"] .gradients-container > div { animation-duration: 8s; }
    .card-wrap[href="/sayclip/"] .gradients-container > div:nth-child(1) { animation-duration: 10s; }
    .card-wrap[href="/sayclip/"] .gradients-container > div:nth-child(3),
    .card-wrap[href="/sayclip/"] .gradients-container > div:nth-child(4) { animation-duration: 12s; }
    .card-wrap[href="/sayclip/"] .card__img::before {
      content: "";
      position: absolute;
      inset: 10%;
      z-index: 1;
      border-radius: 50%;
      pointer-events: none;
      background:
        radial-gradient(circle at 38% 40%, #fff 0 14%, transparent 38%),
        radial-gradient(circle at 30% 62%, #5ad4f0 0 22%, transparent 52%),
        radial-gradient(circle at 66% 36%, #f090dc 0 24%, transparent 54%),
        radial-gradient(circle at 58% 70%, #ffb088 0 20%, transparent 50%);
      filter: blur(22px);
      animation: sayclip-orb 5s ease-in-out infinite;
    }
    @keyframes sayclip-orb {
      0%, 100% { transform: scale(1) rotate(0deg); }
      50% { transform: scale(1.08) rotate(16deg); }
    }
    @media (prefers-reduced-motion: reduce) {
      .card-wrap[href="/sayclip/"] .card__img::before { animation: none; }
    }
    .card-wrap[href="/sayclip/"] .card::after { display: none; }
    .card-wrap[href="/sayclip/"] .card-copy {
      color: #1d1d1f;
      text-shadow: none;
    }
    .sayclip-mark {
      position: absolute;
      inset: 0;
      z-index: 12;
      display: flex;
      align-items: center;
      margin: 0;
      padding: 0 8%;
      pointer-events: none;
    }
    .sayclip-mark img {
      display: block;
      width: 100%;
      height: auto;
    }
    .sayclip-dl {
      position: absolute;
      top: .85rem;
      right: .85rem;
      z-index: 14;
      display: inline-flex;
      align-items: center;
      gap: .32rem;
      height: 1.7rem;
      padding: 0 .7rem 0 .55rem;
      border: 0;
      border-radius: 980px;
      background: #1d1d1f;
      color: #fff;
      font: 600 .68rem/1 var(--sans);
      letter-spacing: .01em;
      white-space: nowrap;
      cursor: pointer;
      box-shadow: 0 1px 2px rgb(0 0 0 / .14);
    }
    .sayclip-dl:focus-visible { outline: 2px solid #0071e3; outline-offset: 2px; }
    .sayclip-dl svg { display: block; flex: none; }
    .sayclip-dl:hover { background: #000; }

    #ngc2-launch[hidden] { display: none; }
    #ngc2-launch {
      --launch-bg: #dcddd7;
      --launch-accent: #735600;
      position: fixed;
      inset: 0;
      z-index: 10000;
      display: grid;
      place-items: center;
      overflow: hidden;
      color: var(--launch-accent);
      background: #000;
      clip-path: var(--launch-clip);
      transition:
        clip-path .72s cubic-bezier(.65,0,.2,1),
        background-color .45s ease .2s;
    }
    [data-theme=dark] #ngc2-launch {
      --launch-bg: #090a08;
      --launch-accent: #ffc52b;
    }
    #ngc2-launch::before,
    #ngc2-launch::after {
      content: "";
      position: absolute;
      pointer-events: none;
    }
    #ngc2-launch::before {
      inset: -35%;
      opacity: 0;
      background:
        linear-gradient(color-mix(in srgb, var(--launch-accent) 11%, transparent) 1px, transparent 1px),
        linear-gradient(90deg, color-mix(in srgb, var(--launch-accent) 11%, transparent) 1px, transparent 1px);
      background-size: 44px 44px;
      transform: perspective(500px) rotateX(62deg) scale(1.4);
      transition: opacity .35s ease .25s;
    }
    #ngc2-launch::after {
      inset: 18px;
      opacity: 0;
      border: 1px solid color-mix(in srgb, var(--launch-accent) 30%, transparent);
      clip-path: polygon(0 0,70px 0,70px 1px,1px 1px,1px 70px,0 70px,0 0,100% 0,100% 70px,calc(100% - 1px) 70px,calc(100% - 1px) 1px,calc(100% - 70px) 1px,calc(100% - 70px) 0,100% 0,100% 100%,calc(100% - 70px) 100%,calc(100% - 70px) calc(100% - 1px),calc(100% - 1px) calc(100% - 1px),calc(100% - 1px) calc(100% - 70px),100% calc(100% - 70px),100% 100%,0 100%,0 calc(100% - 70px),1px calc(100% - 70px),1px calc(100% - 1px),70px calc(100% - 1px),70px 100%,0 100%);
      transition: opacity .3s ease .35s;
    }
    #ngc2-launch img {
      position: relative;
      z-index: 1;
      width: clamp(7rem, 14vw, 10rem);
      height: auto;
      display: block;
      opacity: 0;
      transform: scale(.72);
      filter: drop-shadow(0 0 28px color-mix(in srgb, var(--launch-accent) 18%, transparent));
      transition: opacity .3s ease .18s, transform .65s cubic-bezier(.2,.8,.2,1) .12s;
    }
    #ngc2-launch span {
      position: absolute;
      z-index: 1;
      right: 30px;
      bottom: 26px;
      opacity: 0;
      font: 600 10px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;
      letter-spacing: .18em;
      transition: opacity .3s ease .38s;
    }
    #ngc2-launch.is-launching { background: var(--launch-bg); clip-path: inset(0 round 0); }
    #ngc2-launch.is-launching::before,
    #ngc2-launch.is-launching::after,
    #ngc2-launch.is-launching img,
    #ngc2-launch.is-launching span { opacity: 1; }
    #ngc2-launch.is-launching img { transform: scale(1); }

    @media (prefers-reduced-motion: reduce) {
      #ngc2-launch { transition: none; }
    }


    /* The wallpaper is pinned to the viewport instead of ending with the hero,
       so it runs to the bottom of the page. The inline styles React sets
       are absolute, hence !important. */
    body:has(.desktop-icon) .min-h-screen > img,
    body:has(.desktop-icon) .min-h-screen > iframe,
    body:has(.desktop-icon) .min-h-screen > div:first-of-type {
      position: fixed !important;
    }
    /* first-of-type is the hero's 15% black scrim. Left absolute it ends with
       the hero, and its bottom edge reads as a seam across the pinned
       wallpaper once the page scrolls. */

    /* Second screen below the hero. Its wallpaper is pinned like the hero's and
       sits at the same depth, so it paints over the first one (later in the DOM)
       while the desktop icons at z-index 50 still scroll away above it. */
    #scene2 { position: relative; height: 100svh; }
    #scene2 > iframe {
      position: fixed;
      top: 50%;
      left: 50%;
      width: 100vw;
      height: 56.25vw;
      min-height: 100%;
      min-width: 177.78vh;
      transform: translate(-50%, -50%);
      border: 0;
      pointer-events: none;
      z-index: 0;
      opacity: 0;
      transition: opacity .6s ease;
    }
    body.scene2-on #scene2 > iframe { opacity: 1; }

    /* Chat box on the second screen. Grid-centres the form; the wallpaper iframe
       is fixed, so it's out of flow and unaffected. */
    #scene2 { display: grid; place-items: center; align-content: center; gap: 18px; }
    #chat-title {
      position: relative;
      z-index: 1;
      margin: 0;
      font: 600 clamp(2rem, 6vw, 3.25rem)/1.1 var(--sans);
      letter-spacing: -.02em;
      color: #fff;
      text-shadow: 0 2px 18px rgb(0 0 0 / .45);
    }
    /* Scrubbed against the heading's own entry, not body.scene2-on — that class
       flips a whole viewport early, so the fade used to finish off-screen.
       Unsupported browsers skip the block and just get the plain heading. */
    @supports (animation-timeline: view()) {
      #chat-title {
        animation: chat-rise linear both;
        animation-timeline: view();
        animation-range: entry 5% entry 65%;
      }
      @keyframes chat-rise {
        from { opacity: 0; transform: translateY(28px); }
        to { opacity: 1; transform: none; }
      }
    }
    #chat-title::after {
      content: "";
      display: inline-block;
      width: .06em;
      height: .9em;
      margin-left: .1em;
      vertical-align: -.09em;
      background: currentColor;
      animation: caret 1.1s step-end infinite;
    }
    @keyframes caret { 50% { opacity: 0; } }
    @media (prefers-reduced-motion: reduce) {
      #chat-title { animation: none; opacity: 1; transform: none; }
      #chat-title::after { animation: none; }
    }
    #connect { position: relative; z-index: 1; display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
    #connect button, #connect a {
      text-decoration: none;
      padding: 8px 16px;
      font: 500 var(--text-sm, .875rem)/1 var(--sans);
      color: #fff;
      border: 1px solid rgb(255 255 255 / .25);
      border-radius: 980px;
      background: rgb(0 0 0 / .25);
      -webkit-backdrop-filter: blur(12px);
      backdrop-filter: blur(12px);
      cursor: pointer;
      user-select: all;   /* the no-clipboard fallback shows the URL; make it easy to grab */
    }
    #connect button:hover, #connect a:hover { background: rgb(0 0 0 / .4); }
    #connect button:focus-visible, #connect a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
