/* =====================================================================
   The Art of Nuo Yan — v7 (gallery-first, lightweight)
   Fonts — ONLY the two families supplied by the artist:
     Zilla Slab          all regular text (bold only for special emphasis)
     MONSTER OF FANTASY  big display text (logo, big section titles,
                         artwork title in the detail view)
   Both are subset to Latin + punctuation (woff2). Fallback: generic serif.
   ===================================================================== */
@font-face{font-family:"Zilla Slab";src:url(fonts/zillaslab-regular.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"Zilla Slab";src:url(fonts/zillaslab-bold.woff2) format("woff2");font-weight:700;font-style:normal;font-display:swap}
@font-face{font-family:"MONSTER OF FANTASY";src:url(fonts/monsteroffantasy-regular.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap}

:root{
  --bg:#f2eee6;            /* between v1 parchment #f4ede1 and original #ecede8 */
  --panel:#ffffff; --panel-2:#f7f5f0;
  --line:#d9d4c9; --line-2:#e8e4db;
  --ink:#2c2a31; --ink-2:#55525a; --ink-3:#7c786f;
  --gold:#b48a3c;
  --rail:clamp(252px, 21vw, 300px);   /* v5: a bit wider so the category names + counts fit on one line */
  --gap:clamp(36px, 4vw, 64px);
  --ease:cubic-bezier(.22,1,.36,1);
  --sans:"Zilla Slab", serif;                          /* every regular text */
  --display:"MONSTER OF FANTASY", "Zilla Slab", serif;  /* big display text only */
  --dockH:clamp(128px, 15.5vh, 172px);                  /* bottom dock (progress + Cover Flow) */
  --cfS:clamp(80px, 10vh, 116px);                       /* Cover Flow centre thumbnail */
  --note:clamp(230px, 22vw, 300px);                     /* end card width */
  --glove:url(images/ui/glove-cursor.png) 6 4, pointer;
}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--ink);font:400 15px/1.6 var(--sans);-webkit-font-smoothing:antialiased}
body.is-intro{overflow:hidden}
img{display:block;max-width:100%}
a{color:inherit}
a,button,.card-hit,.tab{cursor:var(--glove)}
button{font:inherit;color:inherit}
h1,h2,h3,p,ol,ul,figure{margin:0}
.display{font-family:var(--display);font-weight:400;letter-spacing:.01em}
.label{font:400 11.5px/1.4 var(--sans);letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3)}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ---------- Wakfu-like panel & buttons ---------- */
.panel{background:linear-gradient(180deg,var(--panel) 0%,var(--panel-2) 100%);border:1px solid var(--line);
  box-shadow:inset 0 0 0 3px #fff, inset 0 0 0 4px var(--line-2), 0 1px 2px rgba(60,50,30,.05)}
.wbtn{display:inline-flex;align-items:center;justify-content:center;gap:.4em;padding:.42em 1em;border-radius:4px;
  border:1px solid #cdc7bb;background:linear-gradient(180deg,#ffffff 0%,#ecebe6 100%);color:#45433f;
  font:400 13px/1.2 var(--sans);letter-spacing:.04em;box-shadow:inset 0 1px 0 #fff,0 1px 1px rgba(0,0,0,.05);transition:border-color .2s,background .2s}
.wbtn:hover{border-color:#b3ac9e;background:linear-gradient(180deg,#ffffff 0%,#f4f2ed 100%)}
.wbtn:active{background:linear-gradient(180deg,#e8e6e0 0%,#fbfaf8 100%)}
.wbtn:focus-visible,.tab:focus-visible,.card-hit:focus-visible,.btn-contact:focus-visible{outline:2px solid #6c63a8;outline-offset:2px}

/* Contact button — kept from v1 */
.btn-contact{display:inline-block;text-decoration:none;font:400 15px/1 var(--sans);color:var(--ink);background:none;cursor:var(--glove);
  border:1.5px solid rgba(185,130,31,.5);border-radius:999px;padding:.6rem 1.25rem;transition:background .2s,color .2s,border-color .2s}
.btn-contact:hover{background:var(--ink);color:var(--bg);border-color:var(--ink)}

/* ================= Intro ================= */
#intro{position:fixed;inset:0;z-index:100;display:grid;place-items:center;background:var(--bg);transition:opacity .35s ease}
#intro.out{opacity:0;pointer-events:none}
#intro.out.quick{transition-duration:.2s}   /* v5: quicker hand-over to the dark stage */
.intro-stage{text-align:center}
.intro-pre{font:400 14px/1 var(--sans);letter-spacing:.3em;text-transform:uppercase;color:var(--ink-3);opacity:0;animation:fadeIn .4s .35s forwards}
.intro-name{font:400 clamp(3rem,10vw,7rem)/1 var(--display);color:var(--ink);display:flex;justify-content:center;margin-top:.5rem}
.il{display:inline-block;opacity:0;transform:translateY(.35em);animation:letterIn .45s var(--ease) forwards}
.il:nth-child(1){animation-delay:.05s}.il:nth-child(2){animation-delay:.1s}.il:nth-child(3){animation-delay:.15s}
.il:nth-child(5){animation-delay:.2s}.il:nth-child(6){animation-delay:.25s}.il:nth-child(7){animation-delay:.3s}
.il-gap{width:.3em}
.il-o{position:relative}
.intro-slime{position:absolute;left:50%;top:52%;width:.42em;image-rendering:pixelated;transform:translate(-50%,-50%);transform-origin:50% 100%;
  opacity:0;animation:slimeDrop .9s .1s forwards}
@keyframes fadeIn{to{opacity:1}}
@keyframes letterIn{to{opacity:1;transform:none}}
@keyframes slimeDrop{
  0%{opacity:0;transform:translate(-50%,-400%) scale(.9,1.12)}
  10%{opacity:1}
  42%{transform:translate(-50%,-50%) scale(1)}
  52%{opacity:1;transform:translate(-50%,-50%) scale(1.32,.7)}
  66%{opacity:1;transform:translate(-50%,-105%) scale(.9,1.12)}
  80%{opacity:1;transform:translate(-50%,-50%) scale(1.12,.88)}
  100%{opacity:1;transform:translate(-50%,-50%) scale(1)}
}

/* ================= Stage tour — iris → spotlight (v7e: no handwritten notes) =================
   .tour-dim is the only layer (its mask = the lit hole). Hidden until main.js adds .on (no JS = never shown). */
#tour{position:fixed;inset:0;z-index:90;display:none;transition:opacity .6s ease}
#tour.on{display:block}
#tour.out{opacity:0;pointer-events:none}
#tour.out.fast{transition-duration:.22s}
.tour-dim{position:absolute;inset:0;background:#0b090e;opacity:.9;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}

/* ================= Rail ================= */
.rail{position:fixed;left:0;top:0;bottom:0;width:var(--rail);padding:14px 0 14px 14px;z-index:20}
.rail-frame{height:100%;display:flex;flex-direction:column;padding:22px 18px 18px;overflow-y:auto;scrollbar-width:none;
  background:linear-gradient(180deg,#ffffff 0%,#f6f4ef 100%);border:1px solid var(--line);box-shadow:inset 0 0 0 3px #fff, inset 0 0 0 4px var(--line-2)}
.rail-frame::-webkit-scrollbar{display:none}
.brand{display:block;text-align:center;text-decoration:none}
.brand-pre{display:block;font:400 11.5px/1 var(--sans);letter-spacing:.28em;text-transform:uppercase;color:var(--ink-3)}
/* logo scales with the rail: "NUO YAN" is ≈4.75em wide in MONSTER OF FANTASY,
   rail inner width = rail − 52px  →  font-size = (rail − 52px) / 5.3 (≈10% spare) */
.logo{display:block;font:400 min(48px, calc((var(--rail) - 52px) / 5.3))/1.05 var(--display);letter-spacing:0;color:var(--ink);margin-top:.4rem;white-space:nowrap;max-width:100%}
.logo-o{position:relative;display:inline-block}
.logo-slime{position:absolute;left:50%;top:52%;width:.42em;transform:translate(-50%,-50%);transform-origin:50% 100%;image-rendering:pixelated}
.brand:hover .logo-slime,.page-ready .logo-slime.hop{animation:slimeHop .7s var(--ease)}
@keyframes slimeHop{0%{transform:translate(-50%,-50%) scale(1.22,.78)}40%{transform:translate(-50%,-125%) scale(.88,1.12)}75%{transform:translate(-50%,-50%) scale(1.1,.9)}100%{transform:translate(-50%,-50%)}}
.tagline{text-align:center;font:400 clamp(11.5px, calc((var(--rail) - 52px) / 15.5), 13px)/1.4 var(--sans);white-space:nowrap;color:var(--ink-2);margin:.5rem 0 1.2rem;padding-bottom:1.1rem;border-bottom:1px solid var(--line-2)}

/* category rows (Wakfu character-list style) */
.tabs{display:flex;flex-direction:column;gap:6px}
.tab{position:relative;display:flex;align-items:center;min-height:56px;padding:6px 8px 6px 0;text-align:left;border:1px solid var(--line);border-radius:3px;overflow:hidden;
  background:linear-gradient(90deg,var(--c) 0%,#fff 78%);background:linear-gradient(90deg,var(--c) 0%,color-mix(in srgb,var(--c) 50%,#fff) 42%,#fff 80%);transition:border-color .2s,transform .25s var(--ease)}
.tab::after{content:"";position:absolute;inset:0;box-shadow:inset 0 0 0 1px rgba(255,255,255,.7);pointer-events:none}
/* v5 hover: the row's colour sweeps left → right over the whole button (transform only)
   and gets more saturated; the art gets more saturated too */
.tab::before{content:"";position:absolute;left:0;top:0;bottom:0;width:135%;pointer-events:none;transform:translateX(-101%);
  background:var(--c);background:linear-gradient(90deg,var(--c) 0%,color-mix(in srgb,var(--c) 80%,#fff) 40%,color-mix(in srgb,var(--c) 55%,#fff) 74%,color-mix(in srgb,var(--c) 0%,transparent) 100%);
  filter:saturate(1.6);transition:transform .45s cubic-bezier(.33,1,.68,1);will-change:transform}
.tab:hover::before{transform:none}
.tab img{position:absolute;left:0;top:0;width:66px;height:100%;object-fit:cover;-webkit-mask-image:linear-gradient(90deg,#000 45%,transparent 100%);mask-image:linear-gradient(90deg,#000 45%,transparent 100%);transition:filter .3s}
.tab:hover img{filter:saturate(1.5)}
/* label: one line, its left edge (--labelX) and size (--labelF) are fitted by main.js
   so the longest name + the count always fit the rail */
.tab-txt{position:relative;display:flex;align-items:center;min-width:0;flex:1;margin-left:var(--labelX,62px)}
.tab-name{display:inline-block;font:400 var(--labelF,12.5px)/1.15 var(--sans);text-transform:uppercase;letter-spacing:.03em;color:var(--ink);white-space:nowrap}
/* work count on the far right: big number (MONSTER OF FANTASY) over a small "works" */
.tab-count{position:relative;flex:none;display:flex;flex-direction:column;align-items:center;min-width:26px;margin-left:6px;line-height:1}
.tab-num{display:block;font:400 22px/1 var(--display);color:var(--ink)}
.tab-unit{display:block;margin-top:2px;font:400 9.5px/1 var(--sans);letter-spacing:.04em;color:var(--ink-3)}
.tab:hover{border-color:#b9b2a5;transform:translateX(2px)}
.tab:hover .tab-name{animation:tabBounce .42s ease-out}
.tab:hover .tab-num{animation:tabPop .4s .05s ease-out}
@keyframes tabBounce{0%{transform:none}30%{transform:translateY(-6px)}55%{transform:translateY(0)}75%{transform:translateY(-2px)}100%{transform:none}}
@keyframes tabPop{0%{transform:none}40%{transform:scale(1.18)}100%{transform:none}}
.tab[aria-pressed="true"]{border-color:#9d978b;background:linear-gradient(90deg,var(--c) 0%,color-mix(in srgb,var(--c) 58%,#e9e7e2) 42%,#e6e4df 80%,#eeede9 100%)}
.tab[aria-pressed="true"] .tab-name{font-weight:700;text-decoration:underline;text-decoration-color:rgba(0,0,0,.25);text-underline-offset:3px}
.bio{font-size:13px;line-height:1.6;color:var(--ink-2);margin:1.2rem 2px 0;text-align:center}
@media (max-height: 720px){.bio{display:none}}
.rail-contact{margin-top:auto;padding-top:1.2rem;display:flex;flex-direction:column;align-items:center;gap:.7rem;text-align:center}
/* v5 contact: pixel-art CRT (sprite sheet stepped by main.js) + bold email.
   Source art is on an 8 px grid → 52×54 art pixels per frame, shown at 1.5× (78×81 css px; 3× device px on retina). */
.crt-row{display:flex;align-items:center;justify-content:flex-start;width:calc(100% + 26px);margin:0 -16px 0 -10px}   /* uses some of the frame's side padding */
.crt{position:relative;flex:none;display:block;padding:0;border:0;background:none;line-height:0;cursor:var(--glove);border-radius:2px}
.crt:focus-visible{outline:2px solid #6c63a8;outline-offset:3px}
/* the CRT is drawn by main.js into this canvas, frame by frame, at whole device pixels (no CSS scaling of the sheet).
   Without JS it shows frame 0 from the sheet (frames are 52×54 art px on a 56×58 pitch, so nothing can bleed in). */
.crt-cv{position:relative;display:block;width:78px;height:81px;image-rendering:pixelated;
  background:url(images/ui/crt-sprite.png) 0 0/1092px 174px no-repeat}
.crt-txt{position:relative;display:flex;flex-direction:column;align-items:flex-start;min-width:0;text-align:left;margin:-18px 0 0 calc(var(--crtW, 78px) * -.154 + 14px)}   /* tucks into the empty space right of the monitor */
.crt-kicker{font:400 10.5px/1.2 var(--sans);letter-spacing:.16em;text-transform:uppercase;color:var(--ink-3);margin-bottom:3px}
.mail-b{font:700 var(--mailF,16px)/1.25 var(--sans);color:var(--ink);white-space:nowrap;padding:0;border:0;background:none;text-align:left;cursor:var(--glove);transition:color .2s}
.mail-b:hover,.crt-row.hot .mail-b{color:#544a8c}
/* "EMAIL COPIED!" — one small line, fixed-positioned (never moves the layout) */
.copied{position:fixed;left:0;top:0;z-index:60;pointer-events:none;white-space:nowrap;font:400 11px/1 var(--sans);letter-spacing:.14em;text-transform:uppercase;color:var(--ink-2);
  text-shadow:0 0 3px var(--bg),0 0 3px var(--bg);opacity:0;transition:opacity .18s}
.copied.on{opacity:1}
.mail-b:focus-visible{outline:2px solid #6c63a8;outline-offset:2px}
.mail{font:400 14px/1.3 var(--sans);color:var(--ink-2);text-decoration:none;border:0;border-bottom:1px solid var(--line);background:none;padding:0;cursor:var(--glove)}
.mail:hover{color:var(--ink);border-color:var(--ink-2)}
.socials{list-style:none;padding:0;display:flex;gap:8px}
.socials a{display:grid;place-items:center;width:32px;height:32px;border:1px solid var(--line);border-radius:4px;background:linear-gradient(180deg,#fff,#efede8);transition:border-color .2s,transform .2s var(--ease)}
.socials img{width:18px;height:18px;object-fit:contain}
.socials a:hover{border-color:#b3ac9e;transform:translateY(-2px)}

/* ================= Main / Gallery ================= */
.main{margin-left:var(--rail);min-width:0}
.gallery{position:relative}
.g-sticky{position:sticky;top:0;height:100vh;overflow:hidden}
/* the strip lives in the area above the dock; cards are vertically centred there */
/* v7: heading band on top (--headH), the works, then a band kept free for the progress flag (--flagB) */
.g-track{--headH:clamp(70px, 11vh, 100px);--flagB:clamp(40px, 8vh, 90px);--capH:52px;
  --bigH:min(61vh, calc(100vh - var(--dockH) - var(--headH) - var(--flagB) - var(--capH)));
  position:absolute;left:0;top:0;bottom:var(--dockH);display:flex;align-items:center;gap:var(--gap);padding:var(--headH) var(--gap) var(--flagB);will-change:transform;transition:opacity .25s}
/* category pages (v6 layout): welcome card with thumbnails on the left, no heading band */
.g-track.cat{--bigH:min(61vh, calc(100vh - var(--dockH) - 124px));padding:0 var(--gap)}
.g-track.cat .card.first{--wcap:calc(100vw - var(--rail) - var(--note) - 3 * var(--gap) - 20px)}
/* v7 page heading ("Recent work" / category) — top-left above the first work, scrolls with the strip */
.g-head{position:absolute;left:var(--gap);top:max(10px, calc(var(--headH) - 66px));white-space:nowrap}
.g-head h2{font-size:clamp(26px, 2.5vw, 36px);line-height:1.05}
.g-head .label{margin-top:2px}
.g-track.swap{opacity:0}
/* Artwork size. Height-driven, the width ALWAYS follows the image's real ratio:
   --ar starts from works.js `size` and is replaced by naturalWidth/naturalHeight
   as soon as the file has loaded. Nothing is ever cropped or stretched.
   v3: max height 61vh (= v2's 76vh − 20%). --wcap = widest allowed image. */
.card{flex:none;margin:0;width:min-content;--wcap:calc((100vw - var(--rail)) * .8);
  --imgH:min(var(--bigH), calc(var(--wcap) / var(--ar)))}
/* v7 Recent work: two (or more) works stacked in one column, together as tall as one big work */
.stack{flex:none;display:flex;flex-direction:column;align-items:flex-start;gap:var(--sgap);--sgap:14px}
.card.half{--imgH:min(calc((var(--bigH) + var(--capH) - var(--n) * var(--capH) - (var(--n) - 1) * var(--sgap)) / var(--n)), calc(var(--wcap) / var(--ar)))}
/* v4: no white mat — the drop shadow sits directly on the image edge */
.card-hit{display:block;padding:0;border:0;background:none;transition:transform .3s var(--ease)}
.card-hit:hover{transform:translateY(-4px)}
.card-img{position:relative;display:block;height:var(--imgH);aspect-ratio:var(--ar);background:#e6e1d6;border-radius:1px;
  box-shadow:0 1px 2px rgba(60,50,30,.10),0 16px 30px -16px rgba(60,50,30,.45)}
.card-img img{border-radius:1px}
.card-img img{height:100%;width:auto;max-width:none;opacity:0;transition:opacity .4s}
.card-img img.loaded{opacity:1}
.card figcaption{display:flex;align-items:flex-end;justify-content:space-between;gap:10px;padding:12px 1px 0}
.cap-title{font:400 14px/1.2 var(--sans);color:var(--ink)}
.cap-sub{display:block;margin-top:2px;font-size:10.5px}
.pill{flex:none;font:400 11px/1 var(--sans);letter-spacing:.06em;color:#5a564e;padding:0 0 2px;white-space:nowrap}   /* v7: text only, no outline */

/* end card inside the strip */
.g-note{flex:none;width:var(--note);display:flex;flex-direction:column;justify-content:center;padding:24px 22px}
.g-note h2{font-size:30px;line-height:1.1;margin-bottom:.3rem}
.g-intro{padding:0}   /* v4: welcome text sits directly on the page, no card */
.g-note .welcome{font:400 15px/1.5 var(--sans);color:var(--ink-2);margin-bottom:1rem}
.g-note .hint{margin-top:1rem;display:flex;align-items:center;gap:.6rem}
.g-note .hint img{width:30px;image-rendering:pixelated}
.g-end{align-items:center;text-align:center;gap:1rem;height:min(61vh,520px)}
.g-end img{width:56px;image-rendering:pixelated}
/* thumbnail mini-grid — justified rows, every thumbnail at its ORIGINAL ratio.
   flex-grow ∝ ratio keeps one common height per row; the ::after filler stops
   the last row from stretching. */
.g-thumbs{--rowH:clamp(44px, 6.6vh, 66px);display:flex;flex-wrap:wrap;align-items:flex-start;gap:6px;margin-top:1rem}
.g-thumbs::after{content:"";flex:999 1 0}
.g-thumbs button{flex:var(--ar) 1 calc(var(--ar) * var(--rowH));aspect-ratio:var(--ar);min-width:0;display:block;padding:0;border:0;border-radius:1px;background:#e6e1d6;
  box-shadow:0 1px 2px rgba(60,50,30,.12),0 6px 10px -6px rgba(60,50,30,.4);transition:transform .25s var(--ease)}
.g-thumbs img{width:100%;height:100%;border-radius:1px}
.g-thumbs button:hover{transform:translateY(-2px)}
.g-thumbs button.on{outline:2px solid var(--ink);outline-offset:2px}
@media (max-height: 760px){.g-thumbs button:nth-child(n+7){display:none}.g-note .welcome{margin-bottom:.6rem}}
@media (max-height: 600px){.g-thumbs button:nth-child(n+4){display:none}}
.g-thumbs button{position:relative}
.g-end{align-items:center;text-align:center;gap:1rem;height:min(var(--bigH, 61vh),520px)}
.g-end img{width:56px;image-rendering:pixelated}

/* bottom dock: progress (left) + Cover Flow (right) */
.g-dock{position:absolute;left:var(--gap);right:max(calc(var(--gap) + 52px), var(--bobR, 0px));bottom:0;height:var(--dockH);display:flex;align-items:center;gap:clamp(12px, 1.6vw, 26px)}

/* Cover Flow (iPod style), circular. Only transform/opacity change; items that
   don't fit the bar are display:none. Thumbnails keep their original ratio. */
.coverflow{flex:1;min-width:0;display:flex;align-items:center;gap:4px}
.cf-col{flex:1;min-width:0}
.cf-stage{position:relative;height:calc(var(--cfS) + 14px);perspective:560px;overflow:hidden}
.cf-item{position:absolute;left:50%;top:7px;width:var(--cfS);height:var(--cfS);padding:0;border:0;border-radius:1px;background:#e6e1d6;
  box-shadow:0 8px 14px -8px rgba(40,30,20,.55);transition:transform .45s var(--ease),opacity .45s var(--ease);will-change:transform}
.cf-item img{width:100%;height:100%;display:block;border-radius:1px}
.cf-item.off{display:none}
.cf-item.jump{transition:none}
.cf-item.cur{outline:2px solid var(--ink);outline-offset:2px}
/* v6: covers that only show because the loop wraps around (end items left of page 1, first items right of the last page) — washed out */
.cf-item.wrap img{filter:grayscale(1)}
/* v6 progress flag (canvas + 9 invisible dot buttons), placed by main.js over the Cover Flow */
.cf-col{position:relative}
.g-flag{position:absolute;left:0;top:0;z-index:3;pointer-events:none}
.g-flag-cv{display:block;image-rendering:pixelated;background:url(images/ui/flag-sheet.png) no-repeat -9999px 0}
.g-flag-dot{position:absolute;padding:0;border:0;background:none;border-radius:2px;pointer-events:auto;cursor:var(--glove)}
.g-flag-dot:focus-visible{outline:2px solid #6c63a8}
.cf-title{margin-top:6px;text-align:center;font:400 13px/1.2 var(--sans);color:var(--ink-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* chunky cartoon block arrows (inline SVG) — gallery Cover Flow + detail view */
.arrow-btn{flex:none;display:inline-grid;place-items:center;width:46px;height:40px;padding:0;border:0;background:none;color:#141216}
.arrow-btn .arrow{width:38px;height:32px;overflow:visible;fill:currentColor;stroke:currentColor;stroke-width:5;stroke-linejoin:round;transition:transform .18s var(--ease)}
.arrow-l .arrow{transform:scaleX(-1)}
.arrow-r:hover .arrow{transform:translateX(4px)}
.arrow-l:hover .arrow{transform:scaleX(-1) translateX(4px)}
.arrow-btn:active .arrow{transition-duration:.05s}
.arrow-r:active .arrow{transform:translateX(6px) scale(.92)}
.arrow-l:active .arrow{transform:scaleX(-1) translateX(6px) scale(.92)}
.arrow-btn:focus-visible{outline:2px solid #6c63a8;outline-offset:2px;border-radius:4px}
.arrow-btn[disabled]{opacity:.22;pointer-events:none}

/* ================= Footer ================= */
.foot{padding:var(--gap)}
.foot-panel{display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap;padding:26px 28px}
.foot-panel h2{font-size:30px;line-height:1.1;margin-bottom:6px}
.foot-actions{display:flex;align-items:center;gap:18px;flex-wrap:wrap}
.copy{margin-top:18px;text-align:center;font-size:12px;color:var(--ink-3)}

/* ================= Detail view =================
   v7: "lights off" — a dark, see-through backdrop over the page (the page stays visible behind it);
   no white mat on the artwork; the text sits BELOW the image so the image gets the whole width. */
.detail{position:fixed;inset:0;z-index:60;background:rgba(17,14,21,.86);opacity:0;transition:opacity .25s ease;
  --ink:#efe9dc;--ink-2:#cfc8ba;--ink-3:#a39c8f;--line:rgba(255,255,255,.17);--line-2:rgba(255,255,255,.1);color:var(--ink)}
.detail.open{opacity:1}
.detail[hidden]{display:none}
html.lock,html.lock body{overflow:hidden}
.detail .arrow-btn{color:#efe9dc}
.d-scroll{position:absolute;inset:0;overflow-y:auto;overscroll-behavior:contain;padding:24px 76px 60px}
.d-top{max-width:1500px;margin:0 auto}
.d-stage{display:flex;justify-content:center;align-items:flex-start;transform:translateY(10px);transition:transform .35s var(--ease)}
.detail.open .d-stage{transform:none}
.frame{box-shadow:0 22px 50px -24px rgba(0,0,0,.75)}
.frame img,.frame video{display:block;max-height:calc(100vh - 96px);max-width:100%;width:auto;height:auto;object-fit:contain;border-radius:1px}
.frame video{background:#2a2530}   /* process timelapse: natural ratio, no crop */
.d-info{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(240px,1fr);gap:18px 48px;align-items:start;max-width:1120px;margin:18px auto 0;padding:0 4px}
.d-title{font-size:34px;line-height:1.08;margin:.35rem 0 .55rem}
.d-medium{font-size:14px;color:var(--ink-2);font-style:italic;margin-bottom:.5rem}
.d-medium:empty,.d-desc:empty{display:none}
.d-desc{font-size:15px;line-height:1.6;color:var(--ink-2);max-width:62ch}
.d-proc-head{display:flex;align-items:baseline;justify-content:space-between;padding:4px 0 0;margin:0 0 10px}
.d-proc-title{font:700 15px/1.2 var(--sans);letter-spacing:.02em}
.d-steplist{list-style:none;padding:0;display:flex;flex-direction:column;gap:6px}
.d-steplist button{display:flex;align-items:center;gap:10px;width:100%;padding:5px;text-align:left;border:1px solid var(--line);border-radius:3px;
  background:rgba(255,255,255,.05);font:400 13px/1.35 var(--sans);color:var(--ink-2);transition:border-color .2s}
.d-steplist button:hover{border-color:rgba(255,255,255,.4)}
.d-steplist img{width:56px;height:40px;object-fit:cover;flex:none;border-radius:1px}
.d-steplist b{font:700 13px/1 var(--sans);color:var(--ink);margin-right:4px}
.placeholder{border:1px dashed rgba(255,255,255,.25);border-radius:3px;padding:14px;text-align:center;font-size:14px;line-height:1.6;color:var(--ink-2)}
.d-nav{display:none;grid-column:1 / -1;justify-content:space-between;gap:8px;margin:0 -4px}
.d-steps{max-width:1500px;margin:46px auto 0;display:flex;flex-direction:column;gap:46px}
.d-step{display:grid;grid-template-columns:150px minmax(0,1fr);gap:24px;align-items:start}
.d-step-meta{position:sticky;top:10px}
.d-step-num{font:400 38px/1 var(--display);color:var(--ink)}
.d-step-cap{margin-top:8px;font-size:13.5px;color:var(--ink-2)}
.d-step .frame{justify-self:start}
.d-step .frame img,.d-step .frame video{max-height:82vh}
.d-close{position:fixed;top:12px;right:14px;z-index:2}
.d-close .arrow,.ov-close .arrow{width:30px;height:30px;stroke-width:7;stroke-linecap:round;fill:none}
.d-close:hover .arrow,.ov-close:hover .arrow{transform:rotate(90deg) scale(1.08)}
.d-arrow{position:fixed;top:50%;margin-top:-20px;z-index:2}
.d-arrow-l{left:14px}.d-arrow-r{right:14px}

/* back to top — v7: Bob walking (pixel art drawn by main.js into the canvas; placed on the device-pixel grid by main.js) */
.to-top{position:fixed;left:0;top:0;z-index:30;display:block;padding:0;border:0;background:none;line-height:0;border-radius:2px;opacity:0;pointer-events:none;transition:opacity .25s}
.to-top.show{opacity:1;pointer-events:auto}
.to-top:focus-visible{outline:2px solid #6c63a8;outline-offset:2px}
.bob-cv{display:block;width:104px;height:166px;image-rendering:pixelated;background:url(images/ui/bob-walk-sheet.png) no-repeat -9999px 0}

/* hover popup — "Making process" preview (mouse only). Only opacity + transform change. */
.pp{position:fixed;left:0;top:0;z-index:40;pointer-events:none;opacity:0;visibility:hidden;max-width:min(430px, calc(100vw - 16px));padding:8px 10px 10px;
  background:linear-gradient(180deg,#ffffff 0%,#f6f4ef 100%);border:1px solid var(--line);
  box-shadow:inset 0 0 0 3px #fff, inset 0 0 0 4px var(--line-2), 0 12px 26px -12px rgba(40,30,20,.45);
  transition:opacity .14s ease,visibility 0s linear .14s;will-change:transform,opacity}
.pp.on{opacity:1;visibility:visible;transition:opacity .14s ease}
.pp-cta{font:700 12.5px/1.2 var(--sans);color:var(--ink);margin:0 0 6px;padding-bottom:6px;border-bottom:1px solid var(--line-2)}
.pp-label{font:400 11.5px/1.2 var(--sans);letter-spacing:.1em;text-transform:uppercase;color:var(--ink-2);margin:0 0 7px}
.pp-label span{color:var(--ink-3);letter-spacing:.06em}
.pp-row{display:flex;flex-wrap:wrap;gap:6px}
.pp-item{position:relative;display:block;height:64px;background:#e6e1d6;border-radius:1px;box-shadow:0 1px 2px rgba(60,50,30,.15)}
.pp-item img{height:64px;width:auto;max-width:none;border-radius:1px}
.pp-item:only-child,.pp-item:only-child img{height:112px}   /* a single step (e.g. a timelapse) gets a bigger preview */
.pp-item video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;border-radius:1px}
.pp-item.vid::after{content:"";position:absolute;left:5px;bottom:5px;border-style:solid;border-width:5px 0 5px 8px;border-color:transparent transparent transparent #fff;filter:drop-shadow(0 0 2px rgba(0,0,0,.6))}
@media (max-width: 860px){.pp{display:none}}

/* ================= v7 ALL WORKS overview (lights off + collage; positions set by main.js) ================= */
.ov{position:fixed;top:0;right:0;bottom:0;left:var(--rail);z-index:31}
.ov[hidden]{display:none}
.ov-dim{position:absolute;inset:0;background:#141216;opacity:0;transition:opacity .4s ease}   /* solid when open: uniform darkness, nothing shows through */
.ov.on .ov-dim{opacity:1}
.ov.closing .ov-dim{transition:opacity .45s ease .2s}
.ov-scroll{position:absolute;inset:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;padding:clamp(20px, 4vh, 44px) calc(var(--gap) + 20px) clamp(18px, 3vh, 34px) var(--gap)}
.ov-cols{position:relative;display:flex;justify-content:center;align-items:flex-start}
.ov-col{position:relative;flex:none}
.ov-h{position:absolute;left:0;right:0;top:0;text-align:center;font:700 clamp(15px, 1.4vw, 22px)/1.15 var(--sans);letter-spacing:.14em;text-transform:uppercase;color:#efe9dc;opacity:0;transition:opacity .35s ease .12s}
.ov-sub{position:absolute;left:0;top:0;font:400 11.5px/1.2 var(--sans);letter-spacing:.14em;text-transform:uppercase;color:#aaa294;white-space:nowrap;opacity:0;transition:opacity .35s ease .2s}
.ov.on .ov-h,.ov.on .ov-sub{opacity:1}
.ov.closing .ov-h,.ov.closing .ov-sub{transition-delay:0s}
.ov-t{position:absolute;left:0;top:0;padding:0;border:0;background:none;transform-origin:50% 50%;cursor:var(--glove)}
.ov-b{position:relative;display:block;width:100%;height:100%;background:#2a2530;border-radius:1px;box-shadow:0 10px 22px -10px rgba(0,0,0,.85)}
.ov-b img{width:100%;height:100%;object-fit:contain;border-radius:1px}
.ov-t:hover .ov-b{outline:2px solid #efe9dc;outline-offset:3px}
.ov-t:focus-visible{outline:2px solid #b9b2d6;outline-offset:4px}
/* v7: lowercase "loading..." centred in an image box until its file has loaded (class set by main.js) */
.ld::before{content:"loading...";position:absolute;inset:0;z-index:1;display:flex;align-items:center;justify-content:center;
  font:400 11px/1 var(--sans);letter-spacing:.04em;color:var(--ink-3);pointer-events:none;overflow:hidden;white-space:nowrap}
.ov-b.ld::before{color:#8d8679}
.g-thumbs .ld::before{font-size:9.5px;letter-spacing:0}
.cf-item.ld:not(.cur)::before{content:none}   /* turned side covers are too narrow for the word: only the centre cover says it */
.ov-close{position:absolute;top:10px;right:10px;z-index:2;color:#efe9dc}

/* signature (top-right, faint, purely decorative): above the gallery/rail, below the popup, detail view and tour */
.sig{position:fixed;top:20px;right:22px;z-index:25;width:clamp(150px, 13vw, 190px);height:auto;opacity:.3;pointer-events:none;user-select:none}
@media (max-width: 860px){.sig{display:none}}

/* reveal (IntersectionObserver) */
.rv{opacity:0;transform:translateY(24px);transition:opacity .6s var(--ease),transform .7s var(--ease)}
.rv.in{opacity:1;transform:none}

/* ================= Mobile / narrow ================= */
@media (max-width: 860px){
  :root{--rail:0px;--gap:18px}
  .rail{position:relative;width:auto;padding:10px 10px 0}
  .rail-frame{height:auto;padding:16px 14px 14px;overflow:visible}
  .logo{font-size:40px}
  .tagline{margin-bottom:.9rem;padding-bottom:.8rem}
  .tabs{flex-direction:row;overflow-x:auto;gap:6px;margin:0 -4px;padding:0 4px 4px;scroll-snap-type:x mandatory;scrollbar-width:none}
  .tabs::-webkit-scrollbar{display:none}
  .tab{flex:0 0 auto;min-height:50px;width:210px;scroll-snap-align:start}
  .tab img{width:56px}
  .tab-num{font-size:20px}
  .bio{display:none}
  .rail-contact{flex-direction:column;align-items:center;padding-top:.9rem}
  .crt-row{width:auto;margin:0;justify-content:center}
  .main{margin-left:0}
  .g-sticky{position:relative;height:auto;overflow:visible;display:block}
  .g-track{position:static;flex-direction:column;align-items:stretch;padding:18px var(--gap) 0;gap:28px;transform:none!important;will-change:auto}
  .card{--imgH:auto;width:auto}
  .card-hit{width:100%}
  .card-img{width:100%;height:auto;aspect-ratio:var(--ar)}
  .card-img img{width:100%;height:auto}
  .g-note{width:auto;height:auto;padding:18px}
  .g-track,.g-track.cat{padding:18px var(--gap) 0}
  .g-note.g-intro{display:none}
  .g-head{position:static}
  .stack{display:contents}
  .ov{left:0}
  .ov-cols{flex-direction:column;align-items:flex-start;gap:28px}
  .d-info{grid-template-columns:1fr}
  .d-nav{display:flex}
  .g-dock{display:none}
  .d-scroll{padding:60px 12px 40px}
  .frame img,.frame video{max-height:none}
  .d-step{grid-template-columns:1fr;gap:10px}
  .d-step-meta{position:relative;top:0}
  .d-arrow{display:none}
  .d-close{top:8px;right:6px}
}

/* ================= Reduced motion ================= */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation:none!important;transition-duration:.001ms!important;transition-delay:0s!important}
  #intro{display:none}
  #tour{display:none!important}
  .rv{opacity:1;transform:none}
}
