/* =================================================================
   Giovanny — Portfolio stylesheet

   Design: the "Kage" landing page from ThreeUI Community (MIT), see
   secret-pathways-assets/LICENSE.md. Faces come from
   secret-pathways-assets/fonts.css (Onest, NotoJP, Wordmark), linked
   in index.html before this file.

   1 · Wordmark glyphs  — the Poppins letters the name needs
   2 · KAGE             — the authored stylesheet, as written. Only two
                          kinds of edit: asset urls start with ../../
                          because this file lives in assets/css/, and
                          the two chapter scrims keyed by id follow the
                          portfolio ids (#pathways → #work,
                          #eternity → #contact).
   3 · PORTFOLIO        — the portfolio's own pieces in that grammar.
   ================================================================= */

/* ------------------------------------------------ 1 · wordmark glyphs
   Kage's "Wordmark" face is a Poppins subset carrying only the letters
   of KAGE. This is the same Poppins SemiBold cut with the capitals the
   name needs (G I O V A N Y). Declared after fonts.css it answers for
   every letter, and the letters both files share are identical. */
@font-face{font-family:'Wordmark';font-style:normal;font-weight:600;font-display:block;src:url(data:font/woff2;base64,d09GMgABAAAAAAgoAAwAAAAADfgAAAfZAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGx4cLgZgAIE8CpEgjVYLPAABNgIkA3QEIAWDVAcgGx8LUVSTeiDTSFk4fz94QJ1vT5I/SXYRXTogTkrkTwiTcwQTAG4FgCQ+grHj7ach3NZZ/89HBTOS2EZswDYqLAwUTMDIBv79DOsjoi7WWn3VEi6Vn6/hxPdFJZlg3mhUmkWaeuIbppVQNGVSbVx1E9nXWPU114EANCusPcQz8W0B2TgYLmtLCsHdooNSK5fU1PbdxQJdUEkgRxHu7agqWUAGyFAW6JatdZUo4y6xTfNnkYzsULXvzUF8J4fw6XGW/f8eNU677PbhFT0pb5L7LfAP4WTIKTW8AAWruACHT1S4DvUymfg8yJPE2MhmtrKTveRRSCXV1FJPM130wFzocweJGTtexP5tr9iz9pQ9aU/Y4/aoPWQP2H32R/uD/d5+Z7+2n9pPAExJAis14UOCmxXyda36XuxAxu1ApFZpc8qm5/TaCBQ1+kyOUkq5czKX3WyUv8LNWu66K9xs5a51jJ4z59asnPlzli/J8ucYb36G57jNbm5Bfl6tCgrzgj8jk0gxkdRhWvybvqLDS0kmUpdN4mokyoVxdEZ+FEVi8ogOk76OIsKaZODhCjbcDN/D6ZUqHabzzLvqO4jJtNbCJMTkBR1eWqHzRb2RBo0WxQWm3+VzgyBXvHleFFWG51Zo5V0zY8ng623cDKXF5LAxVyeTTKQIj+tv0M2u8H4Vk5E174HTxD1boys6vMTEeUYxQbTbzE+E0gzhtSYCDiHh/tVuoMtNqc4rKign7PJwMzy6v9rETZxbS74WHskdCYh9lDs6wyuSOsPIYlNTO1vX9flaZf5Gk/sRLzsjzYtP7f+bNy+bxEUxeeBMPM3vSP3WBR2eY2L/6ViK8uL+El1mSsv7C9CiyBQW/0pUf6swjhZfQJn5r9iliSgSv3IiH8Obb8696L8l7rtj+oyuvPfo3f41rvQXw5vPSB+A482VOiTk5XH1rnxTUPhr9MNeYC/8/lXA4Fy5stf4pk4uPZ16OfUCvcCeL3u+tDeFrPx33Gvlv5X/pv79t/JfS7c3YE0sPdzaWnp47brSo84/wUfXtcoHJkxF0akDExSqAebFKLp4gFkFJoVVfbw5LRzELDJps5KVOSjzJ4PBJmiNLgX1JdbsosJ4TbA9xaqXQ7nvrIBXWp2aIrcwWHpEINSfc20VGmR8ODqZpcyyZ7mkN/Z/hTCtPnwlUzcmZ4zD5OXn7zcRbgK+9nTJ5fYT4cXhDpujx+ozAWfBWBO1Wq4e761LFPuk4jnVLUXZDVk9DI0N7wN4PDmG84U8z6JN9WuOgA4VzVcsTAelBQZvWBSPIMlKKZqehqms+QbfjqLtZbsak3KyeoRUz98qxXg8gsRgXIRy+SQPuKbT0h29jPrCR0CxNQ2Gw9NZOl06Cw6HEXbQMQtmEFBUQgFbqcxnUwmUAIsy/9/byWR0MnyO+vtf8+k6KeHADArn8UhBAFvM5YB7Sx3+OGIuzgia5C80s3hWZUZNdbYjd+v2au/O1FCjwoLCUUj1os37YR4uhGGcQNh8AgMfaof61M74tav9166ZwV8SJiVMAhdk619nvN5Jy561e1Y28HxeEuyD4iaEbaEksCUWEekSQ/opP6QUF/eRGUqmKSIT2yKjllksUW1tkQn5a7PHW8CFnbtsu8D5vzBi22Xj/EVXjouATGC+jX/vvm23jX//gQ3Qu7UbTG0Ws6mt3RAX32YwtpktxrZ2QxxeakLZSRIJ22pCBIIYhG2VSNhJMagAvOmWG0BG95vtGesfUE4fF1Y/hhwUQudrCBwzZPjLUuut3aLnD3L4edDcR1PmseSgUAjTilCOKQNVg+07/+9c9X/n7P2e+zxBxs7Xxz7bPr85tngWPhMH45OJqmyxFI8K2Kq1e9oDu4wMXJItJapDN/tDMpIOQaIp7jIGw11BQHSIpEMyJhifLK4skegs9eahUXM2N3ryxXqdVqznh45Qzhka0ZBk1pVIxJV6IHVGZinlJKwZT8wZpm0wx+vKJZKqUL24qkwcpC0lqdLAaZCbUoiwJHgBMDCi/bu0dl81VlgiCc+fnUYztnTKvFmYUqbQdxmZmCRHSlSHhhBV2WLptleQjKRDkGiKu4xxsg+y7379xvbE1rnz1bbPQ74OAq//6wPQGVMIAlMPtnna9OD5tt6jV4wX5YdvXNOLyCGa7E2lOUA2OM/VqdtuOLzY1I//tYeLy4ul1I2OlUf1PW8Phc/+ffh3Pe2cK6lC97+bYCD/+HXT9vx9+BOlnftBjWOcvgjePb5zPWA7JYPJzjjwdg4DPs6zgJ9zLdA6VwKx82QwybkGcHmQXTwpz7FMLiCmlJdbJxYRk28Qk38SU3NZJyu5W55klhzByI9YI4tYIxtZ0x+0iZh4lZiYYSmA3pW8iEsPmX9r7SoygRqJA4cdyqZO6nA6OXb0Pc71iMDnC0Qyi7cQxWNUzHTQSAaaPFxesd6nXn0W9wEN9NBDB908xO3cTjfVdNFIBz268Ta6L9vCbbTTRT23s5M429hFOx1qsJE266+6lb3U0kojT9FOCzXcw23cwR3cw2YC4uzkYXwG0z4ejmAqVvEAe4Ktq6eXFirpYoWnAxiEDvW3KvvcxR352nwCGqgFwO3SattpopZq4ton6aWHhtviqLlveJ9wPY3hwb1UcRvVtNPK7fNgHe12ZRs1dDGojnEM3ChJYu5q9kfuIgEA) format('woff2');}

/* =================================================================
   2 · KAGE
   ================================================================= */
/* ============================================================= tokens */
:root{
  --ink:#05070a;          /* page black */
  --ink-2:#0a0e12;        /* raised black */
  --bone:#dfe7e0;         /* the pale sage white of the wordmark */
  --bone-dim:#aab4ad;
  --muted:#78837c;
  --line:rgba(223,231,224,.13);
  --line-soft:rgba(223,231,224,.07);
  --vermilion:#e0231c;
  --ember:#ff5a3c;
  --gold:#c9a24a;
  --pad:clamp(20px, 3.4vw, 56px);
  --nav-h:84px;
  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-out:cubic-bezier(.16,1,.3,1);
  --ease-io:cubic-bezier(.65,0,.35,1);
}
*,*::before,*::after{box-sizing:border-box}
html{ -webkit-text-size-adjust:100%; scroll-behavior:auto; }
body{
  margin:0; background:var(--ink); color:var(--bone);
  font-family:'Onest',system-ui,-apple-system,'Helvetica Neue',sans-serif;
  font-weight:300; font-size:16px; line-height:1.6;
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
}
body.is-locked{ overflow:hidden; height:100vh; }
::selection{ background:var(--vermilion); color:#fff; }
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}

/* ============================================================= layers */
#gl{
  position:fixed; inset:0; width:100%; height:100%;
  display:block; z-index:0; background:#05070a;
}
#grain{
  position:fixed; inset:-1px; z-index:60; pointer-events:none;
  opacity:.055; mix-blend-mode:overlay;
  background-repeat:repeat; background-size:180px 180px;
}
#vignette{
  position:fixed; inset:0; z-index:55; pointer-events:none;
  background:radial-gradient(125% 95% at 50% 42%, transparent 40%, rgba(2,4,6,.55) 100%);
}
.page{ position:relative; z-index:10; }

/* ============================================================= type */
.eyebrow{
  font-size:10px; font-weight:500; letter-spacing:.22em; text-transform:uppercase;
  color:var(--bone-dim); text-shadow:0 1px 16px rgba(3,6,8,.9);
}
.jp{ font-family:'NotoJP','Onest',sans-serif; font-weight:400; }
h1,h2,h3{ font-weight:400; margin:0; letter-spacing:-.005em; }
.display{
  text-transform:uppercase; line-height:1.055; letter-spacing:-.012em;
  font-weight:400; text-shadow:0 2px 34px rgba(3,6,8,.72);
}
.h-hero{ font-size:clamp(26px,3.05vw,46px); }
.h-sec{ font-size:clamp(30px,4.0vw,60px); }
.body-lg{ font-size:clamp(14px,1.02vw,17px); line-height:1.72; color:#b4bfb7; font-weight:300; text-shadow:0 1px 20px rgba(3,6,8,.88); }
.body{ font-size:14px; line-height:1.68; color:#9aa5a0; font-weight:300; text-shadow:0 1px 18px rgba(3,6,8,.85); }
.num{ font-size:clamp(26px,2.5vw,36px); font-weight:300; letter-spacing:-.02em; color:var(--bone); font-variant-numeric:tabular-nums; }

/* ============================================================= reveal */
[data-rv]{ opacity:0; }
[data-rv="up"]{ transform:translate3d(0,26px,0); }
[data-rv="fade"]{ transform:none; }
[data-rv].rv-in{ opacity:1; transform:none;
  transition:opacity .9s var(--ease-out), transform 1.05s var(--ease-out); }
.mask-line{ display:block; overflow:hidden; }
.mask-line:not(.word-reveal) > span{ display:block; transform:translate3d(0,110%,0); }
.rv-in .mask-line:not(.word-reveal) > span, .mask-line:not(.word-reveal).rv-in > span{ transform:none; }
.mask-line:not(.word-reveal) > span{ transition:transform 1.05s var(--ease-out); }
.word-mask{ display:inline-block; overflow:hidden; vertical-align:top; }
.word{
  display:inline-block; opacity:0; transform:translate3d(0,112%,0); will-change:transform,opacity;
  transition:transform .82s var(--ease-out), opacity .5s var(--ease-out);
  transition-delay:var(--word-delay,0ms);
}
.word-reveal.rv-in .word{ opacity:1; transform:none; }

/* ============================================================= preloader */
#pre{
  position:fixed; inset:0; z-index:100; background:#05070a;
  display:flex; align-items:center; justify-content:center;
  transition:opacity .8s var(--ease), visibility .8s;
}
#pre.done{ opacity:0; visibility:hidden; pointer-events:none; }
.pre-in{ width:min(420px,74vw); text-align:center; }
.pre-mark{ margin:0 auto 26px; width:44px; height:44px; opacity:.9; }
.pre-mark svg{ width:100%; height:100%; display:block; }
.pre-jp{ font-size:12px; letter-spacing:.5em; color:var(--bone-dim); margin-bottom:20px; }
.pre-bar{ position:relative; height:1px; background:rgba(223,231,224,.14); overflow:hidden; }
.pre-bar i{ position:absolute; inset:0 100% 0 0; background:var(--bone); transition:right .35s linear; }
.pre-meta{ display:flex; justify-content:space-between; margin-top:12px;
  font-size:10px; letter-spacing:.2em; text-transform:uppercase; color:var(--muted); }
.pre-meta b{ font-weight:500; color:var(--bone-dim); font-variant-numeric:tabular-nums; }

/* ============================================================= nav */
.nav{
  /* Width comes from --vw, not from right:0. A fixed element resolves its
     inset against the initial containing block, and the page's own horizontal
     overflow makes that block wider than the screen — 437 against a 390 phone,
     860 against a 768 tablet — which carried the burger off the right edge.
     --vw is the layout viewport, written on every resize. */
  position:fixed; top:0; left:0; width:var(--vw, 100%); height:var(--nav-h); z-index:50;
  display:flex; align-items:center; gap:24px; padding:0 var(--pad);
  transition:transform .55s var(--ease);
}
/* The sticky wash sits on its own layer rather than on the bar. A
   backdrop-filter promotes its element to the containing block for any
   position:fixed descendant, and the bar holds the mobile menu sheet — put the
   blur here and the sheet was measured against an 84px bar instead of the
   frame, for as long as the blur took to fade. */
.nav::before{
  content:''; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:rgba(5,7,10,.62);
  backdrop-filter:blur(14px) saturate(1.1); -webkit-backdrop-filter:blur(14px) saturate(1.1);
  opacity:0; transition:opacity .5s linear;
}
.nav.stuck::before{ opacity:1; }
.nav::after{
  content:''; position:absolute; left:var(--pad); right:var(--pad); bottom:0; height:1px;
  background:var(--line-soft); opacity:0; transition:opacity .5s;
}
.nav.stuck::after{ opacity:1; }
.nav.hide{ transform:translate3d(0,-101%,0); }
.brand{ display:flex; align-items:center; gap:11px; flex:0 0 auto; }
.brand svg{ width:34px; height:34px; display:block; }
.brand-tx{ display:flex; flex-direction:column; line-height:1; gap:3px; }
.brand-tx b{ font-size:12px; font-weight:500; letter-spacing:.26em; }
.brand-tx i{ font-style:normal; font-size:8px; letter-spacing:.34em; color:var(--muted); }
.nav-links{ display:flex; gap:clamp(18px,2.6vw,46px); margin-left:auto; }
.nav-link{
  position:relative; font-size:11px; font-weight:500; letter-spacing:.2em; text-transform:uppercase;
  color:var(--bone-dim); display:block; height:15px; line-height:15px; overflow:hidden;
}
.nav-link span{ display:block; height:15px; line-height:15px; transition:transform .55s var(--ease-out), color .3s; }
.nav-link .alt{ position:absolute; inset:0; transform:translate3d(0,100%,0); color:var(--bone); letter-spacing:.32em; }
.nav-link:hover span{ transform:translate3d(0,-100%,0); }
.nav-link:hover .alt{ transform:none; }
.nav-link.on{ color:var(--bone); }
.nav-link.on::after{ content:''; position:absolute; left:0; bottom:0; width:100%; height:1px; background:var(--vermilion); }
.nav-burger{ margin-left:clamp(18px,2.6vw,42px); width:26px; height:16px; position:relative; flex:0 0 auto; }
.nav-burger i{ position:absolute; right:0; height:1.5px; background:var(--bone); transition:width .45s var(--ease-out), transform .45s var(--ease-out); }
.nav-burger i:nth-child(1){ top:4px; width:26px; }
.nav-burger i:nth-child(2){ top:11px; width:17px; }
.nav-burger:hover i:nth-child(2){ width:26px; }
.nav-burger:hover i:nth-child(1){ width:17px; }

/* ============================================================= hero */
.hero{ position:relative; min-height:100svh; padding:0 var(--pad); display:flex; flex-direction:column; }
.hero::before{ content:''; position:absolute; left:0; right:0; top:0; height:46%; pointer-events:none;
  background:linear-gradient(rgba(3,6,9,.72), rgba(3,6,9,.34) 46%, transparent); }
.hero-top{ padding-top:calc(var(--nav-h) + clamp(12px,2.6vh,34px)); max-width:min(560px,46vw); position:relative; z-index:2; }
.hero-top .eyebrow{ display:flex; align-items:center; gap:10px; margin-bottom:20px; }
.hero-top .eyebrow .dot{ width:5px; height:5px; border-radius:50%; background:var(--vermilion); box-shadow:0 0 10px var(--vermilion); }
.hero h1{ margin-bottom:18px; }
.hero-sub{ max-width:322px; text-shadow:0 1px 26px rgba(3,6,8,.95); }
.hero-spacer{ flex:1 1 auto; min-height:clamp(140px,26vh,300px); }
.hero-foot{ padding-bottom:clamp(22px,4.2vh,42px); position:relative; z-index:2; }
.hero-cue{ display:flex; align-items:center; justify-content:flex-end; gap:12px; margin-bottom:14px;
  font-size:9px; letter-spacing:.3em; text-transform:uppercase; color:var(--muted); }
.hero-cue .track{ width:54px; height:1px; background:var(--line); position:relative; overflow:hidden; }
.hero-cue .track i{ position:absolute; inset:0; background:var(--bone); transform-origin:left;
  animation:cue 2.8s var(--ease-io) infinite; }
.chapters{
  display:grid; grid-template-columns:repeat(4,1fr); gap:clamp(14px,2.4vw,40px);
  border-top:1px solid var(--line-soft); padding-top:18px;
}
.chip{ display:flex; gap:14px; align-items:flex-start; cursor:pointer; }
.chip .num{ line-height:1; flex:0 0 auto; transition:color .4s, transform .5s var(--ease-out); }
.chip .tx{ min-width:0; padding-top:3px; }
.chip b{ display:block; font-size:10px; font-weight:500; letter-spacing:.2em; text-transform:uppercase;
  color:var(--bone-dim); margin-bottom:6px; transition:color .4s;
  text-shadow:0 1px 16px rgba(3,6,8,.9); }
.chip p{ margin:0; font-size:11px; line-height:1.5; color:#7d8781; max-width:22ch;
  transition:color .4s; }
.chip:hover .num{ color:var(--ember); transform:translate3d(0,-2px,0); }
.chip:hover b{ color:var(--bone); }
.chip:hover p{ color:var(--bone-dim); }
.chip.on .num{ color:var(--ember); }
.chip.on b{ color:var(--bone); }
/* the floating window: a generated Sanmon still carried over the hero */
.peek{
  position:absolute; z-index:2; right:clamp(78px,11vw,190px); top:clamp(132px,25vh,238px);
  width:clamp(150px,16vw,262px); display:block;
  transition:transform .8s var(--ease-out);
}
.peek-fr{ display:block; aspect-ratio:16/10;
  background:linear-gradient(180deg, rgba(3,6,9,.04) 24%, rgba(3,6,9,.48) 100%),
    url('../../secret-pathways-assets/generated/kage-sanmon-preview.webp') center / cover no-repeat;
  outline:1px solid rgba(223,231,224,.16); outline-offset:-1px;
  box-shadow:0 34px 70px -30px rgba(0,0,0,.9); transition:outline-color .5s; }
.peek:hover{ transform:translate3d(0,-5px,0); }
.peek:hover .peek-fr{ outline-color:rgba(223,231,224,.42); }
.peek-play{ position:absolute; top:0; right:0; left:0; bottom:auto; aspect-ratio:16/10;
  display:grid; place-items:center; pointer-events:none; }
.peek-play svg{ width:clamp(30px,3.2vw,46px); height:auto; filter:drop-shadow(0 2px 12px rgba(0,0,0,.7));
  transition:transform .55s var(--ease-out); }
.peek:hover .peek-play svg{ transform:scale(1.14); }
.peek-cap{ display:flex; align-items:baseline; gap:9px; margin-top:9px; }
.peek-cap b{ font-size:11px; font-weight:400; letter-spacing:.24em; color:var(--bone-dim); }
.peek-cap i{ font-style:normal; font-size:9px; letter-spacing:.2em; text-transform:uppercase; color:var(--muted); }
@media (max-width:820px){ .peek{ display:none; } }

.hero-side{
  position:absolute; z-index:2; right:var(--pad); top:50%; transform:translateY(-50%);
  display:flex; flex-direction:column; align-items:center; gap:14px; pointer-events:none;
}
.hero-side .v{ writing-mode:vertical-rl; font-size:13px; letter-spacing:.62em; color:rgba(223,231,224,.5); }
@keyframes cue{ 0%{transform:scaleX(0)} 42%{transform:scaleX(1)} 100%{transform:scaleX(1) translateX(100%)} }

/* ============================================================= sections */
.sec{ position:relative; padding:clamp(88px,15vh,190px) var(--pad); }
.sec::before{
  content:''; position:absolute; inset:-22% -4%; z-index:-1; pointer-events:none;
  background:radial-gradient(110% 62% at 30% 50%, rgba(4,7,10,.88), rgba(4,7,10,.62) 42%, rgba(4,7,10,.18) 74%, rgba(4,7,10,0));
  /* A chapter's scrim is there to hold its own copy off the sanctuary, and it
     is inset -22% so its edges never land as a seam. That overshoot, plus the
     section's top padding, means it was washing most of a screen of scene
     above the chapter — the frame stayed masked long after the hero had let
     go of it. The mask takes the top of it back off: nothing at the very top,
     full strength by the time the chapter's own first line arrives. */
  -webkit-mask-image:linear-gradient(transparent, #000 44%);
          mask-image:linear-gradient(transparent, #000 44%);
}
#work::before{ background:radial-gradient(108% 64% at 50% 50%, rgba(4,7,10,.70), rgba(4,7,10,.44) 50%, rgba(4,7,10,0)); }
#contact::before{ background:radial-gradient(82% 58% at 50% 46%, rgba(4,7,10,.26), rgba(4,7,10,.66) 56%, rgba(4,7,10,.90) 82%, rgba(4,7,10,0)); }
.foot::before{
  content:''; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:linear-gradient(rgba(4,7,10,.55), rgba(4,7,10,.94) 40%, rgba(4,7,10,.98));
}
.sec-head{ display:flex; align-items:baseline; gap:16px; margin-bottom:clamp(30px,5vh,66px); }
.sec-head .k{ font-size:10px; font-weight:500; letter-spacing:.24em; text-transform:uppercase; color:var(--muted); }
.sec-head .k b{ color:var(--vermilion); font-weight:500; }
.rule{ flex:1 1 auto; height:1px; background:var(--line-soft); }

/* — chapter I: the gate */
.gate-grid{ display:grid; grid-template-columns:minmax(0,1.02fr) minmax(0,1fr); gap:clamp(28px,5vw,90px); align-items:start; }
.gate-grid h2{ max-width:11ch; }
.gate-copy{ padding-top:6px; }
.gate-copy .lead{ font-size:clamp(15px,1.16vw,19px); line-height:1.66; color:#c2cdc5; text-shadow:0 1px 20px rgba(3,6,8,.9); }
.gate-copy .lead + p{ margin-top:20px; }
.arrowlink{ display:inline-flex; align-items:center; gap:12px; margin-top:34px;
  font-size:11px; font-weight:500; letter-spacing:.2em; text-transform:uppercase; color:var(--bone); }
.arrowlink .ar{ width:34px; height:34px; border:1px solid var(--line); border-radius:50%;
  display:grid; place-items:center; transition:background .45s var(--ease), border-color .45s, transform .5s var(--ease-out); }
.arrowlink .ar svg{ width:13px; height:13px; transition:transform .5s var(--ease-out); }
.arrowlink:hover .ar{ background:var(--bone); border-color:var(--bone); }
.arrowlink:hover .ar svg{ transform:translate3d(2px,-2px,0); }
.arrowlink:hover .ar svg path{ stroke:#05070a; }
.gate-stats{ display:flex; gap:clamp(24px,4vw,62px); margin-top:clamp(46px,8vh,96px); border-top:1px solid var(--line-soft); padding-top:24px; }
.gate-stats div b{ display:block; font-size:clamp(22px,2.1vw,32px); font-weight:300; letter-spacing:-.02em; }
.gate-stats div span{ font-size:10px; letter-spacing:.2em; text-transform:uppercase; color:var(--muted); }

/* — chapter II: pathways cards */
.cards{ display:grid; grid-template-columns:repeat(3,1fr); gap:clamp(10px,1.4vw,22px); align-items:start; }
.card{ position:relative; cursor:pointer; }
.card:nth-child(1){ transform:translateY(0); }
.card:nth-child(2){ transform:translateY(clamp(26px,5vw,74px)); }
.card:nth-child(3){ transform:translateY(clamp(52px,10vw,148px)); }
/* the frame is a hole punched in the page — the scene is rendered straight
   into this rectangle with a scissored viewport, so each card is a live
   window onto a different corner of the sanctuary */
.card-fr{
  position:relative; aspect-ratio:4/5; background:transparent;
  outline:1px solid var(--line-soft); outline-offset:-1px;
  transition:outline-color .5s var(--ease);
}
.card:hover .card-fr{ outline-color:rgba(223,231,224,.30); }
.card:nth-child(1) .card-fr{
  background:
    linear-gradient(180deg,rgba(3,6,9,.04) 36%,rgba(3,6,9,.72) 100%),
    url('../../secret-pathways-assets/generated/kage-approach.webp') center / cover no-repeat;
}
.card:nth-child(2) .card-fr{
  background:
    linear-gradient(180deg,rgba(3,6,9,.06) 36%,rgba(3,6,9,.74) 100%),
    url('../../secret-pathways-assets/generated/kage-lantern-court.webp') center / cover no-repeat;
}
.card:nth-child(3) .card-fr{
  background:
    linear-gradient(180deg,rgba(3,6,9,.05) 36%,rgba(3,6,9,.74) 100%),
    url('../../secret-pathways-assets/generated/kage-moonwater.webp') center / cover no-repeat;
}
.card-fr::after{ content:''; position:absolute; inset:0;
  background:linear-gradient(transparent 46%, rgba(4,6,9,.80)); pointer-events:none; }
/* The fabric overdraws its card by CL_BLEED on every side so the billow and
   the contact shadow have somewhere to go, so the frame cannot clip it. The
   card's outline is not here at all: it is drawn in the cloth shader, where it
   can follow the folds instead of tracing the flat box behind them. */
.cloth-out{ position:absolute; pointer-events:none; z-index:1; }
.on-cloth{ background:none !important; outline:0 !important; overflow:visible; }
.on-cloth::after{ display:none; }

/* ------------------------------------------------- the lights in the stills
   The three plates each have one source in them — two blood moons and a lit
   stone lantern — and they are the only warm thing in an otherwise cold set of
   images. A glow laid over each one, screened so it adds light rather than
   painting over it, is enough to make a flat still look like it is burning.

   Two tracks per light, at durations that do not divide into each other: the
   wrapper swells, the gradient inside it pulses. One track on its own reads as
   a loop within a couple of seconds; two beating against each other do not
   come back around inside the time anyone looks at a card.

   The moon and the lantern are not the same event. A flame gutters — short,
   irregular, deep — so the lantern's track is written unevenly by hand. A moon
   only breathes through moving air, so the moons get a slow, shallow swell and
   nothing more. Giving them both a flicker is what makes this kind of thing
   look like a novelty; the difference is the whole effect. */
.card-fr{ isolation:isolate; }        /* keep the screen blend inside the card */
.glow{
  position:absolute; z-index:1; pointer-events:none;
  left:var(--gx); top:var(--gy); width:calc(var(--gr) * 2); aspect-ratio:1;
  translate:-50% -50%;                /* leaves transform free for the swell */
  mix-blend-mode:screen;
  animation:glow-swell var(--gt2) var(--ease-io) infinite alternate;
}
.glow::before{
  content:''; position:absolute; inset:0; border-radius:50%;
  background:radial-gradient(closest-side, var(--gc1), var(--gc2) 40%, transparent 72%);
  animation:glow-pulse var(--gt) var(--ease-io) infinite;
}
@keyframes glow-swell{ from{ transform:scale(.93); } to{ transform:scale(1.07); } }
@keyframes glow-pulse{ from{ opacity:.78; } 50%{ opacity:1; } to{ opacity:.78; } }
/* a flame does not breathe, it gutters */
@keyframes glow-flame{
  0%{ opacity:.74 }   6%{ opacity:.97 }  12%{ opacity:.63 }  19%{ opacity:.90 }
  27%{ opacity:.55 }  34%{ opacity:.94 } 42%{ opacity:.71 }  51%{ opacity:1 }
  58%{ opacity:.60 }  66%{ opacity:.88 } 74%{ opacity:.67 }  83%{ opacity:.96 }
  91%{ opacity:.72 } 100%{ opacity:.74 }
}
.glow--flame::before{ animation-name:glow-flame; }
.glow--flame{ animation-duration:var(--gt2); }
@media (prefers-reduced-motion:reduce){
  .glow, .glow::before{ animation:none; }
}
.no-webgl .card-fr{ background:linear-gradient(150deg,#101a1d,#0a0d10 62%,#1a0c0b); }
/* If WebGL will not start, the page stays a page: the scene simply becomes a
   still, and the wordmark moves from the 3-D layer into the document. */
.word-fb{ display:none; }
.no-webgl #gl, .no-webgl .peek-play{ display:none; }
/* fixed, or the gradient is measured against a 6000-pixel body box and the
   moon ends up somewhere around the curriculum table */
.no-webgl body{ background:
  radial-gradient(11vw 11vw at 73% 17%, rgba(232,52,28,.95), rgba(158,20,16,.62) 44%, rgba(96,12,12,.20) 64%, transparent 72%),
  radial-gradient(38vw 32vw at 50% 46%, rgba(228,104,24,.40), rgba(122,42,10,.18) 54%, transparent 74%),
  radial-gradient(120% 80% at 50% 0%, rgba(120,150,158,.16), transparent 60%), #05070a;
  background-attachment:fixed; }
.no-webgl .peek-fr{ background:linear-gradient(160deg,#162326,#0b1013 55%,#241010); }
.no-webgl .word-fb{
  display:block; position:absolute; left:0; right:0; bottom:16%; z-index:1;
  font-family:'Wordmark','Onest',sans-serif; font-weight:600; font-size:21.4vw; line-height:.78;
  letter-spacing:.052em; text-align:center; pointer-events:none;
  background:linear-gradient(#e2ece5, #97a89c); -webkit-background-clip:text; background-clip:text;
  color:transparent;
}
/* The live hero has no foot scrim, but the fallback still needs one: there it
   stands on a bright CSS sky rather than a night scene, and the chips and the
   wordmark have nothing else holding them off it. So this carries the whole
   declaration now rather than re-colouring one it used to inherit. */
.no-webgl .hero::after{ content:''; position:absolute; left:0; right:0; bottom:0; height:34%;
  pointer-events:none; background:linear-gradient(transparent, rgba(3,5,8,.72) 52%, rgba(3,5,8,.96)); }
.no-webgl .sec::before, .no-webgl #work::before, .no-webgl #contact::before{ background:none; }
.card-lab{ position:absolute; left:16px; right:16px; bottom:14px; z-index:2;
  display:flex; align-items:flex-end; justify-content:space-between; gap:10px; }
.card-lab b{ font-size:clamp(13px,1.15vw,17px); font-weight:400; letter-spacing:.02em; text-transform:uppercase; }
.card-lab .jp{ font-size:11px; letter-spacing:.3em; color:rgba(223,231,224,.62); }
.card-ar{ position:absolute; top:14px; right:14px; z-index:2; width:26px; height:26px;
  opacity:0; transform:translate3d(-4px,4px,0); transition:.5s var(--ease-out); }
.card:hover .card-ar{ opacity:1; transform:none; }
.card-meta{ display:flex; justify-content:space-between; margin-top:12px;
  font-size:10px; letter-spacing:.16em; text-transform:uppercase; color:var(--muted); }

/* — chapter III: curriculum */
.cur-head{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,.72fr); gap:clamp(28px,5vw,90px); align-items:end; margin-bottom:clamp(34px,6vh,72px); }
.cur-head h2{ max-width:13ch; }
.cur{ border-top:1px solid var(--line-soft); }
.les{
  position:relative; display:grid; align-items:center;
  grid-template-columns:64px minmax(0,1.05fr) minmax(0,1.25fr) 86px;
  gap:clamp(14px,2.4vw,40px);
  padding:clamp(20px,2.4vw,30px) 0; border-bottom:1px solid var(--line-soft);
  cursor:pointer; transition:padding .5s var(--ease-out);
}
.les::before{ content:''; position:absolute; left:calc(var(--pad) * -1); right:0; top:0; bottom:0;
  background:linear-gradient(90deg, rgba(224,35,28,.09), transparent 46%);
  opacity:0; transition:opacity .55s var(--ease); pointer-events:none; }
.les:hover::before{ opacity:1; }
.les:hover{ padding-left:clamp(8px,1.2vw,18px); }
.les .k{ font-size:11px; letter-spacing:.16em; color:var(--muted); font-variant-numeric:tabular-nums; transition:color .4s; }
.les:hover .k{ color:var(--vermilion); }
.les h3{ font-size:clamp(16px,1.5vw,23px); font-weight:400; letter-spacing:-.005em; }
.les h3 em{ font-style:normal; font-family:'NotoJP',sans-serif; font-size:.72em; color:var(--muted); margin-left:12px; letter-spacing:.24em; }
.les p{ margin:0; font-size:13px; line-height:1.6; color:#909b95; text-shadow:0 1px 16px rgba(3,6,8,.92); }
.les .t{ text-align:right; font-size:11px; letter-spacing:.14em; color:#8b958f; font-variant-numeric:tabular-nums; text-shadow:0 1px 16px rgba(3,6,8,.92); }
.les .bar{ position:absolute; left:0; bottom:-1px; height:1px; width:100%; background:var(--vermilion);
  transform:scaleX(0); transform-origin:left; transition:transform .7s var(--ease-out); }
.les:hover .bar{ transform:scaleX(1); }

/* — chapter IV: eternity */
.fin{ min-height:100svh; display:flex; flex-direction:column; justify-content:center; align-items:center; text-align:center; }
.fin .eyebrow{ margin-bottom:26px; }
.fin h2{ font-size:clamp(38px,7.4vw,124px); line-height:.94; letter-spacing:-.03em; text-transform:uppercase; }
.fin p{ max-width:44ch; margin:26px auto 0; }
.cta{
  position:relative; display:inline-flex; align-items:center; gap:14px; margin-top:44px;
  padding:17px 30px; border:1px solid var(--line); border-radius:100px; overflow:hidden;
  font-size:11px; font-weight:500; letter-spacing:.22em; text-transform:uppercase;
  transition:color .45s var(--ease), border-color .45s;
}
.cta i{ position:absolute; inset:0; background:var(--bone); transform:translate3d(0,101%,0);
  transition:transform .62s var(--ease-out); z-index:-1; }
.cta span,.cta svg{ position:relative; z-index:1; }
.cta:hover{ color:#05070a; border-color:var(--bone); }
.cta:hover i{ transform:none; }
.cta:hover svg path{ stroke:#05070a; }

/* — footer */
.foot{ position:relative; padding:clamp(50px,8vh,96px) var(--pad) clamp(26px,4vh,40px);
  border-top:1px solid var(--line-soft); }
.foot-grid,.foot-base{ position:relative; }
.foot-grid{ display:grid; grid-template-columns:minmax(0,1.4fr) repeat(3,minmax(0,.6fr)); gap:clamp(22px,4vw,60px); }
.foot h4{ margin:0 0 16px; font-size:10px; font-weight:500; letter-spacing:.22em; text-transform:uppercase; color:var(--muted); }
.foot ul{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:9px; }
.foot li a{ font-size:13px; color:#8f9a93; transition:color .35s; }
.foot li a:hover{ color:var(--bone); }
.foot-brand p{ margin:16px 0 0; max-width:34ch; font-size:13px; color:#79847e; }
.foot-base{ display:flex; justify-content:space-between; align-items:center; gap:20px; flex-wrap:wrap;
  margin-top:clamp(38px,6vh,74px); padding-top:20px; border-top:1px solid var(--line-soft);
  font-size:10px; letter-spacing:.16em; text-transform:uppercase; color:var(--muted); }

/* ============================================================= progress rail */
.rail{ position:fixed; right:calc(var(--pad) - 4px); top:50%; transform:translateY(-50%); z-index:45;
  display:flex; flex-direction:column; gap:12px; align-items:center; }
.rail button{ width:22px; height:10px; display:grid; place-items:center; }
.rail i{ display:block; width:14px; height:1px; background:rgba(223,231,224,.26); transition:.5s var(--ease-out); }
.rail button.on i{ width:22px; background:var(--bone); }
.rail button:hover i{ width:22px; background:var(--bone-dim); }

/* ============================================================= cursor */
.cur-dot{ position:fixed; z-index:80; top:0; left:0; width:26px; height:26px; margin:-13px 0 0 -13px;
  border:1px solid rgba(223,231,224,.42); border-radius:50%; pointer-events:none;
  transition:width .35s var(--ease-out), height .35s var(--ease-out), margin .35s var(--ease-out),
             background .35s, border-color .35s, opacity .3s; opacity:0; }
.cur-dot.act{ width:52px; height:52px; margin:-26px 0 0 -26px; background:rgba(223,231,224,.07); border-color:rgba(223,231,224,.6); }
@media (hover:hover) and (pointer:fine){ .cur-dot{ opacity:1 } }

/* ============================================================= responsive */
@media (max-width:1080px){
  .hero-top{ max-width:none; }
  .gate-grid{ grid-template-columns:1fr; gap:26px; }
  .cur-head{ grid-template-columns:1fr; gap:18px; }
  .les{ grid-template-columns:44px minmax(0,1fr) 74px; }
  .les p{ display:none; }
  .foot-grid{ grid-template-columns:1fr 1fr; }
}
@media (max-width:820px){
  .nav-links{
    display:flex; position:fixed; top:0; right:0; bottom:0; width:min(84vw,360px);
    padding:calc(var(--nav-h) + 28px) var(--pad) 34px; flex-direction:column; align-items:flex-start; gap:0;
    background:rgba(3,6,9,.98); border-left:1px solid var(--line-soft);
    transform:translate3d(100%,0,0); opacity:0; visibility:hidden; pointer-events:none;
    transition:transform .65s var(--ease-out), opacity .4s, visibility 0s linear .65s;
  }
  .nav.menu-open .nav-links{
    transform:none; opacity:1; visibility:visible; pointer-events:auto; transition-delay:0s;
  }
  .nav-links .nav-link{
    width:100%; height:auto; padding:17px 0; overflow:visible; border-bottom:1px solid var(--line-soft);
    font-size:17px; line-height:1.2;
  }
  .nav-links .nav-link span{ height:auto; line-height:1.2; transform:none !important; }
  .nav-links .nav-link .alt{ position:static; margin-top:6px; font-size:10px; color:var(--muted); }
  /* The links panel leaves the flow to become the slide-in sheet, taking its
     margin-left:auto with it, so without this the burger sits tucked against
     the wordmark instead of out at the edge where a thumb reaches. */
  /* A transform *or* a backdrop-filter makes an element the containing block
     for its position:fixed descendants. This panel is a child of the bar, so
     once the bar went sticky and started hiding on scroll the open panel was
     measured against the bar instead of the viewport: 146px tall, dragged off
     the top, with the page showing through beside it. Neither may apply while
     the sheet is open — it covers the frame, so there is nothing left to blur. */
  /* A hide transform still promotes the bar, so drop it the instant the sheet
     opens. Without transition:none it eases out over .55s and the sheet spends
     that whole time measured against the bar. */
  .nav.menu-open{ transform:none; transition:none; }
  .nav-burger{ margin-left:auto; }
  .nav-burger.active i:nth-child(1){ top:7px; width:26px; transform:rotate(45deg); }
  .nav-burger.active i:nth-child(2){ top:7px; width:26px; transform:rotate(-45deg); }
  html.nav-open,html.nav-open body{ overflow:hidden; }
  .rail{ display:none; }
  .hero-side{ display:none; }
  .chapters{ grid-template-columns:repeat(2,1fr); gap:18px 14px; }
  .chip p{ font-size:10px; }
  .cards{ grid-template-columns:1fr; gap:14px; }
  .card:nth-child(2),.card:nth-child(3){ transform:none; }
  .gate-stats{ flex-wrap:wrap; gap:20px 34px; }
  .foot-grid{ grid-template-columns:1fr; }
  .hero-cue{ display:none; }
}
/* ================================================== section layouts (B set)
   The six sections ship their B compositions — hero split, story spread,
   gardens mosaic, chapter atlas, gallery closing, manifesto footer. They are
   keyed off stable body data attributes so the rules above keep reading as
   the plain grammar of the page and every B override stays in one block.   */

/* — hero B · split: an editorial reading column holds the left, a compact
     numbered index sits under it, and the live scene window becomes a low,
     right-hand counterweight. The scene itself remains untouched.

     The column carried a 90° scrim over the left three-quarters of the frame.
     It has gone: the sanctuary is already near-black behind the reading, and
     measured against it the copy loses almost nothing without it — the
     headline 15.98:1 to 15.47:1, the standfirst 7.94:1 to 7.75:1, the index
     16.11:1 to 16.08:1, all far past what either needs. It was darkening the
     approach, the gate and the lower steps to buy half a point of contrast
     nobody was short of. */
body[data-layout-hero="b"] .hero-top{ margin-left:0; max-width:min(590px,46vw); }
body[data-layout-hero="b"] .hero-foot{ width:min(480px,40vw); margin-left:0; }
body[data-layout-hero="b"] .hero-cue{ justify-content:flex-start; }
body[data-layout-hero="b"] .chapters{ grid-template-columns:repeat(4,minmax(0,1fr)); gap:12px; }
body[data-layout-hero="b"] .chip{ position:relative; flex-direction:column; gap:0; }
body[data-layout-hero="b"] .chip .num{ font-size:clamp(29px,3.1vw,48px); }
body[data-layout-hero="b"] .chip .tx{
  position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0);
  clip-path:inset(50%); white-space:nowrap;
}
/* the live window drops into the open right corner, away from the reading
   column and the oversized 3-D wordmark */
body[data-layout-hero="b"] .peek{
  left:auto; right:var(--pad); top:auto; bottom:clamp(38px,7vh,96px);
}
body[data-layout-hero="b"] .peek-cap b.jp{ font-size:clamp(20px,2.2vw,34px); letter-spacing:.18em; }
/* The Japanese title reads down the right edge, hung under the navigation —
   the one mark on that side of the frame now that the romanization has gone. */
body[data-layout-hero="b"] .hero-side{
  left:auto; right:var(--pad); top:calc(var(--nav-h) + clamp(14px,3vh,42px));
  bottom:auto; transform:none; display:block;
}
body[data-layout-hero="b"] .hero-side .v{
  position:static; transform:none;
  font-size:clamp(30px,3.2vw,54px); letter-spacing:.12em; color:rgba(223,231,224,.62);
}

/* — story B · spread: the title crosses two columns, the reading column is
     held to the right, and the figures become a ruled band. */
body[data-layout-story="b"] .gate-grid{
  grid-template-columns:minmax(120px,.38fr) minmax(0,1.08fr) minmax(280px,.88fr);
  gap:clamp(20px,3vw,54px);
}
body[data-layout-story="b"] .gate-grid h2{ grid-column:1 / 3; max-width:13ch; }
body[data-layout-story="b"] .gate-copy{ grid-column:3; }
body[data-layout-story="b"] .gate-stats{ display:grid; grid-template-columns:repeat(4,1fr); gap:0; }
body[data-layout-story="b"] .gate-stats div{ min-height:108px; padding:18px; border-left:1px solid var(--line-soft); }
body[data-layout-story="b"] .gate-stats div:last-child{ border-right:1px solid var(--line-soft); }

/* — gardens B · mosaic: one immersive live window beside two stacked ones.
     The cards stretch to their rows and the frames flex, so the two small
     viewports meet the tall one exactly instead of drifting apart. */
body[data-layout-gallery="b"] .cards{
  grid-template-columns:minmax(0,1.55fr) minmax(260px,.75fr);
  grid-template-rows:repeat(2,minmax(0,1fr));
  gap:14px; align-items:stretch;
}
body[data-layout-gallery="b"] .card{ transform:none; display:flex; flex-direction:column; min-height:0; }
body[data-layout-gallery="b"] .card-fr{ aspect-ratio:auto; flex:1 1 auto; min-height:0; }
body[data-layout-gallery="b"] .card:first-child{ grid-row:1 / 3; }
body[data-layout-gallery="b"] .card:first-child .card-fr{ flex:0 0 auto; height:min(72vh,760px); }
body[data-layout-gallery="b"] .card:not(:first-child) .card-fr{ min-height:200px; }

/* — chapters B · atlas: a two-then-three plate grid instead of a syllabus.
     Number and title sit at the top of each plate, the running time drops to
     the foot of it. */
body[data-layout-curriculum="b"] .cur-head{ grid-template-columns:minmax(0,.72fr) minmax(0,1.2fr); align-items:start; }
body[data-layout-curriculum="b"] .cur{
  display:grid; grid-template-columns:repeat(6,1fr); gap:1px;
  background:var(--line-soft); border:1px solid var(--line-soft);
}
body[data-layout-curriculum="b"] .les{
  display:flex; flex-direction:column; align-items:flex-start; min-height:250px;
  padding:24px; gap:14px; border:0; background:rgba(5,7,10,.84); overflow:hidden;
}
body[data-layout-curriculum="b"] .les:nth-child(-n+2){ grid-column:span 3; }
body[data-layout-curriculum="b"] .les:nth-child(n+3){ grid-column:span 2; }
body[data-layout-curriculum="b"] .les::before{ left:0; background:linear-gradient(145deg,rgba(224,35,28,.13),transparent 58%); }
body[data-layout-curriculum="b"] .les:hover{ padding-left:32px; }
body[data-layout-curriculum="b"] .les h3{ font-size:clamp(20px,2vw,30px); }
body[data-layout-curriculum="b"] .les p{ display:block; max-width:34ch; }
body[data-layout-curriculum="b"] .les .t{ text-align:left; margin-top:auto; }

/* — closing B · gallery: the title hangs vertically on the right while the
     chapter mark, the last line and the call to action run down the left. */
body[data-layout-closing="b"] .fin{
  display:grid; grid-template-columns:minmax(260px,.7fr) minmax(0,1.3fr); grid-template-rows:auto auto auto;
  align-content:center; align-items:end; text-align:left;
  column-gap:clamp(40px,7vw,120px); row-gap:clamp(16px,2.6vh,30px);
}
body[data-layout-closing="b"] .fin .eyebrow{ grid-column:1; grid-row:1; margin:0; }
body[data-layout-closing="b"] .fin h2{
  grid-column:2; grid-row:1 / 4; align-self:center; justify-self:end;
  font-size:clamp(52px,6vw,82px); writing-mode:vertical-rl;
}
body[data-layout-closing="b"] .fin p{ grid-column:1; grid-row:2; margin:0; }
body[data-layout-closing="b"] .fin .cta{ grid-column:1; grid-row:3; justify-self:start; margin-top:4px; }

/* — footer B · manifesto: the statement leads, the navigation becomes a
     compact ruled index beneath it. */
body[data-layout-footer="b"] .foot-grid{ grid-template-columns:repeat(3,1fr); }
body[data-layout-footer="b"] .foot-brand{
  grid-column:1 / -1; display:grid; grid-template-columns:70px minmax(0,1fr); align-items:center;
  padding-bottom:34px; margin-bottom:8px; border-bottom:1px solid var(--line-soft);
}
body[data-layout-footer="b"] .foot-brand svg{ width:54px; height:54px; }
body[data-layout-footer="b"] .foot-brand p{
  margin:0; max-width:48ch; font-size:clamp(18px,2vw,30px); line-height:1.35; color:var(--bone-dim);
}
body[data-layout-footer="b"] .foot-grid > div:nth-child(n+3){
  padding-left:clamp(18px,2.2vw,34px); border-left:1px solid var(--line-soft);
}
body[data-layout-footer="b"] .foot-base{ display:grid; grid-template-columns:1fr auto 1fr; }
body[data-layout-footer="b"] .foot-base span:last-child{ text-align:right; }

/* ================================================= foreground layers (KAGE)
   The transparent PNG library in secret-pathways-assets/foreground/png is
   introduced as a near plane. Each section carries one .fg box holding a few
   cut-outs that stand between the live sanctuary and the reading: the scene
   itself is untouched, this is only the garden that grows in front of it.

   The cut-outs are the nearest plane on the page, so they sit in front of the
   reading rather than behind it. Inside .page — itself z-index:10, above the
   #gl canvas at 0:
     -1   .sec::before / .foot::before   the section scrims
      2   headings, copy, links, cards, stats, CTA
      3   .fg                            the cut-outs: aria-hidden, inert
   .page caps everything it holds at tier 10, which is under the fixed
   furniture (rail 45, nav 50), so the chapter's live near plane is moved out
   to #fg-sky at 52 — over the layout and the navigation both, and still under
   the passes that treat the frame as one image: vignette 55, grain 60,
   cursor 80.

   A stage is only ever shown while its own chapter holds the viewport, and
   only in the fixed bottom-anchored form. Parked back in its section it is
   inert and invisible: a near plane that scrolls with the page reads as
   wallpaper printed on the document rather than as something standing between
   the camera and the scene, so there is no second, section-owned appearance.
   Every piece is therefore placed from the bottom edge of that fixed plane —
   left/right and bottom, never top.

   The entrance is driven by the chapter, not by the scroll observer: each
   [data-fg-in] piece rises from the edge it is anchored to when its stage goes
   live, one every 90ms in DOM order, and the reduced-motion block at the foot
   of this sheet flattens it. The wrapper owns the entrance and animates
   opacity and transform only; the artwork itself remains at full opacity, with
   the reading protected by the layer order rather than a translucent
   foreground treatment. */
.fg{
  position:absolute; inset:0; z-index:3;
  overflow:visible; pointer-events:none;
}
/* Nothing inside a section may widen the document. The foreground cut-outs and
   the cloth canvases are placed to hang past the frame edges on purpose, and as
   ordinary in-flow descendants they dragged the page box out with them — 194px
   past a 1440 frame. Clip the horizontal axis at the section, which is exactly
   viewport-wide, so each overhang is cut precisely where it leaves the screen.
   `clip` pairs with `visible` without coercing it, so no scroll container is
   created and every bit of vertical bleed survives. */
.sec, .foot{ overflow-x:clip; overflow-y:visible; }
/* the host for whichever chapter currently owns the near plane — no box of
   its own, since every stage it holds is position:fixed to the viewport */
#fg-sky{
  position:fixed; left:0; top:0; width:0; height:0;
  z-index:52; pointer-events:none;
}
.sec > *:not(.fg), .foot > *:not(.fg){ position:relative; z-index:2; }
.fg-el{ position:absolute; display:block; opacity:0; }
.fg-el > img{
  width:100%; height:auto;   /* the width/height attrs hold the box before the lazy image lands */
  opacity:1;
  filter:saturate(.88) brightness(.86);
}
.fg-el--flip > img{ transform:scaleX(-1); }
/* each piece waits off the edge it is anchored to until its chapter is called */
[data-fg-in="up"]   { transform:translate3d(0,13%,0); }
[data-fg-in="left"] { transform:translate3d(-11%,6%,0); }
[data-fg-in="right"]{ transform:translate3d(11%,6%,0); }
/* one slow breath, on the two lightest layers only */
@keyframes fg-sway{
  from{ transform:rotate(-.45deg) translate3d(0,2px,0); }
  to  { transform:rotate(.45deg)  translate3d(0,-6px,0); }
}
.fg-el--sway > img{ animation:fg-sway 21s var(--ease-io) infinite alternate; transform-origin:0% 45%; }

/* The active chapter owns a bottom-anchored near plane. Its former stage is
   retained only long enough to dissolve into the next chapter's scene. */
.fg.fg-active,.fg.fg-retiring{
  position:fixed; left:0; right:0; top:auto; bottom:0; height:min(56svh,680px);
  z-index:1; overflow:visible; pointer-events:none;
}
.fg.fg-active .fg-el{
  opacity:1; transform:none;
  transition:opacity 1.2s var(--ease-out), transform 1.5s var(--ease-out);
  transition-delay:var(--fg-delay,0ms);
}
.fg .fg-el:nth-child(2){ --fg-delay:90ms; }
.fg .fg-el:nth-child(3){ --fg-delay:180ms; }
.fg .fg-el:nth-child(4){ --fg-delay:270ms; }
.fg.fg-retiring .fg-el{
  opacity:0; transform:translate3d(0,8vh,0) scale(.98); filter:blur(18px);
  transition:opacity .68s var(--ease-out),transform .78s var(--ease-out),filter .78s var(--ease-out);
}

/* Placement is keyed off [data-fg] rather than the section id, because the
   stage of the live chapter is re-parented into #fg-sky and stops being a
   descendant of its own section for as long as it holds the near plane.

   Every piece is anchored from the bottom of that plane, which is the bottom
   of the viewport. The cut-outs in png/ are trimmed flush to their own lowest
   opaque row, so a negative bottom here is a real amount of artwork buried off
   the foot of the frame, not slack in the file — the ground-sitting pieces
   carry enough of it that their base line never lifts off the edge. */

/* — I · the gate: the wall runs along the lower-left frame, a pine holds the
     far edge, and one bank of grass closes the foot of the chapter */
/* Wall against the left edge, pine against the right: the chapter is framed
   by the two of them with the court open between.

   left:0, not a negative offset — the plate is trimmed to its own artwork, so
   pulling it off-frame cuts the gate itself rather than trimming empty margin.
   Its left edge sits on the viewport's. */
[data-fg="gate"] .fg-wall  { left:0; bottom:-30px; width:clamp(430px,47vw,780px); }
[data-fg="gate"] .fg-pine  { right:-4%; bottom:-46px; width:clamp(190px,21vw,370px); }
[data-fg="gate"] .fg-grass { left:3%;   bottom:-150px; width:clamp(420px,60vw,1050px); }

/* — II · still gardens: sakura and maple sweep in from the two lower corners
     and carry their whole length, a lit lantern and a low bush hold the edges */
[data-fg="pathways"] .fg-sakura { left:-6%;  bottom:-86px;  width:clamp(430px,50vw,880px); }
[data-fg="pathways"] .fg-leaves { right:-6%; bottom:-62px;  width:clamp(330px,38vw,670px); }
[data-fg="pathways"] .fg-lantern{ left:-1%;  bottom:-96px;  width:clamp(120px,13vw,215px); }
[data-fg="pathways"] .fg-bush   { right:-4%; bottom:-38px;  width:clamp(250px,30vw,530px); }
/* the lantern is the one lit object in the library — it keeps its ember */
[data-fg="pathways"] .fg-lantern > img{ filter:saturate(.96) brightness(1); }
[data-fg="pathways"] .fg-leaves > img{ transform-origin:100% 40%; }

/* — III · sacred craft: basalt and a low wall fragment bracket the atlas and
     a stand of grass ties them together, all three below the plate grid */
[data-fg="lessons"] .fg-wall   { right:-8%; bottom:-78px; width:clamp(390px,50vw,870px); }
[data-fg="lessons"] .fg-stones { left:-4%;  bottom:-48px; width:clamp(250px,30vw,530px); }
[data-fg="lessons"] .fg-grass  { left:24%;  bottom:-84px; width:clamp(280px,33vw,580px); }

/* — IV · afterlight: a far hill closes the horizon, the shrine ruins stand at
     the left of it, grass banks the right, one branch hangs into the corner */
[data-fg="eternity"] .fg-hill   { left:-8%; width:min(150vh,116%); bottom:calc(-1 * min(20vh,15.5vw)); }
[data-fg="eternity"] .fg-ruins  { left:-5%;  bottom:-32px; width:clamp(240px,28vw,500px); }
[data-fg="eternity"] .fg-grass  { right:-7%; bottom:-60px; width:clamp(300px,37vw,670px); }
[data-fg="eternity"] .fg-sakura { left:-15%; bottom:-70px; width:clamp(280px,33vw,580px); }

/* — colophon: one restrained planting along the lower edge, nothing above it */
[data-fg="foot"] .fg-bush   { left:-6%;  bottom:-110px; width:clamp(230px,28vw,480px); }
[data-fg="foot"] .fg-grass  { right:-5%; bottom:-98px;  width:clamp(255px,30vw,530px); }
[data-fg="foot"] .fg-stones { left:36%;  bottom:-104px; width:clamp(190px,22vw,370px); }

@media (max-width:1080px){
  /* the columns have collapsed and the copy has taken the width back, so the
     framing layers step down rather than crowd it */
  [data-fg="gate"] .fg-wall      { width:clamp(390px,42vw,600px); }
  [data-fg="pathways"] .fg-sakura{ width:clamp(400px,46vw,660px); }
  [data-fg="pathways"] .fg-leaves{ width:clamp(310px,35vw,500px); }
  [data-fg="lessons"] .fg-wall   { width:clamp(360px,45vw,640px); }
  [data-fg="eternity"] .fg-sakura{ width:clamp(260px,30vw,430px); }
}
@media (max-width:820px){
  /* one or two anchors per section: the stacked cards, the atlas plates and
     the call to action own the whole width here, so every duplicated piece
     of ornament goes and what stays is smaller */
  [data-fg="gate"] .fg-pine, [data-fg="pathways"] .fg-sakura,
  [data-fg="pathways"] .fg-leaves, [data-fg="lessons"] .fg-wall,
  [data-fg="eternity"] .fg-sakura, [data-fg="foot"] .fg-stones{ display:none; }
  [data-fg="gate"] .fg-wall     { left:-14%; bottom:-22px; width:min(82vw,440px); }
  [data-fg="gate"] .fg-grass    { left:auto; right:-10%; bottom:-76px; width:min(94vw,530px); }
  [data-fg="pathways"] .fg-lantern{ left:-4%;   bottom:-58px; width:clamp(80px,20vw,128px); }
  [data-fg="pathways"] .fg-bush   { right:-10%; bottom:-38px; width:min(72vw,400px); }
  [data-fg="lessons"] .fg-stones  { left:-8%; bottom:-34px; width:min(66vw,360px); }
  [data-fg="lessons"] .fg-grass   { left:auto; right:-8%; bottom:-44px; width:min(70vw,380px); }
  [data-fg="eternity"] .fg-ruins  { left:-8%;   bottom:-25px; width:min(54vw,300px); }
  [data-fg="eternity"] .fg-grass  { right:-12%; bottom:-34px; width:min(80vw,440px); }
  [data-fg="foot"] .fg-bush  { left:-12%;  bottom:-26px; width:min(68vw,340px); }
  [data-fg="foot"] .fg-grass { right:-12%; bottom:-30px; width:min(74vw,380px); }
}
@media (prefers-reduced-motion:reduce){
  .fg-el--sway > img{ animation:none; }
  .fg.fg-retiring .fg-el{ transition:none !important; filter:none !important; }
}

@media (max-width:1080px){
  body[data-layout-hero="b"] .chapters{ gap:16px 20px; }
  body[data-layout-story="b"] .gate-grid{ grid-template-columns:1fr; }
  body[data-layout-story="b"] .gate-grid h2,
  body[data-layout-story="b"] .gate-copy{ grid-column:auto; }
  body[data-layout-story="b"] .gate-grid h2{ max-width:16ch; }
  body[data-layout-curriculum="b"] .les:nth-child(n){ grid-column:span 3; }
  body[data-layout-curriculum="b"] .les:last-child{ grid-column:span 6; }
}
@media (max-width:820px){
  /* the split collapses and the copy takes the page back */
  body[data-layout-hero="b"] .hero-top{ margin-left:0; max-width:none; }
  body[data-layout-hero="b"] .hero-foot{ width:100%; }
  /* The four-column strip is set on a selector specific enough to survive the
     plain .chapters override below 820, so it has to be unset here by name or
     the chips stay four across on a phone and wrap a word to a line. */
  body[data-layout-hero="b"] .chapters{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:18px 14px; }
  body[data-layout-hero="b"] .chip{ flex-direction:row; gap:14px; }
  /* Same shape of bug: the layout selector outranks the plain single-column
     rule, so the heading kept a 37% column while its words are set at 30px —
     "CHAPTERS." alone is wider than that, and it spilled over the paragraph. */
  body[data-layout-curriculum="b"] .cur-head{ grid-template-columns:1fr; gap:18px; align-items:start; }
  body[data-layout-hero="b"] .chip .num{ font-size:clamp(26px,8vw,36px); }
  body[data-layout-hero="b"] .chip .tx{
    position:static; width:auto; height:auto; overflow:visible; clip:auto;
    clip-path:none; white-space:normal;
  }

  body[data-layout-story="b"] .gate-stats{ grid-template-columns:repeat(2,1fr); border-right:1px solid var(--line-soft); }
  body[data-layout-story="b"] .gate-stats div{ min-height:86px; padding:14px; }
  body[data-layout-story="b"] .gate-stats div:nth-child(-n+2){ border-bottom:1px solid var(--line-soft); }
  body[data-layout-story="b"] .gate-stats div:last-child{ border-right:0; }

  /* the mosaic unstacks, but the rhythm survives: the lead window stays the
     tall one and the two field notes stay letterbox */
  body[data-layout-gallery="b"] .cards{ grid-template-columns:1fr; grid-template-rows:auto; }
  body[data-layout-gallery="b"] .card:first-child{ grid-row:auto; }
  body[data-layout-gallery="b"] .card-fr{ flex:0 0 auto; height:auto; }
  body[data-layout-gallery="b"] .card:first-child .card-fr{ height:auto; aspect-ratio:4 / 5; }
  body[data-layout-gallery="b"] .card:not(:first-child) .card-fr{ aspect-ratio:16 / 10; min-height:0; }

  body[data-layout-curriculum="b"] .cur{ grid-template-columns:1fr; }
  body[data-layout-curriculum="b"] .les:nth-child(n){ grid-column:auto; min-height:0; padding:20px; }
  body[data-layout-curriculum="b"] .les:hover{ padding-left:20px; }

  body[data-layout-closing="b"] .fin{ display:flex; align-items:center; text-align:center; gap:0; }
  body[data-layout-closing="b"] .fin .eyebrow{ margin:0 0 26px; }
  body[data-layout-closing="b"] .fin h2{ writing-mode:horizontal-tb; font-size:clamp(38px,7.4vw,124px); }
  body[data-layout-closing="b"] .fin p{ margin:26px auto 0; }
  body[data-layout-closing="b"] .fin .cta{ margin-top:40px; }

  body[data-layout-footer="b"] .foot-grid{ grid-template-columns:1fr; }
  body[data-layout-footer="b"] .foot-brand{ grid-column:auto; grid-template-columns:minmax(0,1fr); row-gap:16px; }
  body[data-layout-footer="b"] .foot-grid > div:nth-child(n+3){ padding-left:0; border-left:0; }
  body[data-layout-footer="b"] .foot-base{ display:flex; }
  body[data-layout-footer="b"] .foot-base span:last-child{ text-align:left; }
}

/* On a phone two columns leave the chip's copy about 110px once the numeral
   and its gutter are taken out, which is narrow enough to wrap a single word
   to a line. Standing the numeral above the label gives the copy the whole
   column back. */
@media (max-width:560px){
  body[data-layout-hero="b"] .chip{ flex-direction:column; gap:4px; }
  body[data-layout-hero="b"] .chip .num{ font-size:clamp(22px,7.4vw,30px); }
  body[data-layout-hero="b"] .chip .tx{ padding-top:0; }
  body[data-layout-hero="b"] .chip p{ max-width:none; }
}

@media (prefers-reduced-motion:reduce){
  *{ animation-duration:.001ms !important; animation-iteration-count:1 !important; transition-duration:.001ms !important; }
  [data-rv]{ opacity:1 !important; transform:none !important; }
  .mask-line > span,.word{ opacity:1 !important; transform:none !important; }
}

/* =================================================================
   3 · PORTFOLIO
   The portfolio's own pieces — projects, filters, the pager, the
   portrait, skills, experience, certificates, dialogs and the contact
   form — written in the Kage grammar above. Where the portfolio needs
   something the authored page did not, it is overridden here instead
   of being edited in place, so the block above stays as Kage wrote it.
   ================================================================= */

/* .card, .cta and friends set display, which outranks the UA [hidden] */
[hidden]{ display:none !important; }
/* items held back by "View more" */
.is-collapsed{ display:none !important; }

a:focus-visible, button:focus-visible{ outline:1px solid var(--bone); outline-offset:4px; }

/* ------------------------------------------------ Indonesian accents
   Kage hangs a small Japanese word beside the English. The portfolio
   uses Indonesian words in the same places, so they are Latin now:
   capitals, and never set in the Japanese face. */
.jp{ text-transform:uppercase; }
.les h3 em, .xp h3 em{ font-family:'Onest',system-ui,sans-serif; }

/* a Latin word read down the edge wants to be small and wide, not the
   54px a three-character kanji title was drawn at */
body[data-layout-hero="b"] .hero-side .v.jp{
  font-size:clamp(12px,1.05vw,16px); letter-spacing:.46em; color:rgba(223,231,224,.56);
}
/* The line is the owner's own and can run long. Where the chapter rail
   is shown it is centred on the right edge, just under this label, so
   the label stops above it: a long line folds into a second column
   instead of running through the rail. 60px is half the rail's height. */
@media (min-width:821px){
  body[data-layout-hero="b"] .hero-side .v.jp{
    max-height:calc(50vh - 60px - var(--nav-h) - clamp(14px,3vh,42px) - 24px);
  }
}
/* the peek caption carries a word, not a glyph pair */
body[data-layout-hero="b"] .peek-cap b.jp{ font-size:clamp(16px,1.5vw,24px); letter-spacing:.2em; }

/* Nav: the hover alternate is now a word, often longer than the label,
   and the link box would cut it off at the sides. The box keeps the
   label's width so the links stay evenly spaced; the clip moves from
   overflow to a clip-path that still cuts above and below (the slide
   needs that) but lets the word run past the sides, centred on the
   label. */
@media (min-width:821px){
  .nav-link{ overflow:visible; clip-path:inset(0 -60px); }
  .nav-link .alt{ right:auto; left:50%; width:max-content; translate:-50% 0; white-space:nowrap; letter-spacing:.24em; }
}

/* Hero chips are links here: each one opens its chapter */
a.chip{ color:inherit; }

/* The fallback word is eight letters, not four */
.no-webgl .word-fb{ font-size:12.4vw; letter-spacing:.03em; }

/* A chapter can run on across more than one section: experience and
   certificates belong to chapter 03, so they close up under it */
.sec--sub{ padding-top:clamp(40px,7vh,96px); }

.sec-head h2.k{ margin:0; }

/* ------------------------------------------------------------ Work */
.filters{
  display:flex; gap:clamp(18px,2.2vw,34px); margin:0 0 clamp(26px,4.4vh,48px);
  overflow-x:auto; scrollbar-width:none; -webkit-overflow-scrolling:touch;
}
.filters::-webkit-scrollbar{ display:none; }
.filter{
  position:relative; flex:0 0 auto; display:inline-flex; align-items:baseline; gap:7px;
  padding:6px 0 8px; font-size:11px; font-weight:500; letter-spacing:.2em; text-transform:uppercase;
  color:var(--bone-dim); text-shadow:0 1px 16px rgba(3,6,8,.9); transition:color .3s;
}
.filter .count{ font-size:9px; letter-spacing:.12em; color:var(--muted); transition:color .3s; }
.filter::after{
  content:''; position:absolute; left:0; bottom:0; width:100%; height:1px; background:var(--vermilion);
  transform:scaleX(0); transform-origin:left; transition:transform .6s var(--ease-out);
}
.filter:hover{ color:var(--bone); }
.filter.is-active{ color:var(--bone); }
.filter.is-active::after{ transform:none; }
.filter.is-active .count{ color:var(--bone-dim); }

/* The Kage B mosaic, generalised: the first three projects on show make
   the tall window and its two stacked companions, and everything after
   runs on three to a row. Six tracks so the lead takes two thirds, the
   same 2:1 the authored 1.55fr / .75fr split gives. */
#workGrid.cards{
  --cols:3;
  grid-template-columns:repeat(6,minmax(0,1fr));
  grid-template-rows:none; grid-auto-rows:auto;
  gap:14px; align-items:stretch;
}
#workGrid .card{ grid-column:span 2; grid-row:auto; transform:none; display:flex; flex-direction:column; min-height:0; }
#workGrid .card-hit{ display:flex; flex-direction:column; flex:1 1 auto; min-height:0; width:100%; padding:0; text-align:left; }
#workGrid .card-fr{ display:block; aspect-ratio:4 / 5; height:auto; flex:0 0 auto; min-height:0; }
#workGrid .card--lead{ grid-column:span 4; grid-row:span 2; }
#workGrid .card--lead .card-fr{ aspect-ratio:auto; height:min(72vh,760px); }
#workGrid .card--side .card-fr{ aspect-ratio:auto; flex:1 1 auto; min-height:200px; }
/* a filter that leaves two projects splits the row, one leaves a single
   wide window */
#workGrid .card--half{ grid-column:span 3; }
#workGrid .card--half .card-fr{ aspect-ratio:4 / 3; }
#workGrid .card--solo{ grid-column:span 6; }
#workGrid .card--solo .card-fr{ aspect-ratio:auto; height:min(62vh,600px); }
#workGrid .card-meta{ gap:14px; }
#workGrid .card-meta span:first-child{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
#workGrid .card-meta span:last-child{ flex:0 0 auto; }
.card-hit:focus-visible{ outline-offset:6px; }
.card-lab b{ text-shadow:0 1px 18px rgba(3,6,8,.9); }

/* A project without a photo is a live window onto the sanctuary — the
   hole-punched frame the Kage cards were built around — with its line
   drawing standing in the middle of it */
#workGrid .card-fr--live{ background:transparent; }
.card-cover{
  position:absolute; inset:0; z-index:1; display:flex; align-items:center; justify-content:center;
  padding:9% 11% 24%; color:var(--bone); pointer-events:none;
}
.card-cover svg{
  width:100%; max-width:380px; max-height:100%; height:auto; overflow:visible;
  fill:none; stroke:currentColor; stroke-width:1.3; stroke-linecap:round; stroke-linejoin:round;
  opacity:.92; filter:drop-shadow(0 2px 16px rgba(3,6,9,.95));
  transition:transform .8s var(--ease-out);
}
.card:hover .card-cover svg{ transform:translate3d(0,-4px,0); }
.card-cover .s{ fill:rgba(5,7,10,.66); }
.card-cover .m{ opacity:.46; }
.card-cover .a{ stroke:var(--ember); }
.card-cover .af{ fill:var(--ember); stroke:none; }
.card-cover .aw{ fill:rgba(255,90,60,.14); stroke:none; }
.card-cover .t{ font-family:'Onest',system-ui,sans-serif; font-size:8.5px; letter-spacing:.06em; fill:currentColor; stroke:none; }
.card-cover .tt{ font-family:'Onest',system-ui,sans-serif; font-size:13px; font-weight:500; fill:currentColor; stroke:none; }
.card-cover .m-fill{ opacity:.5; }
/* without WebGL there is no window to look through, so the frame takes
   one of the three authored stills instead of going flat */
.no-webgl #workGrid .card-fr--live{
  background:linear-gradient(180deg,rgba(3,6,9,.30) 20%,rgba(3,6,9,.80)),
    url('../../secret-pathways-assets/generated/kage-approach.webp') center / cover no-repeat;
}
.no-webgl #workGrid .card-fr--live[data-still="1"]{
  background:linear-gradient(180deg,rgba(3,6,9,.30) 20%,rgba(3,6,9,.80)),
    url('../../secret-pathways-assets/generated/kage-lantern-court.webp') center / cover no-repeat;
}
.no-webgl #workGrid .card-fr--live[data-still="2"]{
  background:linear-gradient(180deg,rgba(3,6,9,.30) 20%,rgba(3,6,9,.80)),
    url('../../secret-pathways-assets/generated/kage-moonwater.webp') center / cover no-repeat;
}

.empty-note{ margin:26px 0 0; font-size:13px; color:var(--muted); }

/* "View more" — the pager wears the Kage call to action */
.more-wrap{ display:flex; justify-content:center; margin-top:clamp(36px,6vh,66px); }
.cta{ isolation:isolate; }
.more-wrap .cta{ margin-top:0; }
.cta .more-count{ color:var(--muted); letter-spacing:.14em; transition:color .45s var(--ease); }
.cta:hover .more-count{ color:rgba(5,7,10,.62); }
.cta svg{ width:13px; height:13px; flex:0 0 auto; }

@media (max-width:820px){
  /* the mosaic unstacks the way the authored one does: the lead stays
     the tall window, every other project becomes a letterbox */
  #workGrid.cards{ --cols:1; grid-template-columns:minmax(0,1fr); }
  #workGrid .card, #workGrid .card--lead, #workGrid .card--side,
  #workGrid .card--half, #workGrid .card--solo{ grid-column:auto; grid-row:auto; }
  #workGrid .card-fr, #workGrid .card--side .card-fr,
  #workGrid .card--half .card-fr{ aspect-ratio:16 / 10; height:auto; flex:0 0 auto; min-height:0; }
  #workGrid .card--lead .card-fr, #workGrid .card--solo .card-fr{ aspect-ratio:4 / 5; height:auto; }
  .card-cover{ padding:8% 18% 22%; }
  #workGrid .card--lead .card-cover{ padding:10% 12% 26%; }
}

/* ----------------------------------------------------------- About */
.gate-links{ display:flex; flex-wrap:wrap; gap:0 34px; }
.about-portrait{ margin:0; }
.about-fr{
  position:relative; display:block; aspect-ratio:4 / 5; overflow:hidden; background:var(--ink-2);
  outline:1px solid var(--line-soft); outline-offset:-1px;
}
.about-fr img{ width:100%; height:100%; object-fit:cover; object-position:50% 16%; }
/* a studio portrait on white is the brightest thing on a night page;
   the same scrim the plates carry settles it into the frame */
.about-fr::after{
  content:''; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(180deg,rgba(3,6,9,.26),rgba(3,6,9,.10) 38%,rgba(3,6,9,.66));
}
body[data-layout-story="b"] .gate-grid .about-portrait{
  grid-column:1 / 3; grid-row:2; width:min(100%,360px); margin-top:clamp(6px,2vh,26px);
}
body[data-layout-story="b"] .gate-grid .gate-copy{ grid-row:1 / 3; }
@media (max-width:1080px){
  body[data-layout-story="b"] .gate-grid .about-portrait,
  body[data-layout-story="b"] .gate-grid .gate-copy{ grid-column:auto; grid-row:auto; }
  body[data-layout-story="b"] .gate-grid .about-portrait{ width:min(100%,340px); margin-top:0; }
}
@media (max-width:560px){
  /* on a phone the portrait sits between the title and the copy; at full
     width it would push the story a whole screen down */
  body[data-layout-story="b"] .gate-grid .about-portrait{ width:min(76%,280px); }
}

/* ---------------------------------------------------------- Skills
   The atlas is authored for five plates, two then three. The plates
   now come from data.js in any number, so main.js marks which ones
   run wide and these rules place them — an id outranks the authored
   nth-child pattern without touching it. */
#skillsGrid .les{ grid-column:span 2; cursor:default; }
#skillsGrid .les.les--wide{ grid-column:span 3; }
#skillsGrid .les.les--full{ grid-column:span 6; }
#skillsGrid .les h3 em{
  display:block; margin:10px 0 0; font-size:10px; letter-spacing:.24em; color:var(--muted);
}
#skillsGrid .les p{ max-width:40ch; }
@media (max-width:1080px){
  #skillsGrid .les, #skillsGrid .les.les--wide{ grid-column:span 3; }
  #skillsGrid .les.les--full, #skillsGrid .les.les--odd{ grid-column:span 6; }
}
@media (max-width:820px){
  #skillsGrid .les, #skillsGrid .les.les--wide,
  #skillsGrid .les.les--full, #skillsGrid .les.les--odd{ grid-column:auto; }
}

/* ------------------------------------------------------ Experience
   The syllabus row Kage ships as its A layout, kept for the timeline:
   number, role, the note, and the period where the running time was. */
.xp-group{
  margin:clamp(34px,5vh,60px) 0 16px; font-size:10px; font-weight:500; letter-spacing:.24em;
  text-transform:uppercase; color:var(--muted);
}
.xp-group:first-child{ margin-top:0; }
.xp-list{ list-style:none; margin:0; padding:0; border-top:1px solid var(--line-soft); }
.xp{
  position:relative; display:grid; align-items:start;
  grid-template-columns:64px minmax(0,1fr) minmax(0,1.25fr) 150px;
  gap:clamp(14px,2.4vw,40px);
  padding:clamp(20px,2.4vw,30px) 0; border-bottom:1px solid var(--line-soft);
  transition:padding .5s var(--ease-out);
}
.xp::before{
  content:''; position:absolute; left:calc(var(--pad) * -1); right:0; top:0; bottom:0;
  background:linear-gradient(90deg, rgba(224,35,28,.09), transparent 46%);
  opacity:0; transition:opacity .55s var(--ease); pointer-events:none;
}
.xp:hover::before{ opacity:1; }
.xp:hover{ padding-left:clamp(8px,1.2vw,18px); }
.xp .k{ padding-top:6px; font-size:11px; letter-spacing:.16em; color:var(--muted); font-variant-numeric:tabular-nums; transition:color .4s; }
.xp:hover .k{ color:var(--vermilion); }
.xp h3{ font-size:clamp(16px,1.5vw,23px); font-weight:400; letter-spacing:-.005em; text-shadow:0 1px 18px rgba(3,6,8,.9); }
.xp h3 em{ display:block; margin:0 0 8px; font-style:normal; font-size:10px; letter-spacing:.24em; color:var(--muted); }
.xp-org{ display:block; margin-top:6px; font-size:13px; color:var(--bone-dim); }
.xp-note p{ margin:0; font-size:13px; line-height:1.6; color:#909b95; text-shadow:0 1px 16px rgba(3,6,8,.92); }
.xp-tags{
  display:flex; flex-wrap:wrap; gap:6px 16px; margin:12px 0 0; padding:0; list-style:none;
  font-size:10px; letter-spacing:.16em; text-transform:uppercase; color:var(--muted);
}
.xp .t{
  padding-top:6px; text-align:right; font-size:11px; letter-spacing:.14em; color:#8b958f;
  font-variant-numeric:tabular-nums; text-shadow:0 1px 16px rgba(3,6,8,.92);
}
.xp .bar{
  position:absolute; left:0; bottom:-1px; height:1px; width:100%; background:var(--vermilion);
  transform:scaleX(0); transform-origin:left; transition:transform .7s var(--ease-out);
}
.xp:hover .bar{ transform:scaleX(1); }
@media (max-width:1080px){
  .xp{ grid-template-columns:44px minmax(0,1fr) 128px; row-gap:12px; }
  .xp .k{ grid-column:1; grid-row:1; }
  .xp h3{ grid-column:2; grid-row:1; }
  .xp .t{ grid-column:3; grid-row:1; }
  .xp-note{ grid-column:2 / 4; grid-row:2; }
}
@media (max-width:560px){
  .xp{ grid-template-columns:34px minmax(0,1fr); }
  .xp .t{ grid-column:2; grid-row:2; padding-top:0; text-align:left; }
  .xp-note{ grid-column:2; grid-row:3; }
}

/* ---------------------------------------------------- Certificates */
.cert-count{ margin:0 0 18px; font-size:10px; font-weight:500; letter-spacing:.24em; text-transform:uppercase; color:var(--muted); }
.cert-grid{ list-style:none; margin:0; padding:0; display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:14px; }
.cert{ display:flex; flex-direction:column; width:100%; padding:0; text-align:left; }
.cert-fr{
  position:relative; display:block; aspect-ratio:4 / 3; overflow:hidden; background:var(--ink-2);
  outline:1px solid var(--line-soft); outline-offset:-1px; transition:outline-color .5s var(--ease);
}
.cert-fr img{
  width:100%; height:100%; object-fit:cover; object-position:top;
  filter:saturate(.9) brightness(.9); transition:transform .9s var(--ease-out);
}
.cert:hover .cert-fr{ outline-color:rgba(223,231,224,.30); }
.cert:hover .cert-fr img{ transform:scale(1.03); }
.cert-doc{
  position:absolute; inset:0; display:grid; place-items:center; align-content:center; gap:10px;
  font-size:10px; font-weight:500; letter-spacing:.24em; color:var(--bone-dim);
}
.cert-doc svg{ width:30px; height:30px; fill:none; stroke:currentColor; stroke-width:1.2; }
.cert-lab{ display:flex; flex-direction:column; gap:5px; margin-top:12px; }
.cert-lab b{ font-size:13px; font-weight:400; line-height:1.45; color:var(--bone); }
.cert-lab span{ font-size:10px; letter-spacing:.16em; text-transform:uppercase; color:var(--muted); }
.cert-empty{
  max-width:660px; padding:24px 26px; border:1px solid var(--line); background:rgba(5,7,10,.78);
  font-size:13px; line-height:1.7; color:var(--bone-dim);
}
.cert-empty-title{ margin:0 0 10px; font-size:10px; font-weight:500; letter-spacing:.22em; text-transform:uppercase; color:var(--bone); }
.cert-empty ol{ margin:0; padding-left:18px; display:grid; gap:8px; }
.cert-empty code{ font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size:12px; color:var(--bone); }
@media (max-width:1080px){ .cert-grid{ grid-template-columns:repeat(3,minmax(0,1fr)); } }
@media (max-width:560px){ .cert-grid{ grid-template-columns:repeat(2,minmax(0,1fr)); } }

/* --------------------------------------------------------- Contact */
/* The closing chapter's near plane (hill, ruins, the last branch) rises
   from the lower edge exactly where the call to action lands. The
   planting stays as authored; the chapter's content is lifted clear of
   it instead, since here the button is the one thing that must read. */
#contact.fin{ padding-bottom:clamp(150px,27vh,290px); }
.fin p a{ color:var(--bone); border-bottom:1px solid var(--line); transition:border-color .35s; }
.fin p a:hover{ border-bottom-color:var(--bone); }
/* a plain line in a footer list (the location) reads like the links */
.foot li > span{ font-size:13px; color:#79847e; }

/* --------------------------------------------------------- Dialogs
   Native <dialog>s for the project gallery, the certificate viewer and
   the contact form. They open in the top layer, above the grain and the
   vignette, so each carries its own hairline frame and ink panel. */
html.dialog-open, html.dialog-open body{ overflow:hidden; }
.kd{
  width:min(1120px, calc(100vw - 2 * var(--pad))); max-width:none; max-height:min(88svh,820px);
  margin:auto; padding:0; border:1px solid var(--line); border-radius:0;
  background:rgba(8,11,14,.97); color:var(--bone); overflow:hidden;
  box-shadow:0 40px 120px -40px rgba(0,0,0,.95);
}
.kd::backdrop{ background:rgba(2,4,6,.76); -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px); }
.kd[open]{ animation:kd-in .62s var(--ease-out); }
.kd[open]::backdrop{ animation:kd-fade .5s var(--ease-out); }
@keyframes kd-in{ from{ opacity:0; transform:translate3d(0,18px,0) scale(.985); } to{ opacity:1; transform:none; } }
@keyframes kd-fade{ from{ opacity:0; } to{ opacity:1; } }
.kd-inner{ position:relative; display:grid; grid-template-columns:minmax(0,1.3fr) minmax(0,1fr); max-height:min(88svh,820px); }
.kd-media{ position:relative; display:flex; flex-direction:column; min-height:0; background:#05070a; border-right:1px solid var(--line-soft); }
.kd-stage{ position:relative; flex:1 1 auto; min-height:min(58svh,560px); overflow:hidden; }
.kd-stage img{ position:absolute; inset:0; width:100%; height:100%; object-fit:contain; }
.kd-stage .card-cover{ padding:12% 14%; }
.kd-caption{
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:14px 18px; border-top:1px solid var(--line-soft); font-size:12px; line-height:1.5; color:var(--bone-dim);
}
.kd-caption p{ margin:0; }
.kd-nav{ display:flex; align-items:center; gap:10px; flex:0 0 auto; margin-left:auto; }
.kd-count{ min-width:46px; text-align:center; font-size:10px; letter-spacing:.16em; color:var(--muted); font-variant-numeric:tabular-nums; }
.kd-btn{
  width:34px; height:34px; flex:0 0 auto; border:1px solid var(--line); border-radius:50%;
  display:grid; place-items:center; background:rgba(5,7,10,.5);
  transition:background .45s var(--ease), border-color .45s;
}
.kd-btn svg{ width:14px; height:14px; fill:none; stroke:var(--bone); stroke-width:1.4; transition:stroke .3s; }
.kd-btn:hover{ background:var(--bone); border-color:var(--bone); }
.kd-btn:hover svg{ stroke:#05070a; }
.kd-close{ position:absolute; top:14px; right:14px; z-index:3; }
.kd-body{ min-height:0; overflow-y:auto; padding:clamp(28px,3.4vw,50px); }
.kd-meta{ margin:0 0 16px; }
.kd-title{ margin:0 0 18px; padding-right:40px; font-size:clamp(26px,2.5vw,40px); }
.kd-summary{ margin:0; }
.kd-details{ margin:28px 0 0; border-top:1px solid var(--line-soft); }
.kd-details div{
  display:grid; grid-template-columns:minmax(92px,.42fr) minmax(0,1fr); gap:16px;
  padding:12px 0; border-bottom:1px solid var(--line-soft);
}
.kd-details dt{ padding-top:3px; font-size:10px; font-weight:500; letter-spacing:.2em; text-transform:uppercase; color:var(--muted); }
.kd-details dd{ margin:0; font-size:13px; line-height:1.6; color:var(--bone-dim); }
.kd-links{ display:flex; flex-wrap:wrap; gap:0 30px; }
.kd-links .arrowlink{ margin-top:28px; }

/* the certificate viewer: one column, the document first */
.kd--cert .kd-inner{ grid-template-columns:minmax(0,1fr); }
.kd--cert .kd-media{ border-right:0; }
.kd--cert .kd-stage{ min-height:min(62svh,640px); }
.kd--cert .kd-caption{ flex-wrap:wrap; }
.kd-cert-title{ margin:0; font-size:14px; color:var(--bone); }
.kd-cert-meta{ margin:4px 0 0; font-size:10px; letter-spacing:.16em; text-transform:uppercase; color:var(--muted); }
.kd--cert .arrowlink{ margin-top:0; }

/* the contact form */
.kd--form{ width:min(660px, calc(100vw - 2 * var(--pad))); }
.kd--form .kd-inner{ grid-template-columns:minmax(0,1fr); }
.kform{ display:grid; gap:20px; margin-top:28px; }
.kform-row{ display:grid; grid-template-columns:1fr 1fr; gap:20px; }
.kfield{ display:flex; flex-direction:column; gap:8px; }
.kfield label{ font-size:10px; font-weight:500; letter-spacing:.2em; text-transform:uppercase; color:var(--muted); }
.kfield .opt{ letter-spacing:.1em; text-transform:none; color:#5f6a64; }
.kfield input, .kfield textarea{
  width:100%; padding:8px 0 10px; font:inherit; font-size:15px; font-weight:300; color:var(--bone);
  background:transparent; border:0; border-bottom:1px solid var(--line); border-radius:0; outline:0;
  transition:border-color .4s var(--ease);
}
.kfield textarea{ min-height:120px; resize:vertical; line-height:1.6; }
.kfield input:focus, .kfield textarea:focus{ border-bottom-color:var(--vermilion); }
.kfield input:-webkit-autofill{ -webkit-text-fill-color:var(--bone); box-shadow:0 0 0 1000px #0a0e12 inset; }
.kform-foot{ display:flex; flex-wrap:wrap; align-items:center; gap:14px 24px; margin-top:6px; }
.kform-foot .cta{ margin-top:0; }
.kform-foot .cta:disabled{ opacity:.5; cursor:progress; }
.form-status{ margin:0; font-size:12px; color:var(--bone-dim); }
.form-status.is-success{ color:var(--bone); }
.form-status.is-error{ color:var(--ember); }

@media (max-width:820px){
  /* on a phone the dialogs become sheets on the lower edge */
  .kd{ width:100vw; max-height:92svh; margin:auto 0 0; border-width:1px 0 0; }
  .kd-inner{ grid-template-columns:minmax(0,1fr); max-height:92svh; overflow-y:auto; }
  .kd-media{ border-right:0; border-bottom:1px solid var(--line-soft); }
  .kd-stage{ flex:0 0 auto; min-height:0; aspect-ratio:4 / 3; }
  .kd--cert .kd-stage{ min-height:0; aspect-ratio:4 / 3; }
  .kd-body{ overflow:visible; }
  .kd[open]{ animation-name:kd-up; }
  @keyframes kd-up{ from{ opacity:0; transform:translate3d(0,40px,0); } to{ opacity:1; transform:none; } }
}
@media (max-width:560px){
  .kform-row{ grid-template-columns:1fr; }
}
