@import url("tokens.css");
@import url("base.css");

/* Grimberg Studio — sub-page chrome.
   The palette, type and notch come from the import above; this file is only the chrome.
   Sub-pages drop the parallax stage and keep the type, the notch and the amber.
   (The :root block here used to be a hand-copied subset of tokens.css and had already
   drifted from it — --font-mono had lost its "Cascadia Code" fallback.) */


*,*::before,*::after { box-sizing: border-box; }
html { background: var(--bg-0); color: var(--snow-1); font-family: var(--font-body); scroll-behavior: smooth; }
body { margin: 0; line-height: 1.6; -webkit-font-smoothing: antialiased; overflow-x: hidden; }
/* Painted concept art is smooth; only the pixel-art sources get nearest-neighbour. */
img { max-width: 100%; display: block; }
h1,h2,h3,h4 { color: var(--snow-0); font-family: var(--font-display); font-weight: 400; line-height: 1.1; margin: 0 0 .5em; }
a { color: var(--ember-1); text-decoration: none; }
a:hover { color: var(--ember-0); text-decoration: underline; text-decoration-thickness: var(--px); text-underline-offset: var(--px); }
:focus-visible { outline: var(--px) solid var(--ember-0); outline-offset: var(--px); }
::selection { background: var(--ember-1); color: var(--bg-0); }
code { font-family: var(--font-mono); font-size: .875em; color: var(--ember-0); background: var(--bg-2); padding: .1em .35em; }

/* ---- Nav ------------------------------------------------------------- */
nav {
  position: sticky; top: 0; z-index: 10;
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  padding: 14px var(--gutter);
  background: rgba(11,13,17,.93);
  box-shadow: 0 var(--px) 0 0 var(--rock-1);
  font: 400 20px/1 var(--font-pixel); letter-spacing: .12em; text-transform: uppercase;
}
nav .brand { color: var(--snow-0); }
nav .links { display: flex; gap: 22px; flex-wrap: wrap; }
nav a { color: var(--snow-1); }
nav a[aria-current="page"] { color: var(--ember-1); }

/* ---- Layout ---------------------------------------------------------- */
.wrap { max-width: 68rem; margin: 0 auto; padding-inline: var(--gutter); }
.narrow { max-width: 48rem; }
section { padding-block: clamp(2.5rem,6vw,4.5rem); }
p { max-width: 64ch; }
.lede { font-size: 1.2rem; color: var(--snow-1); }
.muted { color: var(--snow-2); }

/* ---- Page masthead --------------------------------------------------- */
.masthead { padding-block: 0; }
.masthead .shot { position: relative; overflow: hidden; background: var(--bg-1); }
.masthead .shot img { width: 100%; height: clamp(220px,34vw,430px); object-fit: cover; opacity: .5; }
.masthead .shot::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(11,13,17,.3) 0%, rgba(11,13,17,.72) 55%, var(--bg-0) 100%);
}
.masthead .plate { position: relative; z-index: 1; margin-top: clamp(-170px,-17vw,-90px); padding-bottom: 1rem; }
.eyebrow { font: 400 18px/1 var(--font-pixel); letter-spacing: .28em; text-transform: uppercase; color: var(--ember-1); margin: 0 0 .75rem; }
.masthead h1 { font-size: clamp(44px,8vw,86px); margin: 0 0 .25em; text-shadow: var(--px) var(--px) 0 #000; }
.tagline { font-size: clamp(1.05rem,2.2vw,1.35rem); color: var(--snow-1); max-width: 56ch; }

/* ---- Tags / facts ---------------------------------------------------- */
.tags { display: flex; flex-wrap: wrap; gap: var(--px); list-style: none; margin: 1.25rem 0 0; padding: 0; }
.tags li {
  font: 400 16px/1 var(--font-pixel); letter-spacing: .1em; text-transform: uppercase;
  color: var(--snow-2); background: var(--bg-2); padding: 8px 12px 6px; clip-path: var(--notch);
}
.tags li.on { color: var(--bg-0); background: var(--ember-1); }

.facts { display: grid; grid-template-columns: repeat(auto-fit,minmax(150px,1fr)); gap: var(--px); margin: 2rem 0 0; }
.facts div { background: var(--bg-1); padding: 1rem 1.1rem; clip-path: var(--notch); }
.facts .k { font: 400 15px/1 var(--font-pixel); letter-spacing: .16em; text-transform: uppercase; color: var(--snow-3); }
.facts .v { font-family: var(--font-display); font-size: 2rem; color: var(--ember-1); line-height: 1.1; margin-top: .3rem; }
.facts .v small { font-family: var(--font-body); font-size: .8rem; color: var(--snow-2); display: block; letter-spacing: 0; }

/* ---- Cards ----------------------------------------------------------- */
.grid { display: grid; gap: calc(var(--px) * 4); }
.grid.two { grid-template-columns: repeat(auto-fit,minmax(min(100%,22rem),1fr)); }
.grid.three { grid-template-columns: repeat(auto-fit,minmax(min(100%,17rem),1fr)); }
.card { background: var(--bg-1); padding: 1.4rem 1.5rem; clip-path: var(--notch); }
.card h3 { font-size: 1.6rem; margin-bottom: .35em; }
.card p { font-size: .975rem; margin: 0; color: var(--snow-1); }
.card .k { font: 400 15px/1 var(--font-pixel); letter-spacing: .16em; text-transform: uppercase; color: var(--ember-1); display: block; margin-bottom: .6rem; }

a.work-card { display: block; background: var(--bg-1); clip-path: var(--notch); color: inherit; transition: background 100ms steps(2,end); }
a.work-card:hover { background: var(--bg-2); text-decoration: none; }
a.work-card:hover h3 { color: var(--ember-0); }
a.work-card img { width: 100%; aspect-ratio: 16/9; object-fit: cover; }
a.work-card .body { padding: 1.2rem 1.4rem 1.5rem; }
a.work-card h3 { font-size: 1.9rem; margin: 0 0 .2em; }
a.work-card p { font-size: .975rem; }

/* ---- Gallery --------------------------------------------------------- */
.gallery { display: grid; grid-template-columns: repeat(auto-fill,minmax(min(100%,190px),1fr)); gap: var(--px); margin-top: 1.5rem; }
.gallery figure { margin: 0; background: var(--bg-1); }
.gallery img { width: 100%; aspect-ratio: 2/1; object-fit: cover; }
.gallery.square img { aspect-ratio: 1/1; object-fit: contain; background: var(--bg-2); }
.gallery.tall { grid-template-columns: repeat(auto-fit,minmax(min(100%,210px),1fr)); }
.gallery.tall img { aspect-ratio: 3/4; object-fit: contain; object-position: bottom; padding: 14px 14px 0; background: var(--bg-1); }
.gallery figcaption { font: 400 15px/1.3 var(--font-pixel); letter-spacing: .1em; text-transform: uppercase; color: var(--snow-2); padding: 8px 10px 9px; }

.portraits { display: flex; flex-wrap: wrap; gap: var(--px); margin-top: 1.5rem; align-items: flex-end; }
.portraits img { width: 116px; height: 116px; object-fit: cover; background: var(--bg-1); }

/* ---- Mobs -------------------------------------------------------------
   Sprites off the project's own creature LoRA. A 1024 generation is taken back to the 16px grid
   the model actually paints on by a per-block majority vote (not a resample - edges drift, and
   point-sampling speckles), the backdrop is flood-filled out from the border rather than matched
   by colour, and the result is cropped to the creature. ~40x50 px, 11 KB for all five.
   Every width below is a whole multiple of the native size, so the grid never lands half a pixel. */
.mob-strip {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: center;
  gap: clamp(1rem,4vw,2.75rem); margin-top: 1.5rem;
  background: var(--bg-1); padding: 2.25rem 1.5rem 1.75rem; clip-path: var(--notch);
}
footer .mark { display: flex; align-items: center; gap: .9rem; }
/* The badge carries the name, so the footer no longer sets it as text. Sized by width rather
   than height: it is the STUDIO line that gives out first as this shrinks. The badge is drawn on
   a 260px grid and shown at 260 -- one to one, no resampling at all. It matches the hero
   wordmark's fineness so the two marks agree. The footer has no --art-px to borrow, so the badge
   carries its own grid and a fixed width can be exact. */
footer .mark .footmark { width: 260px; height: auto; display: block;
                         image-rendering: pixelated; }

/* ---- The paper doll ----------------------------------------------------
   assets/player/paperdoll.png exactly as the game reads it: one horizontal strip of
   24 turn frames, 46x110 each. The element is ONE FRAME wide with the whole strip as
   its background, so sliding the background by the strip's width in steps(24) IS the
   animation - no canvas, no script, no second asset.

   It idles PAUSED and runs on hover or focus. Pausing freezes the current frame, so he
   stops facing wherever he got to rather than snapping back to the front - which is the
   whole point of pausing instead of cancelling.

   2.16s is the sheet's own timing: paperdoll.sheet.json says wait 0.09 x 24 frames. */
.doll-block {
  display: grid; grid-template-columns: auto 1fr; gap: clamp(1.5rem,5vw,3rem);
  align-items: center; background: var(--bg-1); clip-path: var(--notch);
  padding: clamp(1.5rem,4vw,2.5rem);
}
.doll-stage {
  background: var(--bg-2); padding: 18px 22px;
  box-shadow: inset 0 0 0 var(--px) var(--rock-1);
}
.doll {
  --s: 3;                                   /* whole multiples only - never a half pixel */
  --frames: 24;
  width: calc(46px * var(--s));
  height: calc(110px * var(--s));
  background: url("../media/notnoita/paperdoll.png") 0 0 no-repeat;
  background-size: calc(46px * var(--frames) * var(--s)) calc(110px * var(--s));
  image-rendering: pixelated;
  animation: doll-turn 2.16s steps(var(--frames)) infinite;
  animation-play-state: paused;
  cursor: ew-resize;
}
.doll:hover, .doll:focus-visible, .doll:active { animation-play-state: running; }
@keyframes doll-turn { to { background-position-x: calc(-46px * var(--frames) * var(--s)); } }
.doll-hint { font: 400 15px/1 var(--font-pixel); letter-spacing: .16em; text-transform: uppercase;
  color: var(--snow-3); margin: .9rem 0 0; text-align: center; }
@media (max-width: 640px) {
  .doll-block { grid-template-columns: 1fr; justify-items: center; text-align: left; }
  .doll { --s: 2; }
}

/* ---- Playlist ---------------------------------------------------------
   One row per track. The art is the game's OWN per-track thumbnail, an SVG built from the
   palette that song derives - so the tile is a miniature of the level the track generates.

   They stay <img src> rather than being inlined: all 33 files reuse the same five element
   ids (sky, sunGlow, grass, road-surface, roadShade), so inlining them into one document
   would make every thumbnail render with the first one's gradients. As separate documents
   each id stays scoped, and the browser caches them. */
.playlist { list-style: none; margin: 1.75rem 0 0; padding: 0; }
.track {
  display: grid; align-items: center; gap: 0 1rem;
  grid-template-columns: 2.4rem 108px minmax(0,1fr) auto 92px;
  padding: .5rem .75rem; background: var(--bg-1);
}
.track + .track { box-shadow: inset 0 var(--px) 0 0 var(--bg-0); }
.track:hover { background: var(--bg-2); }
.track .no { font: 400 17px/1 var(--font-pixel); letter-spacing: .1em; color: var(--snow-3); }

/* The row is the play button. The number swaps for a play/pause glyph on hover and while
   playing, so nothing extra has to sit in the layout. */
.track { cursor: pointer; position: relative; }
.track .no::before { content: "B6"; display: none; font-size: .85em; color: var(--ember-1); }
.track:hover .no i, .track[data-state] .no i { display: none; }
.track:hover .no::before, .track[data-state] .no::before { display: inline; }
.track[data-state="playing"] .no::before { content: "½A½A"; letter-spacing: -.12em; }
.track[data-state] { background: var(--bg-2); }
.track[data-state] .meta b { color: var(--ember-0); }
.track[data-state] .art { opacity: 1; outline: var(--px) solid var(--ember-3); outline-offset: calc(-1 * var(--px)); }

/* Playback progress: a hairline along the bottom edge of the active row. */
.track .bar { position: absolute; left: 0; bottom: 0; height: var(--px); width: 0;
  background: var(--ember-1); pointer-events: none; }
.track .art { width: 108px; height: 68px; object-fit: cover; background: var(--bg-2); display: block; }
.track .meta { min-width: 0; }
.track .meta b { display: block; font-family: var(--font-display); font-weight: 400;
  font-size: 1.35rem; line-height: 1.15; color: var(--snow-0); }
.track .sub { display: block; font-size: .8rem; color: var(--snow-3); overflow-wrap: anywhere; }
.track .dur { font-family: var(--font-mono); font-size: .8rem; color: var(--snow-2); }

/* Difficulty is the pipeline's own baked 0-100 score. The rail is a fixed 56px grid column, so
   the inline width percentage reads as a real proportion instead of being clamped. */
.track .diff { display: grid; grid-template-columns: 56px auto; align-items: center; gap: .6rem; }
.track .diff i { display: block; height: 6px; background: var(--pine-0); }
.track .diff.mid  i { background: var(--ember-1); }
.track .diff.hard i { background: var(--danger); }
.track .diff em { font: 400 15px/1 var(--font-pixel); font-style: normal; color: var(--snow-2); }

/* locked: the campaign opens with five, each later track unlocks the one before it on Easy */
.track[data-locked] .no::after { content: " F512"; font-size: .7em; opacity: .5; }
.track[data-locked] .art { opacity: .78; }

/* Sticky transport, only once something has been played. */
.nowplaying {
  position: sticky; bottom: 0; z-index: 5; display: none;
  align-items: center; gap: 1rem; padding: .75rem 1rem;
  background: var(--bg-2); box-shadow: 0 calc(-1 * var(--px)) 0 0 var(--ember-3);
}
.nowplaying[data-on] { display: flex; }
.nowplaying img { width: 64px; height: 40px; object-fit: cover; flex: none; }
.nowplaying .what { min-width: 0; flex: 1; }
.nowplaying .what b { display: block; font-family: var(--font-display); font-weight: 400;
  font-size: 1.15rem; color: var(--snow-0); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nowplaying .what span { font-family: var(--font-mono); font-size: .75rem; color: var(--snow-3); }
.nowplaying button {
  font: 400 18px/1 var(--font-pixel); letter-spacing: .06em; text-transform: uppercase;
  background: var(--ember-1); color: var(--bg-0); border: 0; padding: 11px 16px 9px;
  clip-path: var(--notch); cursor: pointer; flex: none;
}
.nowplaying button:hover { background: var(--ember-0); }
.nowplaying button.ghost { background: transparent; color: var(--snow-1); box-shadow: var(--pixel-border); }
.nowplaying button.ghost:hover { background: var(--bg-3); color: var(--ember-0); }
@media (max-width: 560px) { .nowplaying .what span { display: none; } }

/* Volume. The range is styled by hand because the default control has rounded everything, and
   the amber fill left of the thumb is a gradient stop driven from --f (set in the input handler)
   rather than a second element. */
.nowplaying .vol { display: flex; align-items: center; gap: .5rem; flex: none; }
.nowplaying .vol button { padding: 10px 11px 8px; font-size: 15px; line-height: 1; }
#np-vol {
  -webkit-appearance: none; appearance: none;
  width: 92px; height: 18px; background: transparent; cursor: pointer;
}
#np-vol:focus-visible { outline: var(--px) solid var(--ember-0); outline-offset: var(--px); }
#np-vol::-webkit-slider-runnable-track {
  height: var(--px); border: 0;
  background: linear-gradient(90deg, var(--ember-1) var(--f, 80%), var(--rock-2) var(--f, 80%));
}
#np-vol::-moz-range-track {
  height: var(--px); border: 0;
  background: linear-gradient(90deg, var(--ember-1) var(--f, 80%), var(--rock-2) var(--f, 80%));
}
#np-vol::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 9px; height: 15px; margin-top: -6px; border: 0; border-radius: 0;
  background: var(--snow-0);
}
#np-vol::-moz-range-thumb {
  width: 9px; height: 15px; border: 0; border-radius: 0; background: var(--snow-0);
}
#np-vol:hover::-webkit-slider-thumb { background: var(--ember-0); }
#np-vol:hover::-moz-range-thumb { background: var(--ember-0); }
.nowplaying[data-muted] #np-vol::-webkit-slider-runnable-track { background: var(--rock-2); }
.nowplaying[data-muted] #np-vol::-moz-range-track { background: var(--rock-2); }
.nowplaying[data-muted] #np-vol::-webkit-slider-thumb { background: var(--snow-3); }
.nowplaying[data-muted] #np-vol::-moz-range-thumb { background: var(--snow-3); }

/* Narrow: the slider is the first thing to go - the transport buttons matter more, and a
   phone has hardware volume anyway. */
@media (max-width: 720px) { #np-vol { display: none; } }


.playlist-foot { display: flex; flex-wrap: wrap; gap: .5rem 1.5rem; justify-content: space-between;
  font: 400 16px/1.4 var(--font-pixel); letter-spacing: .12em; text-transform: uppercase;
  color: var(--snow-3); padding: .9rem .75rem 0; }

@media (max-width: 720px) {
  .track { grid-template-columns: 2.2rem 76px minmax(0,1fr) auto; gap: 0 .75rem; }
  .track .art { width: 76px; height: 48px; }
  .track .diff { display: none; }
  .track .meta b { font-size: 1.15rem; }
}

/* ---- Prose ----------------------------------------------------------- */
.prose h2 { font-size: clamp(30px,4.5vw,44px); margin-top: 2.75rem; }
.prose h3 { font-size: 1.5rem; margin-top: 2rem; color: var(--snow-0); }
.prose ul { padding-left: 1.2rem; max-width: 64ch; }
.prose li { margin-bottom: .5rem; }
.prose blockquote {
  margin: 1.5rem 0; padding: .3rem 0 .3rem 1.4rem; max-width: 64ch;
  box-shadow: inset var(--px) 0 0 0 var(--ember-3); color: var(--snow-1);
}
.prose blockquote p { margin: .4rem 0; }
.prose blockquote cite { display: block; font-style: normal; font-size: .8rem; color: var(--snow-3);
  font-family: var(--font-mono); margin-top: .5rem; overflow-wrap: anywhere; }

/* ---- Devlog ---------------------------------------------------------- */
.entry { padding-block: 2.5rem; }
.entry + .entry { box-shadow: 0 calc(-1 * var(--px)) 0 0 var(--rock-1); }
.entry .date { font: 400 17px/1 var(--font-pixel); letter-spacing: .2em; text-transform: uppercase; color: var(--ember-1); }
.entry h2 { font-size: clamp(28px,4vw,40px); margin: .4rem 0 .8rem; }
.entry .commit {
  font-family: var(--font-mono); font-size: .8rem; line-height: 1.55; color: var(--snow-2);
  background: var(--bg-1); padding: .9rem 1.1rem; margin: 1.25rem 0; max-width: 64ch;
  border-left: var(--px) solid var(--rock-3); overflow-wrap: anywhere;
}
.entry .commit b { color: var(--ember-0); font-weight: 400; }

/* ---- Commit-frequency bars ------------------------------------------- */
.spark { display: flex; align-items: flex-end; gap: 2px; height: 96px; margin: 1.75rem 0 .4rem;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; }
.spark i { flex: 1 1 0; min-width: 3px; background: var(--rock-2); display: block; }
/* A long history packs many more bars; let them go thinner before the row has to scroll. */
.spark.dense { gap: 1px; }
.spark.dense i { min-width: 2px; }
.spark i.warm { background: var(--ember-3); }
.spark i.hot { background: var(--ember-1); }
.spark-key { font: 400 15px/1 var(--font-pixel); letter-spacing: .12em; text-transform: uppercase; color: var(--snow-3); display: flex; justify-content: space-between; gap: 1rem; }

/* ---- Buttons / footer ------------------------------------------------ */
.btn.ghost { background: transparent; color: var(--snow-1); box-shadow: var(--pixel-border); }
.btn.ghost:hover { background: var(--bg-2); color: var(--ember-0); }
.btn-row { display: flex; flex-wrap: wrap; gap: var(--px); align-items: center; }

footer { padding: 3rem var(--gutter) 0 var(--gutter); box-shadow: 0 calc(-1*var(--px)) 0 0 var(--rock-1); margin-top: 3rem; }
footer .bar { max-width: 68rem; margin: 0 auto; display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between; align-items: center; }
footer, footer a { font: 400 18px/1.4 var(--font-pixel); letter-spacing: .12em; text-transform: uppercase; color: var(--snow-3); }
footer a { color: var(--snow-2); }

hr { border: 0; height: calc(var(--px) * 2); margin: 3rem 0;
  background: repeating-conic-gradient(var(--rock-1) 0 25%, transparent 0 50%) 0 0 / calc(var(--px)*2) calc(var(--px)*2); }

.note { background: var(--bg-1); padding: 1.1rem 1.3rem; clip-path: var(--notch); font-size: .95rem; color: var(--snow-2); margin: 2rem 0; max-width: 64ch; }
.note b { color: var(--snow-0); font-weight: 500; }

table { border-collapse: collapse; width: 100%; font-size: .95rem; margin-top: 1.25rem; }
th, td { text-align: left; padding: .55rem .8rem; box-shadow: 0 var(--px) 0 0 var(--bg-2); }
th { font: 400 16px/1 var(--font-pixel); letter-spacing: .12em; text-transform: uppercase; color: var(--snow-3); }
td:first-child { color: var(--snow-0); }
.scroll-x { overflow-x: auto; }

@media (max-width: 560px) {
  nav { font-size: 16px; }
  nav .links { gap: 14px; }
  .masthead .plate { margin-top: -72px; }
  .spark { height: 70px; }
}
