/* kingzhou.net, rebus · ink · paper: tokens, paper, type, header, rebus vocabulary, then the page sections in order. */

:root {
  --paper: #ebe6da;
  --paper-2: #f6f2e8;
  --kraft: #c9a571;
  --ink: #2b0d0d;          /* wine-black: the main ink */
  --riso: #ff4a2e;         /* the one loud accent */
  --blue: #2b4fa0;
  --yellow: #ffe36b;
  --pencil: #6d6a63;
  --display: "Bricolage Grotesque", sans-serif;
  --serif: "Instrument Serif", Georgia, serif;
  --mono: "IBM Plex Mono", ui-monospace, monospace;
  --hand: "Caveat", cursive;
  --type: "Special Elite", "Courier New", monospace;
  --ease-pop: cubic-bezier(.3, 1.35, .45, 1);
  --ease-soft: cubic-bezier(.4, 0, .2, 1);
  --ease-glide: cubic-bezier(.22, 1, .36, 1);
}

* { box-sizing: border-box; margin: 0; }
html { background: var(--paper); color: var(--ink); scroll-behavior: smooth; scroll-padding-top: 64px; overflow-x: hidden; } /* on the root it clips the viewport, so phones never zoom out sideways */
body {
  color: var(--ink); /* the Soft Console kit colours :where(body) for its own dark pages */
  font: 400 13px/1.5 var(--mono); letter-spacing: .02em;
  /* a sheet folded in four: two soft creases */
  background:
    linear-gradient(90deg, transparent 49.8%, #0000000b 50%, #ffffff40 50.2%, transparent 50.5%) 0 0 / 100% 100vh no-repeat,
    linear-gradient(180deg, transparent 49.8%, #0000000a 50%, #ffffff38 50.2%, transparent 50.5%) 0 0 / 100% 100vh no-repeat,
    var(--paper);
}
a { color: inherit; }
img { display: block; }

/* fibre grain over everything; the grain is pure black with varying alpha, so plain blending darkens exactly
   like multiply would, without making the browser blend the whole page on every scroll frame */
body::after {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 1000; opacity: .42;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .5 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

.site-head {
  position: fixed; inset: 0 0 auto; z-index: 900; display: flex; justify-content: space-between; align-items: baseline;
  padding: 18px 26px; text-transform: uppercase; letter-spacing: .12em; font-size: 12px;
  background: #ebe6dad1; -webkit-backdrop-filter: blur(14px) saturate(140%); backdrop-filter: blur(14px) saturate(140%);
}
.site-head nav { display: flex; gap: 22px; }
.site-head a { text-decoration: none; transition: color .15s; }
.site-head a:hover, .site-head a[aria-current] { color: var(--riso); }
.site-head a:active { opacity: .6; transition: none; }
@media (prefers-reduced-transparency: reduce) { .site-head { background: var(--paper); -webkit-backdrop-filter: none; backdrop-filter: none; } }

.section-tag { font: 700 26px/1 var(--hand); color: var(--riso); rotate: -3deg; display: inline-block; }
.section-title { font: 400 clamp(40px, 5vw, 76px)/.95 var(--serif); letter-spacing: -.01em; }
.section-title b { font: 800 1em var(--display); letter-spacing: -.05em; }

/* ---- rebus vocabulary ---- */
/* optical size is pinned: with it on auto, widths stop scaling with font size and the hero layout (measured at one size) breaks */
.w-h { font: 800 1em/1 var(--display); letter-spacing: -.035em; font-variation-settings: "opsz" 96; }
.w-s { font: 400 1.04em/1 var(--serif); letter-spacing: -.01em; }

/* regular words react without changing size: colour plus a pencil underline drawn under them */
.w { position: relative; transition: color .2s; }
.w::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -.01em; height: .15em; pointer-events: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 10' preserveAspectRatio='none'%3E%3Cpath d='M2 6 C 30 2, 60 9, 98 4' fill='none' stroke='%23ff4a2e' stroke-width='4.5' stroke-linecap='round'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
  clip-path: inset(0 100% 0 0); transition: clip-path .35s var(--ease-soft);
}
.w.plain::after { content: none; }
.w:not(.plain):hover { color: var(--riso); }
.w:not(.plain):hover::after { clip-path: inset(0 0 0 0); }

/* app-icon chips and colour dots */
.ico { display: inline-block; width: .74em; height: .74em; vertical-align: -.06em; margin: 0 .02em; transition: transform .3s var(--ease-pop); }
.ico:hover { transform: rotate(-8deg); }
.app { border-radius: .2em; box-shadow: 0 .04em .08em #0003, inset 0 .02em 0 #fff6; display: inline-grid; place-items: center; }
.app svg { width: 62%; height: 62%; }
.dot { width: .48em; height: .48em; vertical-align: .08em; border-radius: 50%;
  background: radial-gradient(circle at 34% 30%, #fff9 0 12%, transparent 40%), conic-gradient(#ff3b30, #ffcc00, #34c759, #00c7be, #007aff, #af52de, #ff2d55, #ff3b30);
  box-shadow: 0 .03em .06em #0004; }

/* clip-art words: cut from magazines, glued in; they never move */
.ransom, .sticker { text-align-last: auto; word-spacing: 0; white-space: nowrap; }
.ransom { display: inline-flex; gap: .03em; vertical-align: baseline; }
.ransom b { display: inline-block; font-weight: 400; padding: .02em .07em; line-height: 1; box-shadow: 0 .03em .05em #0003; }
.sticker {
  display: inline-block; padding: .05em .2em .08em; font: 400 .62em/1 var(--rf, "Rubik Mono One"); vertical-align: .14em;
  background: var(--bg, var(--yellow)); color: var(--fg, var(--ink)); rotate: var(--r, -4deg); box-shadow: 0 .05em .08em #0003;
  clip-path: polygon(0 6%, 8% 0, 30% 4%, 62% 0, 100% 5%, 97% 50%, 100% 94%, 70% 100%, 40% 96%, 4% 100%, 0 60%);
}

/* the system alert that interrupts every jam */
.alert {
  display: inline-flex; align-items: center; gap: .6em; vertical-align: .3em; height: 3.4em; padding: 0 .8em;
  background: #2a2a2c; color: #eee; border-radius: .5em; font: 500 .2em/1.25 -apple-system, "Segoe UI", sans-serif;
  box-shadow: 0 .5em 1.2em #0005; letter-spacing: 0; word-spacing: 0; text-align: left; text-align-last: left;
}
.alert b { font-size: 1.8em; color: #ffcc00; }
.alert i { display: block; font-style: normal; opacity: .7; }
.alert button { font: inherit; color: inherit; border: 0; padding: .2em .7em; border-radius: .4em; background: #4a4a4e; cursor: pointer; transition: background .15s, transform .1s; }
.alert button:hover { background: #5d5d62; }
.alert button:active { transform: scale(.94); }

.site-foot canvas { display: block; width: 100%; height: clamp(180px, 22vw, 340px); mix-blend-mode: multiply; }

.site-head .home { color: inherit; }

/* ---------- hero: one justified sentence that fills the first screen ---------- */
.hero { min-height: 100vh; display: grid; align-content: start; padding: 13vh 6vw 7vh; overflow-x: clip; } /* sits high; the spare line for an open key is left at the bottom */
#say { font-size: 6vw; line-height: 1.12; text-align: justify; text-align-last: justify; hyphens: none; }

/* key elements: the only things allowed to change the layout */
.key { position: relative; display: inline-block; vertical-align: top; text-decoration: none; color: inherit; cursor: pointer; }
.key .k-title { position: absolute; left: 0; top: 0; line-height: 1.12; white-space: nowrap; transform-origin: 0 .1em; transition: transform .5s var(--ease-pop), color .2s; }
.key .k-title::after { /* keys always wear a red wavy underline, so you know they open */
  content: ""; position: absolute; left: 0; right: 0; bottom: .06em; height: .13em;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 8'%3E%3Cpath d='M0 4 Q5 0 10 4 T20 4 T30 4 T40 4' fill='none' stroke='%23ff4a2e' stroke-width='3.6'/%3E%3C/svg%3E") 0 0 / .4em 100% repeat-x;
}
.key .k-title sup { font: 500 .2em var(--mono); color: var(--riso); vertical-align: 2.6em; margin-left: .2em; letter-spacing: 0; }

.k-expand { width: var(--w0); height: 1.12em; transition: width .55s var(--ease-pop), height .55s var(--ease-pop); }
.k-expand.open { width: var(--w1, 6em); height: 2.5em; }
.k-expand.open .k-title { transform: scale(.34); }
.k-expand.open .k-title::after { opacity: 0; }
.k-detail {
  position: absolute; inset: .5em 0 0 0; display: grid; grid-template-columns: auto 1fr; gap: .9em; align-items: start;
  font: 400 .19em/1.35 var(--mono); letter-spacing: 0; word-spacing: 0; text-align: left; text-align-last: left;
  opacity: 0; translate: 0 .6em; transition: opacity .25s, translate .4s var(--ease-soft); pointer-events: none;
}
.k-expand.open .k-detail { opacity: 1; translate: 0 0; transition-delay: .18s; }
.k-detail img { height: 9.4em; aspect-ratio: 4 / 3; object-fit: cover; border: .35em solid #fff; box-shadow: 0 .4em .8em -.3em #0006; rotate: -2deg; }
.k-detail b { display: block; font: 800 1.7em/1 var(--display); letter-spacing: -.03em; margin-bottom: .4em; }
.k-detail em { display: inline-block; margin-top: .7em; font: 700 1.4em var(--hand); font-style: normal; color: var(--riso); }

/* hero layout (js/hero.js): every token is a cell placed by translate, so reflow can glide;
   the sentence stays hidden until fonts are in and the first layout is done */
#say { position: relative; }
#say:not(.laid) { visibility: hidden; }
#say .cell { position: absolute; left: 0; top: 0; white-space: nowrap; line-height: 1.12; pointer-events: none; transition: translate .3s var(--ease-glide); }
#say .cell > *, #say .key { pointer-events: auto; } /* only what is drawn takes the pointer, never a cell's empty box */
#say .key { display: block; margin: 0; transition: translate .3s var(--ease-glide), width .3s var(--ease-glide), height .3s var(--ease-glide); }
#say.still .cell, #say.still .key { transition: none; }
#say .k-expand .k-title { transition: opacity .15s, color .2s; }
#say .k-expand.open .k-title { transform: none; opacity: 0; }
/* the open card has its final size from the start, so nothing inside reflows while the key grows */
#say .k-detail { white-space: normal; }
#say .k-expand.open .k-detail { pointer-events: auto; transition: opacity .13s .09s, translate .2s var(--ease-soft) .09s; }
/* a red pen loops the key once it has opened */
#say .k-circle { position: absolute; z-index: -1; inset: -.3em -.4em; width: calc(100% + .8em); height: calc(100% + .6em); overflow: visible; pointer-events: none; }
#say .k-circle path { fill: none; stroke: var(--riso); stroke-width: 2.4px; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1; opacity: 0; transition: stroke-dashoffset .2s, opacity .2s; }
#say .k-expand.open .k-circle path { stroke-dashoffset: 0; opacity: 1; transition: stroke-dashoffset .38s cubic-bezier(.5, .1, .3, 1), opacity 0s; }
#say .k-detail { --dfs: .22; inset: 0 auto auto 0; width: calc(var(--ow) / var(--dfs)); height: calc(2.24em / var(--dfs)); grid-template-rows: 100%; gap: .8em; align-items: center; font-size: calc(var(--dfs) * 1em); }
#say .k-detail img { height: calc(2.24em / var(--dfs) - .8em); width: auto; aspect-ratio: auto; border-width: .3em; rotate: -1.5deg; }
#say .k-detail img.pixel { image-rendering: pixelated; }
#say .k-detail em { font-size: 1.5em; }

/* small things in the sentence */
/* real emoji, set in the system emoji face */
.emoji { display: inline-block; font: 400 .78em/1 "Segoe UI Emoji", "Apple Color Emoji", "Noto Color Emoji", sans-serif; vertical-align: .02em; }
.sunmoon { display: inline-grid; border: 0; padding: 0; background: none; cursor: pointer; }
.sunmoon span { grid-area: 1 / 1; transition: transform .6s var(--ease-pop), opacity .3s; }
.sunmoon .moon, .sunmoon[aria-pressed="true"] .sun { opacity: 0; transform: rotate(-120deg) scale(.4); }
.sunmoon[aria-pressed="true"] .moon { opacity: 1; transform: none; }
.die { font-size: inherit; }

/* a handwritten aside scribbled above the key it belongs to */
.k-title .note { position: absolute; right: -.5em; bottom: 78%; font: 700 .4em/1 var(--hand); color: var(--riso); rotate: -7deg; letter-spacing: 0; white-space: nowrap; }
/* a pixel die: square pips, a hard offset shadow, and a stepped tumble when rolled */
.die {
  display: inline-grid; grid-template: repeat(3, 1fr) / repeat(3, 1fr); gap: .05em; width: .66em; height: .66em; padding: .09em; vertical-align: middle; /* a grid takes its baseline from its first pip row, so align by the middle */
  background: var(--paper-2); border: .045em solid var(--ink); box-shadow: .06em .06em 0 var(--ink); cursor: pointer;
}
.die i { background: var(--ink); visibility: hidden; }
.die[data-face="1"] i:nth-child(5),
.die[data-face="2"] i:is(:nth-child(1), :nth-child(9)),
.die[data-face="3"] i:is(:nth-child(1), :nth-child(5), :nth-child(9)),
.die[data-face="4"] i:is(:nth-child(1), :nth-child(3), :nth-child(7), :nth-child(9)),
.die[data-face="5"] i:is(:nth-child(1), :nth-child(3), :nth-child(5), :nth-child(7), :nth-child(9)),
.die[data-face="6"] i:is(:nth-child(1), :nth-child(3), :nth-child(4), :nth-child(6), :nth-child(7), :nth-child(9)) { visibility: visible; }
.die.rolling { animation: tumble .48s steps(6) both; }
/* toys answer on press, not on release */
.die, .sunmoon { transition: scale .1s ease-out; }
.die:active, .sunmoon:active { scale: .9; }
@keyframes tumble { 0% { transform: none; } 50% { transform: translateY(-.35em) rotate(180deg); } 100% { transform: rotate(360deg); } }

/* the Soft Console desk inside its key: the real kit, dark, at its own pixel scale */
.sc-desk { display: grid; gap: 10px; align-content: center; padding: 12px; width: max-content; border-radius: 16px; background: var(--surface); color: var(--text-1); box-shadow: var(--raised-2); font: 500 13px/1 var(--font-data); }
.sc-desk-row { display: flex; align-items: center; gap: 10px; }
.sc-desk .sc-val { margin-left: auto; color: var(--accent-text); font-size: 18px; }
.sc-desk .sc-jog { display: block; }
#say .k-sc .k-detail a { color: inherit; text-decoration: none; }
/* the kit is sized in px; on small screens the open key is shorter than the desk, so the desk shrinks to fit */
@media (max-width: 600px) { #say .sc-desk { zoom: .6; } }
@media (min-width: 601px) and (max-width: 900px) { #say .sc-desk { zoom: .8; } }
@media (prefers-reduced-motion: reduce) { #say .cell, #say .key, #say .k-title { transition: none; } }

/* ---------- three lines: each a little wider than the page, drifting slowly on a loop; scrolling pushes them ---------- */
.lines { padding: 10vh 0 12vh; overflow: hidden; }
.line { position: relative; border-top: 1px solid var(--ink); padding: 2.2vh 0; }
.line:last-child { border-bottom: 1px solid var(--ink); }
.line .label { position: absolute; left: 26px; top: -14px; z-index: 2; background: var(--paper); padding: 0 8px; }
.track { display: flex; width: max-content; white-space: nowrap; will-change: transform; }
.set { display: flex; gap: .5em; padding-right: .5em; align-items: center; }
.mechanics .track { font: 400 max(36px, 4.4vw)/1.1 var(--serif); }
.mechanics .emoji { margin-right: .45em; }
.tools .track { font: 800 max(34px, 4.6vw)/1.1 var(--display); letter-spacing: -.04em; text-transform: uppercase; }
.offduty .track { font: 400 max(13px, 1.75vw)/1 var(--mono); text-transform: uppercase; letter-spacing: .08em; }
.offduty .set { gap: 1.2em; padding: .4em 1.2em .4em 0; }
.offduty .stamp { border: 2px solid var(--ink); padding: .7em 1em; rotate: var(--r, 0deg); transition: rotate .3s var(--ease-pop), color .2s, background-color .2s, border-color .2s; }
.offduty .stamp.red { border-color: var(--riso); color: var(--riso); }
/* a stamp straightens and inks in under the pointer; its size never changes */
.offduty .stamp:hover { rotate: 0deg; border-color: var(--riso); background: var(--riso); color: var(--paper); }

/* ---------- sections ---------- */
.block { padding: 12vh 6vw; }
.block > header { display: flex; align-items: baseline; gap: 20px; margin-bottom: 6vh; }

/* ---------- work: one clipping per project, each one link out ---------- */
.clip {
  display: grid; grid-template-columns: 70px minmax(240px, 1fr) 1.1fr; gap: 4vw; align-items: center;
  padding: 7vh 0; border-top: 1px solid var(--ink); text-decoration: none; color: inherit;
}
.clip:nth-of-type(even) { grid-template-columns: 70px 1.1fr minmax(240px, 1fr); }
.clip:nth-of-type(even) .plate { order: 3; }
.clip .no { align-self: start; font: 400 12px var(--mono); letter-spacing: .12em; color: var(--pencil); }
.plate { position: relative; background: var(--paper-2); padding: 14px; box-shadow: 0 18px 30px -22px #0006; rotate: var(--r, -1deg); transition: rotate .5s var(--ease-pop); }
.plate img { display: block; width: 100%; aspect-ratio: var(--ar, 4 / 3); object-fit: cover; }
.plate canvas { position: absolute; inset: 14px; width: calc(100% - 28px); height: calc(100% - 28px); display: block; background: var(--paper-2); } /* hover turns the ink into the picture (ink-dither.js) */
.plate.sq { width: min(100%, 420px); justify-self: center; }
.clip:hover .plate { rotate: 0deg; }
.clip h3 { font: 800 clamp(40px, 5vw, 84px)/.95 var(--display); letter-spacing: -.05em; transition: color .2s; }
.clip h3 i { font: italic 400 1.04em var(--serif); letter-spacing: -.01em; }
.clip p { font: 400 15px/1.6 var(--mono); max-width: 46ch; margin: 18px 0 20px; }
.clip .meta { display: flex; flex-wrap: wrap; gap: 10px; font: 400 11px/1 var(--mono); text-transform: uppercase; letter-spacing: .1em; }
.clip .meta span { border: 1.5px solid currentColor; padding: .6em .8em; }
.clip .meta .red { color: var(--riso); }
.clip .go { display: inline-block; margin-top: 22px; font: 700 28px var(--hand); color: var(--riso); transition: translate .35s var(--ease-pop); }
.clip:hover .go { translate: 8px 0; }
.clip:hover h3 { color: var(--riso); }

/* the smaller things: a typed list, one line each */
.small { border-top: 2px solid var(--ink); margin-top: 4vh; }
.small a { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) minmax(0, 1fr); gap: 24px; align-items: baseline; padding: 16px 0; border-bottom: 1px solid var(--ink); text-decoration: none; font: 400 16px/1.4 var(--type); }
.small a b { font: 400 26px/1.1 var(--serif); }
.small a span:last-child { justify-self: end; text-align: right; color: var(--pencil); text-transform: uppercase; font-size: 12px; letter-spacing: .1em; }
.small a:hover b, .small a:hover span:last-child { color: var(--riso); }

/* ---------- about: ink portrait (hover shows the photo), bio ---------- */
.intro { display: grid; grid-template-columns: minmax(280px, 36vw) 1fr; gap: 5vw; align-items: center; }
.portrait { position: relative; }
.portrait canvas { width: 100%; aspect-ratio: 4 / 3; display: block; mix-blend-mode: multiply; cursor: crosshair; }
.portrait .bubble {
  position: absolute; left: 0; top: 14%; padding: .35em .7em .45em; border: 2px solid var(--ink); border-radius: 1.2em; background: var(--paper-2);
  font: 700 clamp(20px, 1.8vw, 30px)/1 var(--hand); color: var(--riso); white-space: nowrap; pointer-events: none;
  rotate: -6deg; scale: .4; opacity: 0; transform-origin: 85% 110%; transition: scale .3s var(--ease-pop), opacity .12s;
}
.portrait .bubble::after { /* the tail points down at Timmie */
  content: ""; position: absolute; right: 18%; bottom: -12px; width: 18px; height: 18px; background: inherit;
  border: solid var(--ink); border-width: 0 2px 2px 0; rotate: 45deg;
}
.portrait:hover .bubble { scale: 1; opacity: 1; transition-delay: 85ms; }
.bio { font-size: clamp(40px, 5.4vw, 96px); line-height: 1.1; }
.aside { font: 700 1.05em/1 var(--hand); color: var(--riso); display: inline-block; rotate: -3deg; }

/* ---------- contact: objects on the desk, one row at any width ---------- */
/* every size in the desk is in em, so the whole row scales with the window: 4 objects of 15em and 3 gaps of 4em, plus a margin */
.desk { font-size: min(16px, 88vw / 74); display: grid; grid-auto-flow: column; grid-auto-columns: 15em; column-gap: 4em; justify-content: center; align-items: end; padding-top: 6vh; }
.gadget { display: grid; justify-items: center; gap: 1.375em; text-decoration: none; color: inherit; outline: none; }
.gadget .obj { position: relative; display: block; width: 15em; height: 10.625em; }
.gadget .tag { text-transform: uppercase; letter-spacing: .14em; font-size: max(10px, .75em); white-space: nowrap; transition: color .2s; }
.gadget:hover .tag, .gadget:focus-visible .tag { color: var(--riso); }
.gadget:focus-visible .obj { outline: 2px dashed var(--riso); outline-offset: 10px; }
/* each object answers after a short rest, never on a pointer that only passes */
.gadget .obj * { transition-delay: 85ms; }

/* email: the flap lifts, the letter slides up */
.g-mail .obj { perspective: 43.75em; }
.g-mail .obj > span { position: absolute; }
.env-back, .env-front { inset: 1.25em 0 0; }
.env-back { background: #cdb88f; }
.letter {
  left: 0.75em; right: 0.75em; bottom: 0.5em; height: 8em; z-index: 1; padding: 0.875em 0.75em;
  background: var(--paper-2); box-shadow: 0 0.0625em 0.1875em #0002; font: 500 0.6875em/1.4 var(--mono); letter-spacing: 0; text-align: center;
  transition: translate .35s var(--ease-glide);
}
.letter i { display: block; font: 700 1.375em/1 var(--hand); color: var(--riso); margin-bottom: 0.375em; }
.env-front { z-index: 2; background: linear-gradient(170deg, #efe4cb, #e2d2b0); clip-path: polygon(0 0, 50% 52%, 100% 0, 100% 100%, 0 100%); filter: drop-shadow(0 -0.0625em 0 #0001); }
.env-flap {
  z-index: 3; left: 0; right: 0; top: 1.25em; height: 5.5em; background: linear-gradient(180deg, #e6d7b6, #d8c59d);
  clip-path: polygon(0 0, 100% 0, 50% 100%); transform-origin: 50% 0; transition: transform .32s var(--ease-soft), z-index 0s .16s;
}
.env-seal {
  z-index: 4; left: calc(50% - 0.9375em); top: 5.75em; width: 1.875em; height: 1.875em; border-radius: 50%;
  display: grid; place-items: center; background: radial-gradient(circle at 35% 30%, #ff7a5f, var(--riso) 55%, #c22f17); color: #fff6; font: 800 0.875em/1 var(--display);
  box-shadow: 0 0.125em 0.1875em #0004; transition: opacity .12s, scale .2s var(--ease-pop);
}
.g-mail:hover .env-flap, .g-mail:focus-visible .env-flap { transform: rotateX(180deg); z-index: 0; transition: transform .32s var(--ease-soft) 85ms, z-index 0s 230ms; }
.g-mail:hover .env-seal, .g-mail:focus-visible .env-seal { opacity: 0; scale: .6; }
.g-mail:hover .letter, .g-mail:focus-visible .letter { translate: 0 -4em; transition-delay: 200ms; }

/* linkedin: a business card slides out of its leather holder */
.bizcard {
  position: absolute; left: 1.875em; right: 1.875em; bottom: 1.375em; height: 6.5em; z-index: 1; padding: 0.75em 0.875em;
  background: var(--paper-2); box-shadow: 0 0.0625em 0.1875em #0003; display: grid; align-content: start; gap: 0.125em; text-align: left;
  transition: translate .4s var(--ease-pop), rotate .4s var(--ease-pop);
}
.bizcard b { font: 800 1.375em/1 var(--display); letter-spacing: -.04em; }
.bizcard i { font: 400 0.9375em/1 var(--serif); font-style: normal; color: var(--pencil); }
.bizcard .in { position: absolute; right: 0.75em; top: 0.75em; width: 1.5em; height: 1.5em; border-radius: 0.25em; background: #0a66c2; color: #fff; display: grid; place-items: center; font: 800 0.9375em/1 var(--display); letter-spacing: -.04em; }
.holder {
  position: absolute; left: 0.875em; right: 0.875em; bottom: 0; height: 6.875em; z-index: 2; border-radius: 0.625em 0.625em 1em 1em;
  background: radial-gradient(120% 90% at 30% 10%, #8a4c32, #5c2f1d 70%); box-shadow: 0 0.875em 1.375em -0.75em #0008, inset 0 0.125em 0 #ffffff1f;
  outline: 0.0938em dashed #e9c79a80; outline-offset: -0.5em;
}
.holder::before { content: ""; position: absolute; left: 50%; top: -0.0625em; width: 3.5em; height: 0.875em; translate: -50% 0; border-radius: 0 0 1.75em 1.75em; background: #3e1f12; }
.g-in:hover .bizcard, .g-in:focus-visible .bizcard { translate: 0 -4.125em; rotate: -3deg; }

/* x: a mechanical keycap that sinks under the pointer and bottoms out on press */
.g-x .obj { display: grid; place-items: center; }
.cap {
  position: relative; width: 7.375em; height: 7.375em; border-radius: 1.25em; color: #f2f2f2; display: grid; place-items: center;
  background: linear-gradient(180deg, #48484b, #1d1d1f); box-shadow: 0 0.6875em 0 #0c0c0d, 0 1.375em 1.625em -0.5em #0008, inset 0 0.125em 0 #ffffff26;
  transition: translate .12s var(--ease-soft), box-shadow .12s var(--ease-soft);
}
.cap::before { content: ""; position: absolute; inset: 0.5625em 0.75em 1.0625em; border-radius: 0.8125em; background: linear-gradient(180deg, #2b2b2d, #353538); box-shadow: inset 0 0.0625em 0.125em #0008; }
.cap svg { position: relative; width: 2.375em; height: 2.375em; margin-bottom: 0.5em; }
.g-x:hover .cap, .g-x:focus-visible .cap { translate: 0 0.25em; box-shadow: 0 0.4375em 0 #0c0c0d, 0 1em 1.25em -0.5em #0008, inset 0 0.125em 0 #ffffff26; }
.g-x:active .cap { translate: 0 0.625em; box-shadow: 0 0.0625em 0 #0c0c0d, 0 0.375em 0.625em -0.375em #0008, inset 0 0.125em 0 #ffffff1a; transition-duration: .05s; transition-delay: 0s; }

/* github: a spiral notepad; the top sheet holds the contribution graph and lifts to show the handle */
.g-gh .obj { perspective: 43.75em; }
.pad-under, .pad-top { position: absolute; left: 1.75em; right: 1.75em; top: 1.25em; bottom: 0; background: var(--paper-2); }
.pad-under { display: grid; align-content: end; padding: 0 1em 1em; box-shadow: 0 .875em 1.375em -.75em #0006; font: 500 .6875em/1.2 var(--mono); letter-spacing: 0; }
.pad-under b { display: block; font: 700 2em/1 var(--hand); color: var(--riso); }
.pad-top {
  z-index: 1; display: grid; grid-template-rows: auto 1fr; gap: .5em; padding: 1.25em .875em .875em; box-shadow: 0 .0625em .1875em #0003;
  transform-origin: 50% 0; transition: transform .32s var(--ease-soft);
}
.pad-top svg { width: 1.5em; height: 1.5em; color: var(--ink); }
.pad-top i { background: url("assets/img/gh-graph.svg") center / contain no-repeat; }
.pad-rings { position: absolute; z-index: 2; left: 2.5em; right: 2.5em; top: .75em; height: 1em; background: repeating-linear-gradient(90deg, #3a3a3c 0 .3125em, transparent .3125em 1.125em); border-radius: .25em; }
.g-gh:hover .pad-top, .g-gh:focus-visible .pad-top { transform: rotateX(70deg); }

/* links answer on press, not on release */
.clip .plate { transition: rotate .5s var(--ease-pop), scale .12s ease-out; }
.clip:active .plate { scale: .98; }
.gadget:active .obj { scale: .96; }
.gadget .obj { transition: scale .1s ease-out; }
.small a { transition: background-color .15s; }
.small a:active { background: #2b0d0d0d; transition: none; }

/* touch has no hover: the desk objects rest open, so the email, the card and the handle can be read */
@media (hover: none) {
  .g-mail .env-flap { transform: rotateX(180deg); z-index: 0; }
  .g-mail .env-seal { opacity: 0; }
  .g-mail .letter { translate: 0 -4em; }
  .g-in .bizcard { translate: 0 -4.125em; rotate: -3deg; }
  .g-gh .pad-top { transform: rotateX(70deg); }
}

@media (max-width: 820px) {
  .clip, .clip:nth-of-type(even) { grid-template-columns: 1fr; gap: 20px; }
  .clip:nth-of-type(even) .plate { order: 0; }
  .small a { grid-template-columns: 1fr; gap: 4px; }
  .intro { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } *, *::before, *::after { transition-duration: 0s !important; animation-duration: 0s !important; } }
@media (max-width: 720px) { .site-head nav { gap: 14px; } }
@media (max-width: 400px) { .site-head { padding: 16px; letter-spacing: .06em; } .site-head nav { gap: 12px; } }
@media (max-width: 359px) { .site-head .cn { display: none; } }
