/* yishanshen.com/acoustic/: the portal. Claude (O232), 2026-10-27; design portal/DESIGN.md. LOCAL_PENDING_NAS_SYNC.
   One number drives the picture: --s, the seam as a fraction of the long axis (rest .5). portal.js moves it; everything below derives
   from it. Wide forms run the seam across the width, tall forms (portrait phones) down the height. */
@font-face { font-family: "Instrument Sans"; src: url("fonts/instrument-sans-variable.woff2") format("woff2"); font-weight: 400 700; font-stretch: 75% 100%; font-style: normal; font-display: swap; }

:root {
  --paper: #ECE8E0; --ink: #2A2219; --line: #33291F; --soft: rgba(42, 34, 25, .66); --hair-paper: rgba(42, 34, 25, .22);
  --night: #050607; --light: #e9ecf1; --light-dim: rgba(233, 236, 241, .62); --hair-night: rgba(233, 236, 241, .22); --drawn: rgb(158, 168, 189);
  --ease: cubic-bezier(.22, .61, .36, 1);
  --sans: "Instrument Sans", "Segoe UI", system-ui, -apple-system, sans-serif;
  --s: .5;            /* the seam, written by portal.js */
  --tg: 0px;          /* the theatre's glide along the axis, written by portal.js */
  --hg: 0px;          /* the room's glide */
  --dir: to right; --len: 100vw; --tx: 1; --ty: 0;
  --bw: clamp(70px, 8vw, 160px);                /* half the band */
  --x: calc(var(--s) * var(--len));             /* the seam's place */
  --pad: clamp(20px, 2.6vw, 44px);
  color-scheme: light;
}
@media (max-aspect-ratio: 4/5) { :root { --dir: to bottom; --len: 100svh; --tx: 0; --ty: 1; --bw: clamp(40px, 7svh, 80px); } }

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; overflow: hidden; background: var(--night); overscroll-behavior: none; }
body { font: 400 15px/1.45 var(--sans); -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

/* ---- the picture ---------------------------------------------------------------------------------------------------- */
#stage, #stage > * { position: fixed; inset: 0; }
#stage { contain: strict; pointer-events: none; }
.ground {
  background: linear-gradient(var(--dir), var(--paper) calc(var(--x) - var(--bw)), var(--night) calc(var(--x) + var(--bw)));
  background: linear-gradient(var(--dir) in oklab, var(--paper) calc(var(--x) - var(--bw)), var(--night) calc(var(--x) + var(--bw)));
}
/* Each layer is uncovered along the axis by a ramp at the seam; inside it the picture glides (a translate) toward the centre as its
   side grows. The ramps stay in the viewport's frame because they sit on the unmoving outer layer. */
.layer > * { position: absolute; inset: 0; translate: calc(var(--tx) * var(--glide)) calc(var(--ty) * var(--glide)); will-change: translate; }
.theatre-lines { --glide: var(--tg);
  -webkit-mask-image: linear-gradient(var(--dir), #000 calc(var(--x) - var(--bw)), transparent calc(var(--x) + .55 * var(--bw)));
          mask-image: linear-gradient(var(--dir), #000 calc(var(--x) - var(--bw)), transparent calc(var(--x) + .55 * var(--bw))); }
.hall-lines { --glide: var(--hg);
  -webkit-mask-image: linear-gradient(var(--dir), transparent calc(var(--x) - .55 * var(--bw)), #000 calc(var(--x) + var(--bw)), #000 calc(var(--x) + var(--bw) + 3vmax), transparent calc(var(--x) + var(--bw) + 24vmax));
          mask-image: linear-gradient(var(--dir), transparent calc(var(--x) - .55 * var(--bw)), #000 calc(var(--x) + var(--bw)), #000 calc(var(--x) + var(--bw) + 3vmax), transparent calc(var(--x) + var(--bw) + 24vmax)); }
.hall-render { --glide: var(--hg);
  -webkit-mask-image: linear-gradient(var(--dir), transparent calc(var(--x) + .2 * var(--bw)), #000 calc(var(--x) + var(--bw) + 18vmax));
          mask-image: linear-gradient(var(--dir), transparent calc(var(--x) + .2 * var(--bw)), #000 calc(var(--x) + var(--bw) + 18vmax)); }
/* The theatre is its own drawing (Taormina's #lines canvas, toned, feathered into the paper), placed by portal.js with one transform:
   small in its half at rest, growing to where the theatre's own arrival draws it as the visitor goes in. */
.theatre-lines > img { inset: auto; left: 0; top: 0; translate: none; transform-origin: 0 0; will-change: transform; }
/* The room's own line pass (Freestyle on its web geometry, registered to its render within 1.5 px), drawn in the grey-blue of its own
   arrival on black and laid over with "screen": black adds nothing, the lines lighten what lies under them. So the lines rise out of
   the darkening ground at the seam and give way to the lit render further in, as the room's own arrival does. */
html:not(.hall-lines-on) .hall-lines { display: none; }
.hall-lines { mix-blend-mode: screen; }
.hall-lines img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; display: block; }
.hall-render img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; display: block; }
/* a quiet shade under the room's words so they read on any render */
.hall-render::after { content: ""; position: absolute; inset: 0; background: linear-gradient(to top, rgba(5, 6, 7, .62), rgba(5, 6, 7, 0) 34%); }
.veil { background: var(--paper); opacity: 0; transition: opacity 220ms linear; }

/* arrival: paper and black with the band are the first paint; the drawings, then the light, then the words come in */
.theatre-lines, .hall-lines, .hall-render { opacity: 0; transition: opacity 900ms var(--ease); }
html.ready .theatre-lines { opacity: 1; }
html.ready .hall-lines { opacity: 1; transition-delay: 200ms; }
html.ready .hall-render { opacity: 1; transition-delay: 300ms; transition-duration: 1200ms; }
.words, .mark { opacity: 0; transition: opacity 600ms var(--ease) 700ms; }
html.ready .words, html.ready .mark { opacity: 1; }

/* ---- the words and the two ways in ----------------------------------------------------------------------------------- */
#portal { position: fixed; inset: 0; }
/* the shared mark is split by the seam: "Acoustic" in ink on the paper side, "studies" in light on the dark side, each held half a band
   away from the seam's middle (where the ground is mid grey and no ink would read), so the two words move with it */
.mark { position: absolute; top: calc(var(--pad) * .8); left: 0; width: 100vw; height: 12px; margin: 0; z-index: 2; pointer-events: none;
  font: 500 11px/12px var(--sans); letter-spacing: .24em; text-transform: uppercase; white-space: nowrap; }
.mark .w1, .mark .w2 { position: absolute; top: 0; }
.mark .w1 { right: calc(100vw - var(--x) + .5 * var(--bw)); color: var(--ink); }      /* full ink and full light: small text needs 4.5:1 */
.mark .w2 { left: calc(var(--x) + .5 * var(--bw)); color: var(--light); margin-right: -.24em; }
.half { position: absolute; display: block; color: inherit; text-decoration: none; outline: none; -webkit-tap-highlight-color: transparent; cursor: pointer; }
.half.theatre { left: 0; top: 0; width: calc(var(--tx) * var(--x) + var(--ty) * 100vw); height: calc(var(--ty) * var(--x) + var(--tx) * 100svh); color: var(--ink); }
.half.hall { right: 0; bottom: 0; width: calc(var(--tx) * (100vw - var(--x)) + var(--ty) * 100vw); height: calc(var(--ty) * (100svh - var(--x)) + var(--tx) * 100svh); color: var(--light); }
.words { position: absolute; bottom: var(--pad); display: flex; flex-direction: column; gap: 6px; max-width: min(30rem, 38vw); }
.theatre .words { left: var(--pad); }
.hall .words { right: var(--pad); align-items: flex-end; text-align: right; }
.title { font: 460 clamp(26px, 2.6vw, 44px)/1.08 var(--sans); letter-spacing: -.01em; text-wrap: balance; }
.hall .title { font-weight: 480; }
.sub { font: 400 clamp(13px, 1vw, 15px)/1.45 var(--sans); text-wrap: pretty; }
.theatre .sub { color: var(--soft); }
.hall .sub { color: var(--light-dim); }
.kicker { font: 500 11px/1 var(--sans); letter-spacing: .2em; text-transform: uppercase; color: var(--light-dim); margin-bottom: 4px; }
/* the way in is shown at rest, quietly (a visitor should see that a half is a door before moving the pointer); it firms
   and its line draws out on hover or focus */
.enter { display: inline-flex; align-items: center; gap: 10px; margin-top: 10px; padding-right: 3px; font: 500 12px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase;
  opacity: .5; transition: opacity 500ms var(--ease); }
.enter i { display: block; width: 34px; height: 1px; background: currentColor; transform-origin: left center; scale: .42 1; transition: scale 700ms var(--ease); position: relative; }
.enter i::after { content: ""; position: absolute; right: 0; top: -3px; width: 7px; height: 7px; border: solid currentColor; border-width: 1px 1px 0 0; rotate: 45deg; translate: 0 0; }
.hall .enter { flex-direction: row; }
.half.lean .enter { opacity: 1; }
.half.lean .enter i { scale: 1 1; }
.half:focus-visible::before { content: ""; position: absolute; inset: 10px; border: 1px solid currentColor; opacity: .35; pointer-events: none; }
@media (hover: none) { .enter { opacity: 1; } .enter i { scale: 1 1; } }

/* tall forms: the theatre above, the room below; the words sit in each half's lower or upper corner */
@media (max-aspect-ratio: 4/5) {
  /* both marks' words on paper, side by side at the top */
  .mark { text-align: center; } .mark .w1, .mark .w2 { position: static; color: var(--soft); }
  .words { max-width: calc(100vw - 2 * var(--pad)); gap: 4px; }
  /* the theatre's words sit at the foot of its half, just above the band; its drawing above them */
  .theatre .words { bottom: calc(var(--bw) + 10px); }
  .hall .words { bottom: var(--pad); }
  .title { font-size: clamp(22px, 6.2vw, 30px); text-wrap: balance; }
  .sub { font-size: 13px; }
  .enter { margin-top: 6px; }
}
@media (max-height: 500px) and (min-aspect-ratio: 4/5) { .title { font-size: clamp(22px, 2.6vw, 30px); } .words { gap: 4px; max-width: 44vw; } .enter { margin-top: 6px; } .kicker { margin-bottom: 0; } }
/* phones and short screens: the room's words sit lower in its picture, over bright windows; a deeper shade keeps them legible */
@media (max-aspect-ratio: 4/5), (max-height: 500px) { .hall-render::after { background: linear-gradient(to top, rgba(5, 6, 7, .8), rgba(5, 6, 7, .35) 30%, rgba(5, 6, 7, 0) 55%); } }

/* ---- entering ---------------------------------------------------------------------------------------------------------- */
/* the words leave first, so the sweep ends on the picture alone: the theatre's drawing at its own place, or the room at its poster's */
html.entering .mark, html.entering .words { opacity: 0; transition: opacity 260ms var(--ease) 0ms; }
html.entering .half { pointer-events: none; }
/* cross-document view transitions where the browser has them; the room's poster takes the same name on its page */
@view-transition { navigation: auto; }
/* the room opens with its own black arrival (owner, 2026-10-27: entering from here must show the hall's black opening animation, as a
   direct visit does). So its sweep takes the screen and then the lights go down: portal.js fades the veil to the room's black over the
   sweep's second half, and the room's page begins from black; supporting browsers cross-fade the two roots, black onto black. */
html.entering-hall .hall-render::after, html.entering-hall .hall-lines { opacity: 0; transition: opacity 420ms var(--ease); }
::view-transition-group(root) { animation-duration: 420ms; animation-timing-function: cubic-bezier(.22, .61, .36, 1); }

@media (prefers-reduced-motion: reduce) {
  .theatre-lines, .hall-lines, .hall-render, .words, .mark, .enter, .enter i { transition-duration: 1ms !important; transition-delay: 0ms !important; }
  ::view-transition-group(root) { animation-duration: 1ms; }
}
