/* ============================================================================
   YU FEI — PORTFOLIO STYLES
   You normally won't need to touch this file. Colours and fonts live in the
   :root block right below if you'd like to tweak them.
============================================================================ */

:root{
  --paper:#f4f2ec;
  --paper-2:#ebe7dd;
  --print:#fcfbf7;
  --ink:#1c1916;
  --ink-soft:#5b554d;
  --ink-faint:#8c857a;
  --line:#d8d2c5;
  --night-text:#ece6da;
  --night-soft:#a59c8d;
  --seal:#a83a2b;          /* the accent (seal red) */
  --serif:"Cormorant Garamond",Georgia,"Times New Roman",serif;
  --sans:"Helvetica Neue",Helvetica,Arial,system-ui,sans-serif;
  --brush:"Ma Shan Zheng",serif;
  --sidebar:300px;
  --gut:32px;              /* the one gap used between photographs */
}

*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{
  font-family:var(--sans);color:var(--ink);background:var(--paper);
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overflow:hidden;
}
img{display:block;max-width:100%}
::selection{background:var(--seal);color:#fff}
*{scrollbar-width:thin;scrollbar-color:var(--line) transparent}
*::-webkit-scrollbar{width:9px;height:9px}
*::-webkit-scrollbar-thumb{background:var(--line);border-radius:9px;border:3px solid var(--paper)}
*::-webkit-scrollbar-track{background:transparent}

.app{display:flex;height:100vh;}

/* faint paper grain over everything */
body::before{
  content:"";position:fixed;inset:0;pointer-events:none;z-index:200;opacity:.5;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.03'/%3E%3C/svg%3E");
}

/* ── sidebar ─────────────────────────────────────────────────────────── */
.side{
  flex:0 0 var(--sidebar);height:100vh;padding:54px 40px 40px;
  display:flex;flex-direction:column;border-right:1px solid var(--line);
  position:relative;z-index:5;background:var(--paper);
}
.brand{display:flex;align-items:center;gap:14px;cursor:pointer;width:fit-content;text-decoration:none;color:inherit;-webkit-tap-highlight-color:transparent;}
.brand:focus,.brand:focus-visible{outline:none;}
.brand .idmark{font-family:var(--brush);font-size:50px;line-height:.8;color:var(--ink);}
.brand .id-text{display:flex;flex-direction:column;gap:6px;}
.brand .nm{font-family:var(--serif);font-weight:500;font-size:21px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink);}
.brand .sub{font-size:11px;letter-spacing:.3em;text-transform:uppercase;color:var(--ink-faint);}

nav{margin-top:60px;display:flex;flex-direction:column;gap:2px;}
.nav-h{font-size:11px;letter-spacing:.3em;text-transform:uppercase;color:var(--ink-faint);margin-bottom:18px;}
.nav-item{
  font-family:var(--serif);font-size:25px;font-weight:500;color:var(--ink-soft);
  padding:6px 0;cursor:pointer;position:relative;width:fit-content;white-space:nowrap;
  transition:color .35s,letter-spacing .35s;background:none;border:0;text-align:left;
}
.nav-item .dot{position:absolute;left:-20px;top:50%;width:6px;height:6px;border-radius:50%;
  background:var(--seal);transform:translateY(-50%) scale(0);transition:transform .35s cubic-bezier(.2,.8,.3,1);}
.nav-item:hover{color:var(--ink);letter-spacing:.012em;}
.nav-item.active{color:var(--ink);}
.nav-item.active .dot{transform:translateY(-50%) scale(1);}
.nav-item .tag{font-family:var(--sans);font-size:9px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--seal);vertical-align:super;margin-left:8px;opacity:.85;}

.side-foot{margin-top:auto;font-size:12px;line-height:1.7;color:var(--ink-faint);}
.side-foot .cap{font-family:var(--serif);font-style:italic;font-size:16px;color:var(--ink-soft);display:block;margin-bottom:6px;}
.side-foot .l2{display:block;}
.side-foot .copyright{display:block;margin-top:14px;font-size:11px;letter-spacing:.04em;color:var(--ink-faint);}

/* ── main area ───────────────────────────────────────────────────────── */
.main{flex:1;height:100vh;position:relative;}
.main.scrolls{overflow-y:auto;scroll-behavior:smooth;}
.main.fixed{overflow:hidden;}
.stage{min-height:100%;}
.main.scrolls .stage{padding-bottom:120px;}

.view-head{padding:64px 72px 8px;display:flex;justify-content:space-between;align-items:flex-end;gap:24px;}
.view-head h1{font-family:var(--serif);font-weight:500;font-size:64px;line-height:.95;letter-spacing:-.01em;}
.view-head .meta{text-align:right;font-size:12px;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-faint);line-height:1.9;flex:0 0 auto;}
.rule{height:1px;background:var(--line);margin:28px 72px 0;}

/* editorial feed ────────────────────────────────────────────────────────────
   Every landscape renders at one size and every portrait at another, so the
   page reads as a considered set rather than a pile of mismatched shapes.
   Landscapes run the full width; portraits are half-width, paired where they
   sit together and centred when one is left over. The gap never changes —
   uneven spacing is what makes a gallery look accidental.
─────────────────────────────────────────────────────────────────────────── */
.feed{padding:56px 72px 0;display:flex;flex-direction:column;gap:96px;}
.work{display:grid;gap:var(--gut);opacity:0;transform:translateY(40px);
  transition:opacity 1.1s cubic-bezier(.16,1,.3,1),transform 1.1s cubic-bezier(.16,1,.3,1);}
.work.in{opacity:1;transform:none;}
.work.wide{grid-template-columns:1fr;}                        /* landscape, full width */
.work.duo{grid-template-columns:1fr 1fr;}                     /* two portraits together */
.work.solo{grid-template-columns:1fr;justify-items:center;}   /* a leftover portrait... */
.work.solo .frame{width:calc((100% - var(--gut)) / 2);}       /* ...at the paired width */

/* A photograph is never cropped. object-fit:contain guarantees it even in the
   moment before app.js has read the image's true ratio, and the ratios below
   are only placeholders that hold the space until it does. */
.frame{overflow:hidden;cursor:pointer;position:relative;background:var(--paper-2);}
.frame img{width:100%;height:100%;object-fit:contain;filter:saturate(.96);
  transition:filter 1.1s ease;}
.frame:hover img{filter:saturate(1.06) brightness(1.03);}
.frame.portrait{aspect-ratio:4/5;}
.frame.landscape{aspect-ratio:16/9;}

/* The caption lies on the photograph. A gradient scrim keeps it readable over
   a bright sky or a dark alley without dimming the whole frame. */
.frame .cap{position:absolute;left:0;right:0;bottom:0;padding:78px 34px 26px;color:#fff;
  background:linear-gradient(to top,rgba(12,10,8,.74) 0%,rgba(12,10,8,.44) 44%,rgba(12,10,8,0) 100%);
  opacity:0;transform:translateY(10px);pointer-events:none;
  transition:opacity .8s ease,transform .8s cubic-bezier(.16,1,.3,1);}
.work.in .frame .cap{opacity:1;transform:none;}
.frame .cap .idx{display:block;font-family:var(--serif);font-style:italic;font-size:15px;
  letter-spacing:.05em;color:rgba(255,255,255,.72);}
.frame .cap h2{font-family:var(--serif);font-weight:500;font-size:34px;line-height:1.06;
  margin:6px 0 0;text-shadow:0 1px 22px rgba(0,0,0,.45);}
.frame .cap p{font-size:13px;line-height:1.7;margin-top:8px;max-width:46ch;color:rgba(255,255,255,.82);}
.frame.portrait .cap{padding:66px 24px 22px;}
.frame.portrait .cap h2{font-size:25px;}
.frame .cue{position:absolute;top:16px;right:18px;font-size:10px;letter-spacing:.28em;
  text-transform:uppercase;color:#fff;mix-blend-mode:difference;opacity:0;transform:translateY(-6px);transition:.4s;}
.frame:hover .cue{opacity:1;transform:none;}

/* about */
.about{padding:72px;max-width:760px;}
.about p{font-family:var(--serif);font-size:28px;line-height:1.5;color:var(--ink);}
.about .small{font-family:var(--sans);font-size:14px;line-height:1.8;color:var(--ink-soft);margin-top:34px;max-width:48ch;}
.about .contact{margin-top:30px;font-size:12px;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-faint);}
.about .contact a{color:var(--seal);text-decoration:none;border-bottom:1px solid transparent;transition:.25s;}
.about .contact a:hover{border-color:var(--seal);}

/* ── prints board ────────────────────────────────────────────────────────
   .psurface is the window onto the board; .pboard is the board itself, far
   larger than the window and moved and scaled as a single piece. The label
   sits inside the window but outside the board, so it holds its place while
   everything behind it pans and zooms.
───────────────────────────────────────────────────────────────────────── */
.psurface{position:absolute;left:0;right:0;top:0;bottom:0;z-index:1;overflow:hidden;
  cursor:grab;touch-action:none;overscroll-behavior:contain;}
.psurface.panning{cursor:grabbing;}
/* the board is a finite surface, not an endless void — it has a visible rim */
.pboard{position:absolute;left:0;top:0;transform-origin:0 0;will-change:transform;
  background:var(--print);border:1px solid var(--line);border-radius:20px;
  box-shadow:0 2px 50px rgba(40,32,22,.05);}

.pcap{position:absolute;top:26px;left:28px;z-index:40;pointer-events:none;
  background:rgba(252,251,247,.93);border:1px solid var(--line);border-radius:14px;
  padding:13px 20px 14px;backdrop-filter:blur(8px);
  box-shadow:0 8px 26px rgba(40,32,22,.10);}
.pcap .big{font-family:var(--serif);font-weight:500;font-size:30px;line-height:1;white-space:nowrap;}
.pcap .sub{font-size:10px;letter-spacing:.24em;text-transform:uppercase;color:var(--ink-faint);margin-top:7px;}

.print{position:absolute;background:var(--print);padding:10px 10px 0;cursor:grab;
  box-shadow:0 10px 26px rgba(40,32,22,.16),0 2px 6px rgba(40,32,22,.12);
  transition:transform .8s cubic-bezier(.2,.9,.25,1),box-shadow .35s;will-change:transform;touch-action:none;}
.print .ph{overflow:hidden;background:var(--paper-2);}
/* a print shows the whole photograph — never a cropped piece of one */
.print img{width:100%;height:auto;object-fit:contain;pointer-events:none;}
.print .plabel{font-family:var(--serif);font-style:italic;font-size:14px;color:var(--ink-soft);text-align:center;padding:9px 4px 11px;}
/* both shapes keep a fixed width; the height follows the photo's own ratio */
.print.portrait .ph{width:208px;height:auto;}
.print.landscape .ph{width:300px;height:auto;}
.print:hover{box-shadow:0 22px 50px rgba(40,32,22,.26),0 4px 10px rgba(40,32,22,.16);}
/* a sheet pressed into the middle of a pile shows an edge, not a drop shadow —
   fifty full shadows on one spot composite into a dark halo */
.print.buried{box-shadow:0 1px 2px rgba(40,32,22,.14);}
.print.dragging{cursor:grabbing;transition:box-shadow .2s;box-shadow:0 34px 70px rgba(40,32,22,.34);z-index:999!important;}

.controls{position:absolute;bottom:30px;left:50%;transform:translateX(-50%);z-index:15;display:flex;gap:10px;align-items:center;}
.btn{font-family:var(--sans);font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-soft);
  background:rgba(252,251,247,.86);border:1px solid var(--line);padding:11px 20px;border-radius:30px;cursor:pointer;transition:.25s;backdrop-filter:blur(6px);}
.btn:hover{color:var(--ink);border-color:var(--ink-faint);transform:translateY(-1px);}
.chint{font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-faint);margin-left:6px;}
.zoomer{display:inline-flex;align-items:center;gap:2px;padding:3px;border-radius:30px;
  background:rgba(252,251,247,.86);border:1px solid var(--line);backdrop-filter:blur(6px);}
.zbtn{width:30px;height:30px;border:0;border-radius:50%;background:transparent;cursor:pointer;
  font-family:var(--sans);font-size:15px;line-height:1;color:var(--ink-soft);transition:.2s;}
.zbtn:hover{background:var(--paper-2);color:var(--ink);}
.zlevel{min-width:46px;text-align:center;font-size:11px;letter-spacing:.08em;color:var(--ink-faint);}

/* ── lightbox ────────────────────────────────────────────────────────── */
.lb{position:fixed;inset:0;z-index:300;background:rgba(16,14,12,.94);display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .5s;}
.lb.open{opacity:1;pointer-events:auto;}
.lb .pic{position:relative;transform:scale(.96);transition:transform .6s cubic-bezier(.16,1,.3,1);}
.lb.open .pic{transform:none;}
.lb img{max-width:74vw;max-height:78vh;object-fit:contain;box-shadow:0 30px 90px rgba(0,0,0,.6);}
.lb .lbcap{position:absolute;left:0;bottom:-46px;color:var(--night-text);}
.lb .lbcap .t{font-family:var(--serif);font-style:italic;font-size:20px;}
.lb .lbcap .c{font-size:11px;letter-spacing:.26em;text-transform:uppercase;color:var(--night-soft);margin-top:6px;}
.lb .x{position:absolute;top:28px;right:34px;color:var(--night-soft);font-size:30px;cursor:pointer;line-height:1;transition:color .2s;}
.lb .x:hover{color:#fff;}
.lb .arr{position:absolute;top:50%;transform:translateY(-50%);color:var(--night-soft);cursor:pointer;font-family:var(--serif);font-size:40px;padding:20px;transition:color .2s;user-select:none;}
.lb .arr:hover{color:#fff;}
.lb .arr.prev{left:24px;}.lb .arr.next{right:24px;}
.lb .count{position:absolute;top:30px;left:34px;font-size:12px;letter-spacing:.2em;color:var(--night-soft);}

.fade-swap{animation:fadeup .8s cubic-bezier(.16,1,.3,1);}
@keyframes fadeup{from{opacity:0;transform:translateY(18px);}to{opacity:1;transform:none;}}

/* ── gallery view (multi-column, no side text) ───────────────────────── */
.gallery{padding:52px 72px 120px;}
.gallery .gitem{margin:0;cursor:pointer;position:relative;overflow:hidden;background:var(--paper-2);
  opacity:0;transform:translateY(28px);transition:opacity .9s cubic-bezier(.16,1,.3,1),transform .9s cubic-bezier(.16,1,.3,1);}
.gallery .gitem.in{opacity:1;transform:none;}
.gallery .gitem img{width:100%;display:block;filter:saturate(.96);transition:filter 1.1s ease;}
/* no hover zoom — scaling inside a clipped tile would hide the photo's edges */
.gallery .gitem:hover img{filter:saturate(1.06) brightness(1.03);}
.gallery figcaption{position:absolute;left:15px;bottom:13px;font-family:var(--serif);font-style:italic;font-size:15px;
  color:#fff;text-shadow:0 2px 12px rgba(0,0,0,.55);opacity:0;transform:translateY(6px);transition:.4s;pointer-events:none;}
.gallery .gitem:hover figcaption{opacity:1;transform:none;}

/* masonry — varying heights, FULL photos, never cropped (default) */
.gallery.masonry{column-count:3;column-gap:24px;}
.gallery.masonry .gitem{break-inside:avoid;margin-bottom:24px;}
.gallery.masonry img{height:auto;}

/* uniform grid — equal columns, tightly packed. Every tile shares a width and
   takes its height from the photograph, so nothing is cropped; packing the
   columns keeps that from leaving holes under the shorter pictures. */
.gallery.grid{column-count:3;column-gap:18px;}
.gallery.grid .gitem{break-inside:avoid;margin-bottom:18px;}
.gallery.grid img{height:auto;}

/* justified rows — equal-height magazine rows */
.gallery.justified{display:flex;flex-wrap:wrap;gap:14px;}
.gallery.justified .gitem{height:300px;flex-grow:1;}
/* app.js grows each row item by its photo's ratio, so contain fits almost
   exactly — any leftover shows as a thin paper edge rather than a crop. */
.gallery.justified img{height:100%;width:100%;object-fit:contain;}

/* ── responsive ──────────────────────────────────────────────────────── */
@media (max-width:880px){
  body{overflow:auto;}
  .app{flex-direction:column;height:auto;min-height:100vh;}
  .side{flex:none;width:100%;height:auto;padding:30px 26px;border-right:0;border-bottom:1px solid var(--line);
    position:sticky;top:0;}
  /* mobile: character + name + tagline all on one horizontal line */
  .brand{align-items:baseline;}
  .brand .idmark{font-size:42px;}
  .brand .id-text{flex-direction:row;align-items:baseline;gap:10px;}
  nav{margin-top:26px;flex-direction:row;flex-wrap:wrap;gap:6px 20px;align-items:center;}
  .nav-h{width:100%;margin-bottom:6px;}
  .nav-item{font-size:21px;}
  .nav-item .dot{display:none;}
  /* keep the copyright visible on mobile; drop the longer footnote lines */
  .side-foot{display:block;margin-top:16px;}
  .side-foot .cap,.side-foot .l2{display:none;}
  .main{height:auto;}
  .main.scrolls,.main.fixed{overflow:visible;}
  .view-head{padding:40px 26px 8px;flex-direction:column;align-items:flex-start;gap:10px;}
  .view-head h1{font-size:44px;}
  .view-head .meta{text-align:left;}
  .rule{margin:20px 26px 0;}
  .feed{padding:38px 26px 0;gap:52px;}
  /* one photograph per row on a phone — a half-width portrait would be tiny */
  .work.duo{grid-template-columns:1fr;}
  .work.solo .frame{width:100%;}
  .frame .cap{padding:56px 20px 18px;}
  .frame .cap h2,.frame.portrait .cap h2{font-size:23px;}
  .frame .cap .idx{font-size:13px;}
  .gallery{padding:30px 26px 90px;}
  .gallery.masonry{column-count:2;column-gap:16px;}
  .gallery.masonry .gitem{margin-bottom:16px;}
  .gallery.grid{column-count:2;column-gap:12px;}
  .gallery.grid .gitem{margin-bottom:12px;}
  .gallery.justified .gitem{height:220px;}
  .about{padding:40px 26px;}
  .about p{font-size:22px;}
  /* prints fall back to a simple scattered scroll area on small screens */
  .main.fixed{min-height:80vh;}
  .psurface{position:relative;height:70vh;min-height:420px;margin:10px 16px 0;
    border:1px solid var(--line);border-radius:12px;}
  .pcap{top:14px;left:14px;padding:10px 15px 11px;border-radius:11px;}
  .pcap .big{font-size:22px;}
  .pcap .sub{font-size:9px;margin-top:5px;}
  /* four control groups will not sit on one phone-width line — let them wrap */
  .controls{gap:7px;flex-wrap:wrap;justify-content:center;
    width:calc(100vw - 20px);left:50%;transform:translateX(-50%);}
  .btn{padding:9px 13px;font-size:10px;}
  .zoomer{padding:2px;}
  .zbtn{width:27px;height:27px;font-size:14px;}
  .zlevel{min-width:40px;font-size:10px;}
  .controls{position:fixed;bottom:18px;}
}
