/* Emma Lee — v4. Shared design system, carried over from v2/v3.html's aesthetic. */
:root{
  --paper:#f6f6f6;--pink:#f2c6f2;--ink:#0b0b0b;--soft:#e9e9e9;--pad:4.75vw;
  --display:"Placard Next Condensed","Arial Narrow","Nimbus Sans Narrow","Liberation Sans Narrow",Impact,sans-serif;
  --serif:"Times New Roman MT Condensed","Times New Roman",Times,serif;
  --sans:"Canva Sans","Helvetica Neue",Arial,sans-serif;
  --micro:"Avenir Next","Helvetica Neue",Arial,sans-serif;
  --ease:cubic-bezier(.16,.78,.18,1);
  --header-h:88px;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth;background:var(--paper)}
body{margin:0;color:var(--ink);background:var(--paper);font:14px/1.5 var(--sans)}
button,a{font:inherit;color:inherit}
button{cursor:pointer;background:none;border:0}
a{text-underline-offset:5px}
button:focus-visible,a:focus-visible{outline:2px solid var(--ink);outline-offset:6px}
::selection{background:var(--ink);color:var(--pink)}
[hidden]{display:none!important}
body.modal-open{overflow:hidden}
h1,h2,h3,p{margin:0}
img{display:block;max-width:100%}
.micro{font:400 10px/1.5 var(--micro);letter-spacing:.11em;text-transform:uppercase}
.skip{position:fixed;top:12px;left:12px;z-index:1000;background:var(--paper);padding:12px;transform:translateY(-160%)}
.skip:focus{transform:none}
.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* ---------- custom metaball cursor ---------- */
/* A real teardrop — head circle + smaller tail circle joined by their outer
   tangent lines — drawn as one SVG path (updating a path's `d` repaints just
   that path, not the whole page, unlike changing a DOM element's width/height
   every frame). At rest the tail catches up to the head and the shape
   collapses to a plain circle. */
/* mix-blend-mode has to live directly on this outermost fixed/z-indexed div,
   not on a nested child (or the <svg>/<path> inside it) — an element only
   blends against the real page when IT is the one establishing the stacking
   context; nested one level deeper, it just sees its own empty local
   backdrop and renders unblended. That's also why the "VIEW" label below is
   a fully separate fixed sibling, not a child of this element — it needs a
   real, always-legible solid background, not an inverting blend. */
.cursor-wrap{position:fixed;inset:0;z-index:10000;pointer-events:none;display:none;mix-blend-mode:difference}
.cursor-on .cursor-wrap{display:block}
.cursor-wrap.off{visibility:hidden}
.cursor-svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
.cursor-blob{fill:#fff;transition:opacity .22s var(--ease)}
.cursor-wrap.view .cursor-blob{opacity:0}
.cursor-label{position:fixed;top:0;left:0;z-index:10000;display:none;pointer-events:none;font:400 10px/1 var(--micro);letter-spacing:.11em;color:#fff;
  background:rgba(11,11,11,.82);padding:.5em .85em;border-radius:99px;
  opacity:0;transition:opacity .22s var(--ease)}
.cursor-on .cursor-label.view{display:block;opacity:1}
.cursor-label.off{visibility:hidden}
.cursor-on,.cursor-on a,.cursor-on button{cursor:none}

/* ---------- header / nav (pill hover kept verbatim from v3) ---------- */
.site-header{position:sticky;top:0;z-index:100;display:flex;align-items:center;justify-content:space-between;gap:20px;
  padding:0 var(--pad);height:var(--header-h);background:var(--paper);border-bottom:1px solid transparent}
.site-header.solid{border-bottom-color:var(--soft)}
.brand{font:900 clamp(20px,2.3vw,28px)/.9 var(--display);letter-spacing:-.035em;text-decoration:none;white-space:nowrap}
.site-nav{display:flex;flex-wrap:wrap;gap:clamp(8px,1.6vw,24px)}
.nav-link{position:relative;isolation:isolate;padding:.48em 1.05em .46em;font:500 clamp(13px,1.35vw,18px)/1 var(--sans);letter-spacing:.015em;text-transform:uppercase;text-decoration:none}
.nav-link::before{content:"";position:absolute;z-index:-1;left:.08em;top:50%;width:.68em;height:.68em;transform:translateY(-50%);border-radius:99px;background:var(--ink);transition:left .34s var(--ease),width .34s var(--ease),height .34s var(--ease)}
.nav-link:hover,.nav-link:focus-visible{color:var(--paper);outline:none}
.nav-link:hover::before,.nav-link:focus-visible::before{left:0;width:100%;height:100%}
.nav-link[aria-current="page"]{text-decoration:none;color:var(--paper)}
.nav-link[aria-current="page"]::before{left:0;width:100%;height:100%}

/* ---------- reveal on scroll ---------- */
.js .reveal{opacity:0;transform:translateY(18px);transition:opacity .8s var(--ease),transform .8s var(--ease)}
.js .reveal.visible{opacity:1;transform:none}

/* ---------- footer / colophon (shared) ---------- */
.site-footer{padding:6svh var(--pad) 5svh;border-top:1px solid var(--soft);margin-top:8svh}
.colophon{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap}
.colophon a{text-decoration:none}
.colophon-id{display:inline-flex;align-items:center;gap:10px}
.footer-logo{flex:none;height:26px;width:auto;display:block}

/* ---------- footer now-playing (Spotify) ---------- */
/* Middle column of the colophon. Inherits the colophon's 10px micro caps on
   purpose — the point is that it reads as another footer item, not a widget
   dropped into one. */
/* Grid rather than space-between: with variable-width items either side, a
   flex row leaves the middle wherever the spacing lands rather than centred.
   Columns are assigned explicitly so the row still holds when the strip is
   absent (not configured, or nothing ever played). */
.colophon{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:20px}
.colophon-id{grid-column:1;justify-self:start}
.colophon > a{grid-column:3;justify-self:end}
.np{grid-column:2;justify-self:center}

.np{display:flex;align-items:center;gap:13px;min-width:0}
.np-art{flex:none;width:22px;height:22px;border-radius:2px;object-fit:cover;background:var(--soft);display:block}

/* Hover card on the cover. Light rather than dark so it belongs to the page
   instead of reading as a Spotify component; the shadow does the lifting and
   the artwork stays the loudest thing in it. */
.np-cover{position:relative;flex:none;display:block;line-height:0}
.np-card{position:absolute;bottom:calc(100% + 11px);left:0;z-index:20;width:158px;
  padding:9px;border-radius:4px;background:#fff;border:1px solid var(--soft);
  box-shadow:0 8px 28px rgba(0,0,0,.09);
  opacity:0;pointer-events:none;transform:translateY(5px);
  transition:opacity .2s var(--ease),transform .2s var(--ease)}
.np-cover:hover .np-card,.np-cover:focus-visible .np-card{opacity:1;transform:none}
.np-cover:focus-visible{outline:2px solid var(--ink);outline-offset:3px;border-radius:2px}
.np-card-art{display:block;width:140px;height:140px;border-radius:3px;object-fit:cover;background:var(--soft)}
.np-card-album{display:block;margin-top:9px;color:var(--ink);
  font:400 13px/1.25 var(--serif);letter-spacing:-.01em;text-transform:none}
.np-card-meta{display:block;margin-top:5px;color:#777;
  font:400 9.5px/1.3 var(--micro);letter-spacing:.11em;text-transform:uppercase}
.np-line{color:#777;text-decoration:none;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.np-line b{font-weight:400;color:var(--ink)}
a.np-line:hover{opacity:.6}

.np-eq{display:inline-flex;align-items:flex-end;gap:2px;height:8px;flex:none}
.np-eq i{width:2px;height:100%;background:#1db954;transform-origin:bottom;
  animation:np-eq 1.1s var(--ease) infinite}
.np-eq i:nth-child(2){animation-delay:.18s}
.np-eq i:nth-child(3){animation-delay:.36s}
@keyframes np-eq{0%,100%{transform:scaleY(.28)}50%{transform:scaleY(1)}}

/* Playlist name is a tooltip rather than a row of its own; the link's
   aria-label carries it for anyone not hovering. */
.np-code{position:relative;display:inline-flex;flex:none;line-height:0}
.np-code img{display:block;width:92px;height:23px;opacity:.75;transition:opacity .2s var(--ease)}
.np-code:hover img,.np-code:focus-visible img{opacity:1}
.np-code:focus-visible{outline:2px solid var(--ink);outline-offset:3px;border-radius:2px}
.np-tip{position:absolute;bottom:calc(100% + 9px);left:0;z-index:5;
  padding:6px 9px;border-radius:3px;background:var(--ink);color:var(--paper);
  font:400 9.5px/1 var(--micro);letter-spacing:.09em;text-transform:uppercase;white-space:nowrap;
  opacity:0;pointer-events:none;transform:translateY(4px);
  transition:opacity .18s var(--ease),transform .18s var(--ease)}
.np-tip::after{content:"";position:absolute;top:100%;left:13px;
  border:5px solid transparent;border-top-color:var(--ink)}
.np-code:hover .np-tip,.np-code:focus-visible .np-tip{opacity:1;transform:none}

/* ---------- editorial project rows (used on work.html) ---------- */
.project{position:relative;display:grid;grid-template-columns:44px minmax(0,1fr);gap:2.4vw;padding:5svh var(--pad);scroll-margin-top:calc(var(--header-h) + 16px)}
.chapter{align-self:start;position:relative}
.chapter span{display:block;position:sticky;top:calc(var(--header-h) + 24px);font:italic 16px var(--serif)}
.composition{position:relative;display:grid;grid-template-columns:minmax(0,.62fr) minmax(0,1fr);gap:3.4vw;align-items:center;min-width:0}
.project-copy{z-index:2;max-width:32ch;align-self:center;padding-bottom:0}
.project-copy .micro{margin-bottom:14px}
.project-copy h3{font:900 clamp(26px,2.9vw,42px)/.9 var(--display);letter-spacing:-.035em;text-transform:uppercase;margin-bottom:14px;overflow-wrap:normal}
.project-copy p{font:400 clamp(14px,1.2vw,17px)/1.28 var(--serif);max-width:30ch;margin-bottom:12px}
.project-copy .facts{display:flex;flex-direction:column;gap:5px;margin-top:14px}
.visual-wrap{position:relative;min-width:0}
.visual-wrap::before{content:"";position:absolute;inset:-5% 8% 8% -6%;background:rgba(246,246,246,.5);transform:rotate(-4deg);z-index:-1}
.image{position:relative;display:block;width:100%;overflow:hidden;background:#e8e6e3;height:clamp(220px,38svh,400px);padding:0;border:0;text-align:left}
.image img{width:100%;height:100%;display:block;object-fit:cover;transition:transform .8s var(--ease)}
.image:hover img{transform:scale(1.02)}
.image-note{display:flex;justify-content:space-between;gap:20px;margin-top:12px;font:400 9px/1.4 var(--micro);letter-spacing:.1em;text-transform:uppercase}
.project.reverse .composition{grid-template-columns:minmax(0,1fr) minmax(0,.62fr)}
.project.reverse .visual-wrap{grid-column:1;grid-row:1}
.project.reverse .project-copy{grid-column:2;grid-row:1;align-self:center;padding-bottom:0}
.project.reverse .visual-wrap::before{inset:8% -5% -5% 12%;transform:rotate(3deg)}

@media(max-width:850px){
  :root{--pad:5.5vw}
  .project{grid-template-columns:24px minmax(0,1fr);gap:2vw;padding:4svh var(--pad)}
  .composition,.project.reverse .composition{display:flex;flex-direction:column;align-items:stretch;gap:20px}
  .project-copy,.project.reverse .project-copy{order:2;padding-bottom:0;align-self:stretch;max-width:100%}
  .visual-wrap{width:100%}
  .image{height:38svh}
  .project-copy h3{font-size:clamp(28px,6vw,38px)}
  /* Three columns stop fitting well before the phone breakpoint, so the
     strip takes a centred row of its own under the id and the link. */
  .colophon{grid-template-columns:1fr auto}
  .colophon > a{grid-column:2}
  .np{grid-column:1 / -1;grid-row:2;justify-self:stretch;justify-content:center;
    padding-top:15px;margin-top:4px;border-top:1px solid var(--soft)}
}
@media(max-width:560px){
  .site-header{flex-wrap:wrap;height:auto;padding:14px var(--pad)}
  .site-nav{gap:10px}
  .nav-link{font-size:13px}
  .image{height:32svh}
  /* The two-column arrangement set at 850px carries all the way down rather
     than collapsing to a stack: the name stays left and the link stays right
     on one row, with the now-playing strip centred on its own row beneath.
     Stacking everything left pushed the link into the middle of a column of
     three left-aligned items, where it read as another line of text rather
     than an action. If the pair gets too tight the name wraps to two lines,
     which is a better failure than the link losing its corner. */
  .colophon{gap:14px}
  /* The card would overflow the viewport off a 22px thumbnail at this width;
     it is a hover affordance anyway, and there is no hover here. */
  .np-card{display:none}
}
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation:none!important;transition:none!important}
  .js .reveal{opacity:1;transform:none}
  .image:hover img{transform:none}
}
