/* =====================================================================
   openjkdf2_libretro — public site

   The same palette and the same monospace voice as the COG Factory's own
   working index (tools/cogfactory/projects/index.html), on purpose: the
   public pages and the working pages are one body of work, and a visitor who
   follows a link into the tooling should not feel the seam.

   Dark only, and deliberately so — this is a terminal-coloured site about a
   1997 game engine, not a document that wants to follow a reading mode.
   ===================================================================== */
:root{
  --bg:#0b0d10; --panel:#14171c; --panel2:#1b1f26; --line:#2a3039;
  --ink:#d8dde4; --dim:#8b95a3; --faint:#5c6674;
  --amber:#ffb02e; --cyan:#4fd1e0; --green:#5ee08a; --red:#ff6b5e;
  --mono:"Cascadia Mono",Consolas,"DejaVu Sans Mono",ui-monospace,monospace;
  --wrap:1360px;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0; background:var(--bg); color:var(--ink);
  font-family:var(--mono); font-size:14px; line-height:1.62;
  -webkit-font-smoothing:antialiased;
}
img{max-width:100%;height:auto;display:block}
a{color:var(--cyan);text-decoration:none}
a:hover{text-decoration:underline}
code{background:var(--panel2);border:1px solid var(--line);border-radius:3px;
  padding:1px 5px;font-size:.92em;color:#cfd6df}
.wrap{max-width:var(--wrap);margin:0 auto;padding:0 24px}
.dim{color:var(--faint)}
h1,h2,h3{line-height:1.24}

/* ---- top nav -------------------------------------------------------- */
.topnav{
  position:sticky;top:0;z-index:50;border-bottom:1px solid var(--line);
  background:rgba(11,13,16,.94);backdrop-filter:blur(8px);
}
.topnav .wrap{display:flex;align-items:center;gap:20px;
  height:52px;flex-wrap:wrap}
.brand{color:var(--amber);font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;font-size:13.5px}
.brand span{color:var(--faint)}
.brand:hover{text-decoration:none;color:#ffc25c}
.navlinks{margin-left:auto;display:flex;gap:6px;flex-wrap:wrap}
.navlinks a{
  color:var(--dim);font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;
  padding:6px 11px;border:1px solid transparent;border-radius:4px;
}
.navlinks a:hover{color:var(--ink);border-color:var(--line);text-decoration:none}
.navlinks a.on{color:var(--amber);border-color:#5c4318;background:#241a08}
.navlinks a.ext{color:var(--faint)}

/* ---- heads ---------------------------------------------------------- */
.hero,.pagehead{
  border-bottom:1px solid var(--line);
  background:linear-gradient(180deg,#11151b 0%,#0b0d10 100%);
  padding:52px 0 40px;
}
.pagehead{padding:34px 0 26px}

/* ---- the hero picture ------------------------------------------------
   THE BAND TRAVELS; the picture does not merely sit behind it. That is a
   composition decision before it is an effect one. The two duellists are
   1361px apart horizontally and 1069px vertically in the source, and a band
   470px tall cannot hold a diagonal that long: whatever crop you choose, one
   of them is outside it. Rotating the picture to lay the diagonal flat needs
   38 degrees, and a 38-degree rotation leaves a usable rectangle the pair
   spans edge to edge -- level at last, and nowhere to put them. There was no
   static crop that worked.

   So the picture is taller than the band and moves up FASTER than the page.
   You meet the Sith at the top and find Kyle on the way down, and the frame
   that could not hold both at once no longer has to.

   Three layers, each its own element so they can move independently:
     ::before  the photograph, 168% of the band's height, translating up
     ::after   the scrims -- fixed to the band, so the type is protected at
               every scroll position, not just at the top
     .wrap     the type, above both

   The colour grading is baked into herobg.jpg by make_hero_bg.py, because a
   flat CSS wash dark enough to make white text safe over a forest fire turns
   the fire into a grey rectangle. CSS does the scrim, pixels do the grade. */
.hero{position:relative;overflow:hidden;isolation:isolate}
.hero .wrap{position:relative;z-index:2}

/* BOUND TO THE CONTENT COLUMN, not the row. `left:38%` on a full-bleed layer
   is 38% of the VIEWPORT, so on a 2560px monitor the panel ran ~600px past
   the text column it belongs to and read as wallpaper rather than as art
   behind the words. Capping this box at --wrap and centring it makes the
   picture's right edge land exactly on the text's right edge at every width;
   below --wrap it simply fills, matching .wrap. */
.heroart{
  position:absolute;top:0;bottom:0;left:0;right:0;
  max-width:var(--wrap);margin-inline:auto;
  overflow:hidden;z-index:0;pointer-events:none;
}

/* A PANEL, NOT A BACKDROP. `cover` on a full-width band 470px tall can only
   ever show half the height of a 3:2 picture -- which is why no crop of it
   ever had both faces in at once. Confined to the right of the row the box is
   nearly as tall as it is wide, so almost the whole picture fits, and it is
   permanently clear of the type. The left edge is masked rather than cut, so
   it fades into the ground instead of ending on a seam. */
.heroart::before{
  content:"";position:absolute;left:38%;right:0;top:0;height:150%;z-index:0;
  background:#0b0d10 url(herobg.jpg) center top / cover no-repeat;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 26%,#000 100%);
          mask-image:linear-gradient(90deg,transparent 0,#000 26%,#000 100%);
  transform:translate3d(0,var(--hero-rest),0);
  will-change:transform;
}
.heroart::after{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(90deg,
      rgba(11,13,16,.90) 0%, rgba(11,13,16,.72) 44%,
      rgba(11,13,16,.30) 62%, rgba(11,13,16,.06) 82%,
      rgba(11,13,16,0) 100%),
    linear-gradient(180deg,
      rgba(11,13,16,.30) 0%, rgba(11,13,16,0) 34%,
      rgba(11,13,16,.62) 90%, var(--bg) 100%);
}

/* THE TWO NUMBERS THAT DECIDE THE MOTION, and the only ones to touch.
   --hero-from is where the picture sits at the top of the page and --hero-to
   is where it has travelled to by the end of the range. To reverse the whole
   effect -- to open on Kyle and rise to the Sith as you scroll -- swap them:

       --hero-from:-33%;  --hero-to:0%;   --hero-rest:-16%;

   --hero-rest is the still position for browsers that cannot animate, so keep
   it between the other two. */
:root{ --hero-from:0%; --hero-to:-33%; --hero-rest:-16%; }

@keyframes heropan{
  from{transform:translate3d(0,var(--hero-from),0)}
  to{transform:translate3d(0,var(--hero-to),0)}
}

/* PARALLAX WHERE IT ACTUALLY WORKS -- and unlike `background-attachment:
   fixed`, this is a capability query that means something. @supports reports
   background-attachment:fixed as supported on iOS, which then ignores it;
   `animation-timeline: scroll()` is either implemented or it is not. Browsers
   without it keep the resting transform above, which is a composition and not
   a broken effect. The motion is also off for anyone who has asked for less
   of it. */
/* The scripted fallback writes --heropan on .hero; this is the only thing it
   touches, and without the script the property never resolves so the resting
   transform above stands. */
.hero.js-parallax .heroart::before{transform:translate3d(0,var(--heropan,var(--hero-rest)),0)}

@supports (animation-timeline: scroll()){
  @media (prefers-reduced-motion: no-preference){
    .heroart::before{
      transform:translate3d(0,var(--hero-from),0);
      animation:heropan linear both;
      animation-timeline:scroll(root block);
      animation-range:0 460px;
    }
  }
}

@media (max-width:900px){
  /* Narrow: the type fills the band, so the scrim is flat and heavy and the
     picture is texture rather than subject. */
  .heroart::before{left:0;height:150%;background-position:62% top;
    -webkit-mask-image:none;mask-image:none}
  .heroart::after{
    background:linear-gradient(180deg,
      rgba(11,13,16,.80) 0%, rgba(11,13,16,.86) 55%, var(--bg) 100%);
  }
}

.hero h1{
  margin:0;font-size:clamp(28px,5.2vw,52px);letter-spacing:.14em;
  text-transform:uppercase;color:var(--amber);font-weight:700;
}
.hero h1 span{color:var(--faint)}
/* Credit where the engine came from, directly under the name it is packaged
   as -- above the pitch, because it outranks the pitch. */
.thanks{
  margin:18px 0 0;max-width:76ch;color:var(--dim);font-size:13px;
  border-left:2px solid var(--cyan);padding-left:14px}
.thanks a{color:var(--cyan)}
.pagehead h1{margin:6px 0 0;font-size:clamp(22px,3.6vw,34px);
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink)}
.crumb{margin:0;font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--faint)}
.crumb a{color:var(--faint)}
.lede{max-width:82ch;color:var(--dim);font-size:15px;margin:16px 0 0}
.pagehead .sub,.card .sub,.part .sub{
  color:var(--amber);font-size:11.5px;letter-spacing:.14em;
  text-transform:uppercase;margin-top:8px}
.stats{margin-top:14px;color:var(--faint);font-size:12.5px;letter-spacing:.04em}
.stats b{color:var(--ink);font-weight:600}
.warn{
  margin:18px 0 0;padding:10px 14px;border-left:2px solid var(--amber);
  background:#1a1408;color:#d9c9a8;font-size:13px;max-width:78ch}
.note{
  margin:14px 0 0;color:var(--faint);font-size:12px;
  border-left:2px solid var(--line);padding-left:10px;max-width:88ch}

/* ---- buttons -------------------------------------------------------- */
.btns{display:flex;gap:12px;flex-wrap:wrap;margin-top:26px}
.btn{
  display:inline-flex;align-items:center;gap:9px;
  border:1px solid var(--line);border-radius:5px;padding:9px 16px;
  font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;
  font-weight:700;color:var(--ink);background:var(--panel);white-space:nowrap;
}
.btn:hover{text-decoration:none;border-color:var(--faint)}
.btn.big{padding:14px 24px;font-size:13px}
.btn.dl{background:var(--amber);border-color:var(--amber);color:#0b0d10}
.btn.dl:hover{background:#ffc25c;border-color:#ffc25c}
.btn.ghost{background:transparent}
.btn.ghost:hover{background:var(--panel)}
.btn.cold{
  background:transparent;border-style:dashed;color:var(--faint);
  cursor:default;font-weight:400}
.btn .sz{font-weight:400;opacity:.75;letter-spacing:.06em;text-transform:none}

/* ---- sections ------------------------------------------------------- */
main{padding:34px 0 72px;min-height:40vh}
/* The landing page's first section sat 27px under the hero's bottom rule, so
   the DOWNLOAD heading read as part of the hero rather than as the start of
   the page. Give the rule room on both sides: the hero gets more below its
   content, and the first section more above its title. */
.home main{padding-top:60px}

/* A TALLER BAND. The hero is the only place on the site carrying a picture,
   and at 52/40 the type filled it corner to corner with the art squeezed into
   whatever was left. The extra height is not decoration: .heroart is 150% of
   the hero, so a taller band shows more of the picture AND gives the travel
   more absolute distance to move through. */
.hero{padding:92px 0 88px}
section{margin:0 0 46px}
section h2{
  margin:0 0 14px;font-size:15px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--amber);border-bottom:1px solid var(--line);padding-bottom:9px}
.two{display:grid;gap:30px;grid-template-columns:repeat(auto-fit,minmax(320px,1fr))}
.two h3{margin:0 0 10px;font-size:13px;letter-spacing:.1em;text-transform:uppercase}
.rel{margin:0 0 12px}
.pill{
  font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;
  padding:2px 7px;border-radius:3px;border:1px solid;white-space:nowrap;
  vertical-align:middle}
.pill.answered{color:var(--green);border-color:#25583a;background:#0f2519}
.pill.open{color:var(--amber);border-color:#5c4318;background:#241a08}
ul.assets,ul.need{list-style:none;padding:0;margin:0}
ul.assets li{
  display:flex;gap:12px;align-items:baseline;padding:8px 0;
  border-bottom:1px solid var(--line)}
ul.assets .sz{margin-left:auto;color:var(--faint);font-size:12px}
ul.need li{padding:6px 0 6px 16px;position:relative;color:var(--dim)}
ul.need li::before{content:"▸";position:absolute;left:0;color:var(--faint)}
ol.how{margin:0;padding-left:22px;color:var(--dim);max-width:92ch}
ol.how li{margin:0 0 9px}
ol.how b{color:var(--ink)}

/* ---- home strip ----------------------------------------------------- */
/* SIX tiles, and an explicit column count rather than auto-fit: six items on
   an auto-fitted grid orphan one at whatever width happens to fit five, and a
   landing page's featured row is exactly where that shows. 3/2/1 always
   divides six. */
.strip{display:grid;gap:12px;margin:20px 0 24px;grid-template-columns:repeat(3,1fr)}
@media (max-width:1000px){.strip{grid-template-columns:repeat(2,1fr)}}
@media (max-width:560px){.strip{grid-template-columns:1fr}}
.tile{position:relative;display:block;border:1px solid var(--line);
  border-radius:6px;overflow:hidden;background:#06070a}
.tile:hover{border-color:#3c454f;text-decoration:none}
.tile img{aspect-ratio:16/9;object-fit:cover;width:100%}
.tile span{
  position:absolute;left:0;right:0;bottom:0;padding:16px 10px 7px;
  background:linear-gradient(180deg,transparent,rgba(0,0,0,.86));
  color:var(--ink);font-size:11.5px;letter-spacing:.08em;text-transform:uppercase}

/* ---- subsection tiles ----------------------------------------------- */
.sects{display:grid;gap:18px;margin-bottom:46px;
  grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}
.sect{
  display:block;background:var(--panel);border:1px solid var(--line);
  border-radius:7px;padding:22px 20px 18px;color:var(--ink)}
.sect:hover{border-color:var(--amber);text-decoration:none;transform:translateY(-2px)}
.sect{transition:border-color .12s,transform .12s}
.sect{padding:0;overflow:hidden}
.sect > .kicker,.sect > h3,.sect > p,.sect > .count{
  margin-left:20px;margin-right:20px;display:block}
.sect > .kicker{margin-top:20px}
.sect > .count{margin-bottom:20px}
/* Three frames across the head of a section tile: a strip of what is behind
   the link, cropped square so three of them tile evenly at any width. */
.pv{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--line);
  border-bottom:1px solid var(--line);margin-bottom:4px}
.pv img{width:100%;aspect-ratio:4/3;object-fit:cover;opacity:.82}
.sect:hover .pv img{opacity:1}
.sect .kicker{font-size:10px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--faint)}
.sect h3{margin:6px 0 10px;font-size:17px;letter-spacing:.06em;color:var(--amber)}
.sect p{margin:0;color:var(--dim);font-size:13px}
.sect .count{
  display:inline-block;margin-top:14px;font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink);border:1px solid var(--line);
  border-radius:999px;padding:4px 11px}
.sect.cold{opacity:.72}
.sect.cold h3{color:var(--dim)}
.sect.cold:hover{border-color:var(--line);transform:none}

/* ---- project grid --------------------------------------------------- */
.grid{display:grid;gap:20px;grid-template-columns:repeat(auto-fill,minmax(348px,1fr))}
.card{
  background:var(--panel);border:1px solid var(--line);border-radius:7px;
  overflow:hidden;display:flex;flex-direction:column;
  transition:border-color .12s,transform .12s}
.card:hover{border-color:#3c454f;transform:translateY(-2px)}
.card .shot{
  position:relative;display:block;aspect-ratio:16/9;background:#06070a}
.card .shot img{width:100%;height:100%;object-fit:cover}
.card .shot:hover{text-decoration:none}
.noshot{
  display:flex;align-items:center;justify-content:center;height:100%;
  color:var(--faint);font-size:11px;letter-spacing:.18em;
  background:repeating-linear-gradient(135deg,#0e1116 0 10px,#12161c 10px 20px)}
.num{
  position:absolute;left:0;top:0;background:rgba(0,0,0,.74);
  border-right:1px solid var(--line);border-bottom:1px solid var(--line);
  color:var(--amber);font-size:11px;font-weight:700;letter-spacing:.1em;padding:4px 9px}
.more,.legacy{
  position:absolute;bottom:8px;background:rgba(0,0,0,.74);
  border:1px solid var(--line);color:var(--dim);font-size:10px;
  padding:2px 7px;border-radius:3px;letter-spacing:.08em}
.more{right:8px}
.legacy{left:8px;color:var(--faint);border-style:dashed}
.card .body{padding:14px 15px 0;flex:1}
.card h3{margin:0;font-size:15px;letter-spacing:.08em;text-transform:uppercase}
.card h3 a{color:var(--ink)}
.card h3 a:hover{color:var(--amber);text-decoration:none}
.card .sub{margin-top:6px}
.card p{margin:10px 0 0;color:var(--dim);font-size:12.5px}
.card .stats{margin-top:10px;font-size:11.5px}
.chips{display:flex;gap:5px;flex-wrap:wrap;margin:12px 0 0}
.chip{
  font-size:10px;letter-spacing:.06em;color:var(--faint);
  border:1px solid var(--line);border-radius:999px;padding:2px 8px}
.card .foot{
  display:flex;gap:9px;align-items:center;flex-wrap:wrap;
  margin-top:14px;padding:12px 15px;border-top:1px solid var(--line);
  background:var(--panel2)}

/* ---- project page --------------------------------------------------- */
.heroshot{
  width:100%;border:1px solid var(--line);border-radius:7px;margin-bottom:26px;
  background:#06070a}
.qa{max-width:96ch}
.qa .q{color:var(--dim);font-size:15px;margin:0 0 14px}
.qa .q b{color:var(--amber)}
.verdict{
  border-left:2px solid var(--line);background:var(--panel);
  padding:14px 16px;color:var(--dim);font-size:13.5px;max-width:96ch}
.verdict b{color:var(--ink)}
.verdict i{color:var(--ink);font-style:italic}
table.meta{
  border-collapse:collapse;margin:26px 0 40px;width:100%;max-width:96ch;
  font-size:12.5px}
table.meta th,table.meta td{
  text-align:left;vertical-align:top;padding:8px 12px 8px 0;
  border-bottom:1px solid var(--line)}
table.meta th{
  color:var(--faint);font-weight:400;letter-spacing:.12em;text-transform:uppercase;
  font-size:10.5px;white-space:nowrap;width:1%;padding-right:26px}
.gallery{display:grid;gap:14px;grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}
.gallery .g{position:relative;display:block;border:1px solid var(--line);
  border-radius:6px;overflow:hidden;background:#06070a}
.gallery .g:hover{border-color:#3c454f;text-decoration:none}
.gallery .g img{width:100%;aspect-ratio:16/9;object-fit:cover}
.gallery .g span{
  position:absolute;left:0;bottom:0;background:rgba(0,0,0,.74);
  border-top:1px solid var(--line);border-right:1px solid var(--line);
  color:var(--dim);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
  padding:3px 9px}
.tex{display:flex;gap:8px;flex-wrap:wrap}
.tex .t{display:block;line-height:0}
.tex img{
  width:96px;height:96px;image-rendering:pixelated;
  border:1px solid var(--line);border-radius:4px;background:#06070a}
.tex .t:hover img{border-color:var(--amber)}

/* ---- lightbox -------------------------------------------------------- */
#lb{
  position:fixed;inset:0;z-index:200;background:rgba(4,5,7,.94);
  display:flex;align-items:center;justify-content:center;flex-direction:column;
  gap:14px;padding:52px 24px 24px}
/* An author `display` beats the UA sheet's [hidden]{display:none}, so the
   attribute needs saying again here or the overlay is up from the first
   paint -- with no picture in it, over the whole page. */
#lb[hidden]{display:none}
#lbimg{
  max-width:min(1280px,96vw);max-height:78vh;width:auto;
  border:1px solid var(--line);background:#06070a}
#lbimg.pix{image-rendering:pixelated;max-width:min(512px,80vw)}
#lbcap{color:var(--dim);font-size:12px;letter-spacing:.06em;text-align:center}
#lbx{position:absolute;top:14px;right:18px}
#lbx,.lbnav button{
  font-family:inherit;font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  background:var(--panel);border:1px solid var(--line);color:var(--ink);
  border-radius:4px;padding:8px 14px;cursor:pointer}
#lbx:hover,.lbnav button:hover{border-color:var(--amber);color:var(--amber)}
.lbnav{display:flex;gap:10px}
pre.readme{
  background:var(--panel);border:1px solid var(--line);border-radius:6px;
  padding:18px;overflow-x:auto;color:var(--dim);font-size:12px;line-height:1.5;
  max-height:520px}
/* ---- prev / next ----------------------------------------------------
   These were two 12px links in the footer margin and nobody found them.
   They are the only way to walk the catalogue in order, which is how the
   projects are meant to be read, so they get the weight of a real control:
   a full-width pair of panels carrying the next project's NAME. */
.pn{
  display:grid;gap:14px;grid-template-columns:1fr 1fr;
  border-top:1px solid var(--line);padding-top:26px;margin-top:34px}
/* DIRECT children only: `.pn span` also matched the `.dir` label INSIDE each
   link, which gave the word "Previous" its own bordered box. */
.pn > a,.pn > span{
  display:flex;flex-direction:column;gap:5px;min-height:72px;
  justify-content:center;padding:14px 20px;border-radius:6px;
  border:1px solid var(--line);background:var(--panel);color:var(--ink);
  transition:border-color .12s,background .12s,transform .12s}
.pn a:hover{
  text-decoration:none;border-color:var(--amber);background:var(--panel2);
  transform:translateY(-2px)}
.pn a:hover b{color:var(--amber)}
.pn .dir{
  font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--faint)}
.pn b{font-size:14.5px;letter-spacing:.06em;font-weight:700}
.pn .next{text-align:right;align-items:flex-end}
.pn > span{border-style:dashed;background:transparent;opacity:.35}
@media (max-width:640px){.pn{grid-template-columns:1fr}}

/* ---- build badge ------------------------------------------------------
   Which build of a level this is. It sits with the download button because
   that is the question it answers: not "how old is this page" but "is the
   file I already have the same file". */
.build{
  display:inline-flex;align-items:center;gap:8px;white-space:nowrap;
  font-size:10px;letter-spacing:.14em;text-transform:uppercase;font-weight:700;
  color:var(--green);border:1px solid #25583a;background:#0f2519;
  border-radius:999px;padding:4px 11px;margin-left:auto}
.build i{font-style:normal;font-weight:400;letter-spacing:.06em;
  text-transform:none;color:var(--dim)}
.build.big{font-size:11.5px;padding:9px 16px;border-radius:5px;margin-left:0}

/* ---- toolchain ------------------------------------------------------ */
.parts{display:grid;gap:18px;margin-bottom:46px;
  grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}
.part{background:var(--panel);border:1px solid var(--line);border-radius:7px;
  padding:20px}
.part h3{margin:0;font-size:15px;color:var(--amber);letter-spacing:.04em}
.part p{margin:12px 0 0;color:var(--dim);font-size:13px}

/* ---- footer --------------------------------------------------------- */
footer{border-top:1px solid var(--line);background:#0a0c0f;padding:30px 0 46px}
footer p{margin:0 0 12px;color:var(--faint);font-size:12px;max-width:96ch}
footer b{color:var(--dim)}

@media (max-width:560px){
  .wrap{padding:0 16px}
  .gallery{grid-template-columns:1fr}
  .grid{grid-template-columns:1fr}
}
