/* Pure Practical Portfolio. Layout geometry is computed in site.js; this file only sets the
   stage (one fixed screen, no vertical scroll, no rubber band) and the type. */

/* Helvetica Neue Extended Light: the installed 43 Light Extended wins if it is on the machine;
   otherwise the bundled 33 Thin Extended (the only Extended cut on this Mac) stands in. */
@font-face {
  font-family: "PPP Extended";
  src: local("Helvetica Neue LT Std 43 Light Extended"), local("HelveticaNeueLTStd-LtEx"),
       local("Helvetica Neue Light Extended"),
       url("../fonts/HelveticaNeueLTStd-LtEx.otf") format("opentype"),
       url("../fonts/HelveticaNeueLTStd-ThEx.otf") format("opentype");
  font-weight: 300; font-style: normal; font-display: block;
}

:root {
  --bg: #ffffff;
  --ink: #111111;
  --frame: #ebebeb;
  color-scheme: light;
}

html, body {
  margin: 0; padding: 0;
  width: 100%; height: 100%;
  overflow: hidden;
  overscroll-behavior: none;            /* no rubber band, no swipe-to-go-back on the trackpad */
  background: var(--bg);               /* Safari 26 paints its bar strips in the body colour */
}
body {
  position: fixed; inset: 0;           /* iOS: a fixed body cannot be dragged, so nothing bounces */
  touch-action: none;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-text-size-adjust: 100%; text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
  font-synthesis: none;
  color: var(--ink);
}

.stage { position: absolute; inset: 0; overflow: hidden; contain: strict; }
a { color: inherit; text-decoration: none; -webkit-user-drag: none; }

/* frames: absolutely placed by site.js; a real image fills its frame */
.f { position: absolute; display: block; background: var(--frame); overflow: hidden; cursor: pointer; }
.f img, .f video { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 0; -webkit-user-drag: none; pointer-events: none; }
.f .part { position: absolute; overflow: hidden; }        /* one file of a group tile */
.project .f { cursor: zoom-in; }

/* enlarged view: fog over the page, the image fitted to the screen, thin arrows either side */
.lb { position: fixed; inset: 0; z-index: 50; pointer-events: none; }
.lb.on { pointer-events: auto; }
.lbfog { position: absolute; inset: 0; background: rgba(255,255,255,.62); opacity: 0;
  -webkit-backdrop-filter: blur(14px) saturate(.85); backdrop-filter: blur(14px) saturate(.85);
  transition: opacity .35s ease; cursor: zoom-out; }
.lb.on .lbfog { opacity: 1; }
.lbfig { position: absolute; inset: 0; }
.lb .lbimg { position: absolute; cursor: default; transform-origin: 0 0; box-shadow: 0 12px 48px rgba(0,0,0,.16), 0 0 0 1px rgba(0,0,0,.06);
  transition: transform .42s cubic-bezier(.2,.7,.2,1), opacity .28s ease; }
.lb .lbimg > img, .lb .lbimg > video { object-fit: contain; object-position: 50% 50%; }
.lbarrow { position: absolute; top: 50%; width: 56px; height: 96px; margin-top: -48px; padding: 24px 16px;
  border: 0; background: none; color: var(--ink); cursor: pointer; opacity: 0; transition: opacity .35s ease;
  -webkit-tap-highlight-color: transparent; }
.lb.on .lbarrow { opacity: 1; }
.lbarrow.prev { left: 16px; } .lbarrow.next { right: 16px; }
.lbarrow svg { display: block; width: 100%; height: 100%; overflow: visible; }
.lbarrow path { fill: none; stroke: currentColor; stroke-width: 1.2; vector-effect: non-scaling-stroke; }
.lbarrow:hover path { stroke-width: 2; }


.row   { position: absolute; left: 0; right: 0; }
.track { position: absolute; top: 0; left: 0; height: 100%; will-change: transform; }
.wrow  { position: absolute; left: 0; width: 100%; }

/* project and title texts */
.label, .title {
  font-family: "PPP Extended", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 300; letter-spacing: 0; white-space: nowrap; line-height: 1;
}
.label { position: absolute; transform: translateY(-50%); font-size: 30px; padding: 10px 0; cursor: pointer;
  color: var(--ink);                                        /* white neon glow: reads on light frames and dark stills alike */
  text-shadow: 0 0 2px #fff, 0 0 5px #fff, 0 0 10px rgba(255,255,255,.9), 0 0 18px rgba(255,255,255,.75), 0 0 32px rgba(255,255,255,.5); }
.title { display: block; width: fit-content; position: relative; font-size: 30px; margin: 0 0 1.1em; cursor: pointer;
  white-space: normal; line-height: 1.1; transform-origin: 0 50%; transition: transform .2s ease; }
.label { transform-origin: 0 50%; transition: transform .2s ease, text-shadow .2s ease; }

/* hovered titles: a little bigger, with the emblem's RGB wave as a glow. The glow is a blurred copy of the text
   (data-t, set in site.js) painted with the moving rainbow, behind the letters. */
.label::before, .title::before {
  content: attr(data-t); position: absolute; inset: 0; z-index: -1; padding: inherit; pointer-events: none;
  color: transparent; text-shadow: none; -webkit-text-stroke: 4px transparent;
  background: linear-gradient(90deg, #ff0040, #ff8000, #ffee00, #00ff60, #00e5ff, #0050ff, #b000ff, #ff0040) 0 0 / 420px 100% repeat-x;
  -webkit-background-clip: text; background-clip: text;
  filter: blur(7px) saturate(1.6); opacity: 0; transition: opacity .2s ease;
  animation: text-wave 1.6s linear infinite paused; }
.title { isolation: isolate; }
@keyframes text-wave { to { background-position: 420px 0; } }
.label:hover { transform: translateY(-50%) scale(1.06); text-shadow: none; }
.title:hover { transform: scale(1.06); }
.label:hover::before, .title:hover::before { opacity: 1; animation-play-state: running; }
@media (prefers-reduced-motion: reduce) { .label::before, .title::before { animation: none; } }

/* project page: the text block sits in the middle of the space below the belt */
.copy { position: absolute; left: 0; right: 0; bottom: 0; display: grid; place-items: center; padding: 0 16px 7vh; box-sizing: border-box; }
.copy > div { max-width: 31em; width: 100%; }
.copy p {
  margin: 0;
  font-family: Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;
  -webkit-user-select: text; user-select: text;
}

@media (max-width: 899px) {
  .lbarrow { width: 36px; height: 72px; margin-top: -36px; padding: 18px 10px; }
  .lbarrow.prev { left: 4px; } .lbarrow.next { right: 4px; }
  .label { font-size: 21px; }
  .title { font-size: 22px; }
  .copy p { font-size: 12px; }
}

/* home: the emblem, leaning 20° right, about as tall as the two big rows (2.6 of 5.6 row weights), near the
   top-right corner; it stays put while the rows drift underneath and never catches the pointer */
.emblem, .emblem-glow { position: fixed; top: -12vh; right: 2vw; height: 46vh; width: 46vh; pointer-events: none;
  transform: rotate(20deg); transform-origin: 50% 50%; transition: transform .25s ease, opacity .25s ease; }
.emblem { z-index: 5; }
/* hovered (html.onemb, set by the inked-pixel test in site.js): a little bigger, with an RGB glow behind it.
   The glow is the stamp's own shape (mask) filled with a rainbow that sweeps across it, like Razer's wave
   effect, blurred into a halo; the blur sits on the outer box because a filter runs before the mask. */
.emblem-glow { z-index: 4; opacity: 0; filter: blur(12px) saturate(1.6); }
.emblem-glow i { position: absolute; inset: 0;
  -webkit-mask: url(emblem.webp) center / contain no-repeat; mask: url(emblem.webp) center / contain no-repeat;
  background: linear-gradient(90deg, #ff0040, #ff8000, #ffee00, #00ff60, #00e5ff, #0050ff, #b000ff, #ff0040) 0 0 / 46vh 100% repeat-x;
  animation: emblem-wave 1.6s linear infinite paused; }
@keyframes emblem-wave { to { background-position: 46vh 0; } }
html.onemb .emblem { transform: rotate(20deg) scale(1.07); }
html.onemb .emblem-glow { opacity: 1; transform: rotate(20deg) scale(1.1); }
html.onemb .emblem-glow i { animation-play-state: running; }
@media (prefers-reduced-motion: reduce) { .emblem-glow i { animation: none; } }

html.onemb, html.onemb * { cursor: pointer !important; }

/* "click here" (vid's sequin PNG, trimmed, assets/click-here.webp) left of the emblem, with the emblem's RGB wave
   glowing behind it: on a fresh open or a reload it fades in, stays for 10 s, then fades away; site.js adds .show,
   and leaves it off when the visitor comes back from a project/about page. */
.click-hint { position: fixed; top: 7.3vh; right: calc(2vw + 50vh); height: 7.4vh; aspect-ratio: 1400 / 287; z-index: 6;
  pointer-events: none; opacity: 0; }
.click-hint img { position: absolute; inset: 0; width: 100%; height: 100%; }
.click-hint .hint-arrow { position: absolute; left: 100%; top: 50%; transform: translateY(-50%); margin-left: .12em;
  font-size: 5.4vh; line-height: 1; font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif; }
.click-hint i { position: absolute; inset: -6%; filter: blur(8px) saturate(1.6); }
.click-hint b { position: absolute; inset: 6%; overflow: hidden;
  -webkit-mask: url(click-here.webp) center / 100% 100% no-repeat; mask: url(click-here.webp) center / 100% 100% no-repeat; }
.click-hint b::before { content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 200%;
  background: linear-gradient(90deg, #ff0040, #ff8000, #ffee00, #00ff60, #00e5ff, #0050ff, #b000ff, #ff0040,
    #ff8000, #ffee00, #00ff60, #00e5ff, #0050ff, #b000ff, #ff0040);
  animation: hint-wave 2.4s linear infinite; }
@keyframes hint-wave { to { transform: translateX(-50%); } }
.click-hint.show { animation: hint-show 10.8s ease forwards; }
@keyframes hint-show { 0% { opacity: 0; } 4% { opacity: 1; } 94% { opacity: 1; } 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .click-hint b::before { animation: none; } }

/* project + about pages: the same emblem a third the size, at the top middle, as the home button (same glow on hover) */
.project .emblem, .project .emblem-glow { top: 1vh; right: auto; left: 50%; height: 11.5vh; width: 11.5vh; margin-left: -5.75vh; }
.project .emblem-glow i { background-size: 11.5vh 100%; }
.project .emblem-glow { filter: blur(5px) saturate(1.6); }
.project .emblem-glow i { animation-name: emblem-wave-s; }
@keyframes emblem-wave-s { to { background-position: 11.5vh 0; } }
/* …and upright there (no 20° lean) */
.project .emblem, .project .emblem-glow { transform: none; }
html.onemb .project .emblem { transform: scale(1.07); }
html.onemb .project .emblem-glow { transform: scale(1.1); }

/* phone: the emblem sized by the screen width (not its height), tucked into the top-right corner, the CLICK HERE
   hint just left of it; long titles wrap instead of running off the screen */
@media (max-width: 899px) {
  .home .emblem, .home .emblem-glow { top: -14vw; right: -4vw; height: 54vw; width: 54vw; }
  .home .emblem-glow i { background-size: 54vw 100%; animation-name: emblem-wave-m; }
  .click-hint { top: 9vw; right: 57vw; height: 8vw; }
  .click-hint .hint-arrow { font-size: 7vw; }
  .label { white-space: normal; max-width: calc(100vw - 24px); line-height: 1.1; }
}
@keyframes emblem-wave-m { to { background-position: 54vw 0; } }

/* iPhone (html.ios, set by site.js): the page is one whole screen tall and sits scrolled by the top strip, so the
   rows run on under the island and the address bar. Fixed layers are cut at Safari's window, so the emblem, the
   hint and the enlarged view become ordinary absolute layers placed against the visible window (--inT down). */
html.ios, html.ios body { overflow: visible; height: var(--scr); }
html.ios body { position: relative; inset: auto; }
html.ios .emblem, html.ios .emblem-glow, html.ios .click-hint { position: absolute; }
html.ios .home .emblem, html.ios .home .emblem-glow { top: calc(var(--inT) - 14vw); }
html.ios .click-hint { top: calc(var(--inT) + 1.5vw); }
html.ios .project .emblem, html.ios .project .emblem-glow { top: calc(var(--inT) + 1vh); }
html.ios .copy { padding-bottom: calc(7vh + var(--inB)); }
html.ios .lb { position: absolute; inset: auto 0; top: var(--inT); height: var(--win); }
html.ios .lbfog { top: calc(-1 * var(--inT)); bottom: calc(-1 * var(--inB)); }

/* touch: a pressed title lights up as on hover */
.label.lit { transform: translateY(-50%) scale(1.06); text-shadow: none; }
.title.lit { transform: scale(1.06); }
.label.lit::before, .title.lit::before { opacity: 1; animation-play-state: running; }
/* phone: less air under the page text, so the longest one (KRES) clears the taller belt */
@media (max-width: 899px) { .copy { padding-bottom: 3vh; } html.ios .copy { padding-bottom: calc(2vh + var(--inB)); } }

/* about page: the wax seal at the text's bottom right, just outside it, a little turned */
.copy .seal { position: absolute; right: -132px; bottom: -10px; width: 118px; height: auto; transform: rotate(-8deg);
  pointer-events: none; -webkit-user-drag: none; filter: drop-shadow(0 3px 6px rgba(0,0,0,.18)); }

/* Free stand-in for Helvetica Neue Extended (SIL OFL, fonts/Archivo-OFL.txt): Archivo, variable. Matched by measuring
   both: Thin (100), width 112 % with slightly tighter letters and word spaces (Helvetica Extended has wider letters, tighter spaces), 3 % larger = same cap height and line lengths.
   The default since 9 Nov (html.archivo, set in each page head); ?font=helvetica shows the Helvetica version (remembered), ?font=archivo back. */
@font-face {
  font-family: "PPP Archivo";
  src: url("../fonts/Archivo-VF.ttf") format("truetype");
  font-weight: 100 900; font-stretch: 62% 125%; font-style: normal; font-display: block;
}
html.archivo .label, html.archivo .title {
  font-family: "PPP Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 100; font-stretch: 112%; font-variation-settings: "wght" 100, "wdth" 112; letter-spacing: -0.012em; word-spacing: -0.07em;
}
html.archivo .label, html.archivo .title { font-size: 30.9px; }
@media (max-width: 899px) { html.archivo .label { font-size: 21.6px; } html.archivo .title { font-size: 22.7px; } }
