
:root{
  /* The site commits to dark: screenshots are the content and a bright ground
     competes with them. Declaring color-scheme makes that a decision rather than
     an omission -- without it the <select> and the scrollbars still render in the
     OS light theme against this palette. */
  color-scheme: dark;
  --bg:#0d0f13; --surface:#15181e; --surface-2:#1d212a; --border:#282d38;
  --border-2:#3a4150; --text:#e6e9ef; --text-2:#b8bfcc; --muted:#8b94a4;
  --accent:#5b8cff; --accent-dim:#16233f;
  /* The one destructive-looking control on the page. Pulled toward the logo's
     red but lifted off it, because #ee1b24 itself reads at 4.08:1 on a card. */
  --danger:#ff6b5a; --danger-dim:#2d1612;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  margin:0; background:var(--bg); color:var(--text);
  font-family:Archivo,"Helvetica Neue",Arial,sans-serif; font-size:16px; line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
a{color:var(--accent); text-underline-offset:2px}
a:focus-visible,button:focus-visible{outline:2px solid var(--accent); outline-offset:3px; border-radius:3px}
img{max-width:100%; height:auto; display:block}
/* The one place !important earns its keep. `hidden` is a plain attribute and the
   UA rule behind it is just [hidden]{display:none}, so any class on the same
   element that sets display beats it on source order and the element stays on
   screen with its attribute dutifully set. That is what kept the timeline legend
   visible -- and stale -- after a search narrowed to a single contributor. */
[hidden]{display:none !important}

.top{
  display:flex; align-items:center; justify-content:space-between; gap:20px;
  padding:16px 28px; border-bottom:1px solid var(--border);
  position:sticky; top:0; background:rgba(13,15,19,.92); backdrop-filter:blur(8px); z-index:20;
}
/* On a phone the header (logo row and a full-width search bar) is ~125px of an
   ~800px screen. It slides away while scrolling down and returns on the way up
   (base.html); sticky month headings follow it through --topH. */
.top{transition:transform .2s ease}
.top.tucked{transform:translateY(-100%)}
.brand{display:block; text-decoration:none; line-height:0}
/* The logo's blue sits at 2.2:1 on this ground, under the readable threshold.
   A faint light halo lifts it without altering the artwork itself. */
.brand img{height:40px; width:auto; filter:drop-shadow(0 0 1.5px rgba(255,255,255,.45))}
.top nav{display:flex; gap:20px; font-size:.92rem; flex:none}

/* ---- search ---- */
.search{position:relative; flex:1 1 420px; max-width:480px; min-width:150px}
.search input{
  width:100%; background:var(--surface); color:var(--text); font:inherit; font-size:.92rem;
  border:1px solid var(--border); border-radius:6px; padding:8px 38px 8px 12px;
}
.search input::placeholder{color:var(--muted)}
.search input:focus{outline:none; border-color:var(--accent); background:var(--surface-2)}
.search input::-webkit-search-cancel-button{display:none}
/* The whole right end of the field is the target, not the glyph: 21x19px was
   under the 24px minimum. */
#qclear{
  position:absolute; right:0; top:0; bottom:0; width:38px; background:none;
  border:0; color:var(--muted); font-size:19px; line-height:1; cursor:pointer; padding:0;
}
#qclear:hover{color:var(--text)}
.sugg{
  position:absolute; left:0; right:0; top:calc(100% + 6px); background:var(--surface);
  border:1px solid var(--border-2); border-radius:6px; z-index:40;
  box-shadow:0 10px 34px rgba(0,0,0,.5);
  max-height:min(60vh,420px); overflow-y:auto; overscroll-behavior:contain;
}
/* Sticky: the panel scrolls through every match now, and a group heading that
   scrolls away leaves you reading a list of unlabelled values. */
.sugg b{
  display:block; padding:5px 12px; background:var(--surface-2); color:var(--muted);
  font-size:12.5px; letter-spacing:.06em;
  text-transform:uppercase; font-weight:600;
  position:sticky; top:0; z-index:1;
}
.sugg button{
  display:flex; width:100%; gap:10px; align-items:baseline; justify-content:space-between;
  background:none; border:0; color:var(--text-2); font:inherit; font-size:.88rem;
  padding:7px 12px; text-align:left; cursor:pointer;
}
.sugg button:hover,.sugg button[aria-selected="true"]{background:var(--accent-dim); color:var(--text)}
.sugg button i{font-style:normal; color:var(--muted); font-family:"JetBrains Mono",monospace; font-size:12px}
.sugg .none{padding:9px 12px; color:var(--muted); font-size:.86rem}

.toolbar{display:flex; gap:14px 20px; align-items:center; justify-content:space-between;
  flex-wrap:wrap; margin:0 0 16px}
.toolbar .controls{display:flex; gap:14px 18px; align-items:center; flex-wrap:wrap}
.chips{display:flex; flex-wrap:wrap; gap:7px; align-items:center; min-height:1px}
.pagesize{display:flex; align-items:center; gap:8px; color:var(--muted);
  font-size:13.5px; white-space:nowrap}
.pagesize select{
  background:var(--surface); color:var(--text); border:1px solid var(--border);
  border-radius:5px; padding:5px 8px; font:inherit; font-size:13.5px; cursor:pointer;
}
.pagesize select:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.more{display:flex; justify-content:center; padding:4px 0 70px}
#loadmore{
  background:var(--surface); border:1px solid var(--border-2); color:var(--text);
  font:inherit; font-size:14px; padding:11px 26px; border-radius:6px; cursor:pointer;
}
#loadmore:hover{border-color:var(--accent); color:var(--accent); background:var(--accent-dim)}
.chip{
  display:inline-flex; gap:7px; align-items:center; background:var(--accent-dim);
  color:var(--accent); border-radius:14px; padding:2px 2px 2px 11px;
  font-family:"JetBrains Mono",monospace; font-size:13px;
}
/* 24px square at least (WCAG 2.2 target size); the glyph alone was 14px. */
.chip button{background:none; border:0; color:inherit; cursor:pointer; font-size:15px; line-height:1;
  min-width:24px; min-height:24px; border-radius:50%; padding:0}
.chip button:hover{color:var(--text); background:rgba(91,140,255,.18)}
.chipclear{background:none; border:0; color:var(--accent); font:inherit; font-size:13.5px;
  cursor:pointer; padding:4px 6px; text-decoration:underline; text-underline-offset:2px}
.chips .count{color:var(--muted); font-size:13.5px}
.top nav a{color:var(--text-2); text-decoration:none}
.top nav a:hover{color:var(--accent)}

.wrap{max-width:1500px; margin:0 auto; padding:0 28px}
.prose{max-width:66ch}
h1{font-size:clamp(1.9rem,4vw,2.9rem); line-height:1.05; letter-spacing:-.025em; margin:0 0 14px; text-wrap:balance}
h2{font-size:1.3rem; letter-spacing:-.015em; margin:36px 0 10px; text-wrap:balance}
h3{font-size:1rem; margin:28px 0 8px}
p{margin:0 0 1em}
.intro{padding:46px 0 26px}
.intro p{color:var(--text-2); max-width:58ch; font-size:1.08rem}
.pilot{
  display:inline-block; font-size:13px; font-weight:600;
  letter-spacing:.06em; text-transform:uppercase; color:var(--accent); text-decoration:none;
  background:var(--accent-dim); border:1px solid transparent; border-radius:3px; padding:4px 10px; margin-bottom:16px;
}
.pilot:hover{border-color:var(--accent)}
/* Results first: on the home page a search hides the welcome above them (browse.js). */
body.filtering .intro,body.filtering .contribute,body.filtering .highlights{display:none}
.reshead{font-size:clamp(1.4rem,3vw,1.9rem); margin:30px 0 18px; overflow-wrap:anywhere}

/* ---- contribute ---- */
/* Sits between the intro and the timeline, where someone who has just read what
   this is finds out they can add to it. Surface rather than accent: it is an
   invitation, not the point of the page. */
.contribute{
  background:var(--surface); border:1px solid var(--border); border-left:3px solid var(--accent);
  border-radius:6px; padding:17px 22px; margin:0 0 26px;
}
.contribute{position:relative}
.contribute .dismiss{position:absolute; top:4px; right:4px; background:none; border:0;
  color:var(--muted); font-size:22px; line-height:1; width:40px; height:40px; cursor:pointer}
.contribute .dismiss:hover{color:var(--text)}
.contribute p{margin:0; color:var(--text-2); max-width:64ch}
.contribute b{color:var(--text); font-weight:600}
.contribute-ways{display:flex; flex-wrap:wrap; align-items:center; gap:10px 14px; margin-top:14px !important}
.contribute-ways .or{color:var(--muted); font-size:.93rem}
/* "or write to <address>" is one phrase: it wraps as a sentence, not as two pieces. */
.contribute-ways a:not(.dl){color:var(--accent)}

/* ---- timeline ---- */
.tl{background:var(--surface); border:1px solid var(--border); border-radius:6px; padding:18px 20px 12px; margin:0 0 26px}
.tlhead{display:flex; justify-content:space-between; align-items:baseline; gap:16px; margin-bottom:12px; flex-wrap:wrap}
.tlhead h2{margin:0; font-size:.95rem; font-weight:600}
.tlstat{font-size:13.5px; color:var(--muted); font-variant-numeric:tabular-nums}
/* 180 monthly bars at 3px plus 2px gaps need ~900px. On a phone that overflowed
   the card and scrolled the whole page sideways, so the bars thin out instead;
   overflow-x is a safety net for when the archive outgrows even that. */
.tlbars{display:flex; align-items:flex-end; gap:2px; height:84px; cursor:crosshair;
  user-select:none; touch-action:pan-y; overflow-x:auto; overscroll-behavior-x:contain}
.tlb{flex:1 1 0; min-width:3px; background:var(--border-2); border-radius:2px 2px 0 0;
  min-height:3px; transition:opacity .12s, background .12s}
.tlb.has{background:var(--accent)}
/* The keyboard cursor. It rides the bar itself rather than a full-height
   column, so an empty month still shows a 4px marker where the walk is. */
.tlb{position:relative}
.tlb.cur::after{content:""; position:absolute; inset:0; border-radius:2px;
  outline:1.5px solid var(--text); outline-offset:1px; pointer-events:none}
.tlbars:focus{outline:none}
.tlbars:focus-visible{outline:2px solid var(--accent); outline-offset:4px; border-radius:3px}
/* Dimming is its own class rather than riding on .has, so a selection reads the
   same whether the bar is one colour or a stack of contributor bands. */
.tlb.dim{opacity:.22}
.tlb.empty{background:var(--border); min-height:2px}
.tlb.split{display:flex; flex-direction:column-reverse; overflow:hidden; background:var(--border)}
/* The segments must not swallow pointer events, or dragging a range over a
   stacked bar never finds the bar underneath it. */
.tlb.split i{display:block; width:100%; pointer-events:none}
.tlhint{color:var(--muted); font-size:13px}
.tllegend{display:flex; flex-wrap:wrap; gap:5px 16px; margin:10px 0 0;
  font-family:"JetBrains Mono",monospace; font-size:13px; color:var(--text-2)}
.tllegend span,.tllegend a{display:flex; align-items:center; gap:6px}
.tllegend a{color:var(--text-2); text-decoration:none; min-height:24px}
.tllegend a:hover{color:var(--accent)}
.tllegend b{width:9px; height:9px; border-radius:2px; flex:none}
.tlmore{display:none; background:none; border:0; color:var(--accent); font:inherit;
  font-size:13.5px; padding:8px 0 4px; cursor:pointer}
/* One cell per month, mirroring the bars above it. */
.tlyears{display:flex; gap:2px; margin-top:7px; height:15px;
  font-family:"JetBrains Mono",monospace; font-size:12.5px; color:var(--muted);
  font-variant-numeric:tabular-nums}
.ty{flex:1 1 0; min-width:3px; position:relative}
.tlyears{position:relative}
/* Year labels, placed by years.js: centred on the months each year covers. */
.tylabels{position:absolute; inset:0; pointer-events:none}
.tylabels i{position:absolute; top:0; left:0; font-style:normal; white-space:nowrap}
/* The year line is drawn from the ruler cell rather than from the January bar.
   A stacked bar sets overflow:hidden to clip its colour bands to its rounded
   top, and that clipped the line away too -- so it vanished in exactly the busy
   stretches where knowing the year matters most, which read as the lines
   disappearing whenever the bars got dense. The ruler clips nothing, and from
   there the line rules over the bars instead of hiding in the gap between them.
   84px is the height of .tlbars and 7px its distance from this row. */
.ty.jan::after{content:""; position:absolute; left:-2px; bottom:calc(100% + 7px);
  width:2px; height:84px; background:rgba(230,233,239,.16); pointer-events:none}
/* The same boundary again as a tick on the rule itself. */
.ty.jan::before{content:""; position:absolute; left:-2px; top:0; width:2px;
  height:4px; background:var(--border-2)}
.tlclear{background:none; border:1px solid var(--danger); color:var(--danger); font:inherit; font-size:13px;
  padding:3px 10px; border-radius:4px; cursor:pointer}
.tlclear:hover{background:var(--danger-dim); border-color:var(--danger); color:#ff8a7a}

/* ---- grid ---- */
/* A full-width flex item, so it breaks the justified row cleanly, and sticky
   under the site header so you always know which month you are looking at
   however far down you have scrolled. */
.gridhead{
  flex:1 0 100%; position:sticky; top:var(--topH,73px); z-index:6; margin:20px 0 0; padding:8px 2px 9px;
  /* Solid: a fade let the tops of the screenshots show through the label. */
  background:var(--bg); border-bottom:1px solid var(--border);
  font-size:14px; font-weight:600; letter-spacing:.01em; color:var(--text-2);
}
.gridhead:first-child{margin-top:0}

.actions{display:flex; flex-wrap:wrap; gap:10px; align-items:center}
/* A <button> styled as .dl starts from the browser's own button look. */
button.dl{background:none; font:inherit; font-size:13.5px; cursor:pointer}
.dl.ghost{background:none; border:1px solid var(--border-2); color:var(--text-2);
  font:inherit; font-size:14px; cursor:pointer}
.dl.ghost:hover{border-color:var(--accent); color:var(--accent); background:var(--accent-dim)}
.dl.ghost.done{border-color:var(--go); color:var(--go); background:var(--go-dim)}
/* Justified rows, not a fixed grid. 93% of the archive is not 16:9 -- windowed
   Minecraft loses height to the title bar, giving ratios from 1.60 to 1.94 --
   so a 16:9 box with object-fit:cover was shaving the left and right edges off
   almost every screenshot, which is where the F3 column and chat live.

   Each cell carries its own --ar. flex-basis scales with it so wider images
   claim more of the row, and aspect-ratio derives the height, so everything in
   a row lands on the same height with nothing cropped. The ::after filler stops
   a short final row from stretching to full width. */
.grid{display:flex; flex-wrap:wrap; gap:10px; align-content:flex-start}
.grid::after{content:""; flex-grow:1e6}
/* The same filler, once per month group, closing each group's last row. Without
   one, a sparse month stretches its images across the full width. */
.gridfill{flex:1e6 0 0; height:0; min-width:0}
.cell{position:relative; display:block; background:var(--surface); border-radius:5px;
  overflow:hidden; border:1px solid var(--border); text-decoration:none;
  flex:var(--ar) 1 calc(var(--ar) * 155px); aspect-ratio:var(--ar); min-width:150px}
.cell img{
  width:100%; height:100%; object-fit:cover; background:var(--surface-2);
  color:transparent; font-size:0; transition:transform .35s ease, opacity .3s;
}
/* The cell now matches the image's own ratio, so cover crops nothing; it is kept
   only to absorb sub-pixel rounding in the aspect-ratio arithmetic. */
.shot img{width:100%; height:auto}
.cell:hover img{transform:scale(1.035)}
.cell figcaption{
  position:absolute; left:0; right:0; bottom:0; padding:16px 10px 7px;
  background:linear-gradient(transparent,rgba(6,8,11,.88));
  font-family:"JetBrains Mono",monospace; font-size:12.5px; color:#d7dce6;
  opacity:0; transition:opacity .18s;
}
.cell:hover figcaption,.cell:focus-visible figcaption{opacity:1}
.empty-note{color:var(--muted); padding:40px 0}

/* ---- detail ---- */
/* The screenshot is what the page is for, so it gets the width. Metadata sits
   below it rather than beside it: a 300px sidebar was costing the image a third
   of the viewport on every view. */
.detail{padding:16px 0 70px}
.detailbar{display:flex; justify-content:space-between; align-items:center; gap:10px 18px;
  margin:0 0 12px; flex-wrap:wrap}
.detailbar .pos{flex:1; color:var(--muted); font-size:13.5px}
/* fit-content so the frame hugs the screenshot. A fixed-width card left a
   854px original floating in half a metre of empty surface. */
.shot{margin:0 auto; background:var(--surface); border:1px solid var(--border);
  border-radius:6px; overflow:hidden; display:flex; justify-content:center;
  align-items:center; width:fit-content; max-width:100%}
.shot img{width:auto; max-width:100%; height:auto; max-height:calc(100vh - 215px)}
.detail h1{font-size:1.35rem; letter-spacing:-.01em; margin:22px 0 14px}
dl.meta{display:grid; grid-template-columns:repeat(auto-fit,minmax(185px,1fr));
  gap:15px 24px; margin:0 0 22px; font-family:"JetBrains Mono",monospace; font-size:12.5px}
dl.meta > div{min-width:0}
dl.meta dt{color:var(--muted); margin-bottom:3px}
dl.meta dd{margin:0; color:var(--text-2); word-break:break-word}
/* The same weight as Earlier / Later beside it: Back is as much a way out. */
.back{display:inline-block; padding:7px 16px; border:1px solid var(--border-2); border-radius:5px;
  font-size:13px; text-decoration:none; color:var(--text-2)}
.back:hover{border-color:var(--accent); color:var(--accent)}
.nav2{display:flex; gap:8px}
.nav2 a,.nav2 span{padding:7px 16px; border:1px solid var(--border-2); border-radius:5px;
  font-size:13px; text-decoration:none; color:var(--text-2)}
.nav2 a:hover{border-color:var(--accent); color:var(--accent)}
.nav2 span{opacity:.3}
.dl{display:inline-block; padding:9px 15px; border:1px solid var(--accent); color:var(--accent);
  border-radius:5px; text-decoration:none; font-size:13.5px}
.dl:hover{background:var(--accent-dim)}

/* ---- statistics ---- */
.card{background:var(--surface); border:1px solid var(--border); border-radius:6px;
  padding:22px 24px 18px; margin:0 0 22px}
.card > h2{margin:0 0 4px; font-size:1.05rem}
.card > p.note{margin:0 0 18px; color:var(--muted); font-size:13.5px; max-width:68ch}
.stack-wrap{overflow-x:auto}
.stackbars{display:flex; align-items:flex-end; gap:2px; height:190px; min-width:640px}
.sb{flex:1 1 0; min-width:3px; display:flex; flex-direction:column-reverse; border-radius:2px 2px 0 0;
  overflow:hidden; background:var(--border); min-height:2px}
.sb i{display:block; width:100%}
.axis{display:flex; justify-content:space-between; margin-top:9px; padding-top:8px;
  border-top:1px solid var(--border); font-family:"JetBrains Mono",monospace;
  font-size:12.5px; color:var(--muted)}
/* Only the stacked chart's axis needs the floor, and only to stay in step with
   .stackbars. Applied to every .axis it dragged other charts' axes
   out to 640px and took the whole page sideways with it. */
.stack-wrap .axis{min-width:640px}
.legend{display:flex; flex-wrap:wrap; gap:4px 8px; margin:18px 0 0;
  font-family:"JetBrains Mono",monospace; font-size:13px}
.legend button{display:flex; align-items:center; gap:7px; color:var(--text-2); background:none;
  border:1px solid transparent; border-radius:4px; font:inherit; padding:4px 8px; cursor:pointer; min-height:30px}
.legend button:hover,.legend button.on{border-color:var(--border-2); color:var(--text)}
.legend button[aria-pressed="true"]{border-color:var(--accent)}
/* One contributor lit, the rest dimmed (stats.js). */
.spot [data-c]{opacity:.12; transition:opacity .12s}
.spot [data-c].on{opacity:1}
.legend b{width:11px; height:11px; border-radius:2px; flex:none}
.legend i{color:var(--muted); font-style:normal}
.two{display:grid; grid-template-columns:minmax(0,320px) minmax(0,1fr); gap:30px; align-items:center}
.pie-rows{display:grid; gap:7px; font-family:"JetBrains Mono",monospace; font-size:13px}
.pie-row{display:grid; grid-template-columns:11px 1fr auto auto; gap:11px; align-items:center}
.pie-row b{width:11px; height:11px; border-radius:2px}
.pie-row u{text-decoration:none; color:var(--text-2)}
.pie-row em{font-style:normal; color:var(--muted); font-variant-numeric:tabular-nums}
.pie-row s{text-decoration:none; color:var(--text); font-variant-numeric:tabular-nums}
.span-wrap{overflow-x:auto}
.spans{display:grid; gap:9px}
.span-row{display:grid; grid-template-columns:130px 1fr; gap:14px; align-items:center;
  font-family:"JetBrains Mono",monospace; font-size:13px}
.span-row > span{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
/* The chart fits the screen rather than scrolling sideways: the names give up
   width first, and the year labels shorten themselves to suit (stats.js). */
@media (max-width:600px){
  .span-row{grid-template-columns:92px 1fr; gap:8px; font-size:12px}
}
.span-track{position:relative; height:15px; background:var(--surface-2); border-radius:3px}
.span-bar{position:absolute; top:0; bottom:0; border-radius:3px; opacity:.9}
/* Year rule. The axis named only the first and last month, which left every
   bar's actual years to be guessed off its pixel position. */
.span-track i{position:absolute; top:0; bottom:0; width:1px; background:var(--border);
  pointer-events:none}
/* The rule heads the chart: you read the years first, then the bars under them.
   So the labels sit above their own line and the ticks hang off its underside,
   pointing down into the tracks they measure. */
.span-row.span-rule{margin-bottom:7px; align-items:end}
.span-ticks{position:relative; height:17px; border-bottom:1px solid var(--border);
  font-family:"JetBrains Mono",monospace; font-size:12.5px; color:var(--muted);
  font-variant-numeric:tabular-nums}
.span-ticks i{position:absolute; top:0; left:0; font-style:normal; white-space:nowrap}
.span-ticks u{position:absolute; bottom:0; width:1px; height:4px; background:var(--border-2);
  text-decoration:none}
.year-wrap{overflow-x:auto}
.yearbars{display:flex; align-items:stretch; gap:6px; height:130px; min-width:620px}
/* stretch, not flex-end: each column needs a definite height for its bar's
   percentage height to resolve against, or the bar collapses to nothing. */
.yearbars > div{flex:1; display:flex; flex-direction:column; justify-content:flex-end; gap:6px}
.yearbars u{display:block; background:var(--accent); border-radius:2px 2px 0 0; text-decoration:none}
.yearlabels{display:flex; gap:6px; margin-top:8px; min-width:620px;
  font-family:"JetBrains Mono",monospace; font-size:12.5px; color:var(--muted)}
.yearlabels > div{flex:1; text-align:center}
.yearlabels s{display:block; text-decoration:none; color:var(--text-2);
  font-variant-numeric:tabular-nums}
.caption{margin:-2px 0 14px; color:var(--text-2); max-width:70ch}
.tagrow{display:flex; flex-wrap:wrap; gap:7px; margin:0 0 20px}
.tag{display:inline-flex; align-items:center; background:var(--surface-2);
  border:1px solid var(--border); color:var(--text-2); text-decoration:none;
  border-radius:13px; padding:3px 11px; font-family:"JetBrains Mono",monospace; font-size:13px}
.tag:hover{border-color:var(--accent); color:var(--accent); background:var(--accent-dim)}
/* A collection is a curated set rather than a label, so it reads as one. */
.tag.coll{border-style:dashed}

/* ---- contributor x year heatmap ---- */
.heat-wrap{overflow-x:auto}
.heat{display:grid; grid-template-columns:132px repeat(var(--yrs,16),minmax(42px,1fr));
  gap:2px; min-width:760px; font-family:"JetBrains Mono",monospace;
  font-variant-numeric:tabular-nums}
.heat b{font-size:12px; font-weight:500; color:var(--muted); text-align:center;
  padding-bottom:3px}
.heat u{display:flex; align-items:center; text-decoration:none; font-size:12.5px;
  color:var(--text-2); padding-right:8px; white-space:nowrap}
.heat i{display:flex; align-items:center; justify-content:center; height:25px;
  border-radius:3px; font-style:normal; font-size:11.5px}
/* A year nobody shot still gets a cell: the absence is the information. */
.heat i.zero{background:var(--surface-2)}

.facts{display:grid; grid-template-columns:repeat(auto-fit,minmax(168px,1fr)); gap:1px;
  background:var(--border); border:1px solid var(--border); border-radius:6px; overflow:hidden}
.fact{background:var(--surface); padding:15px 18px}
.fact b{display:block; font-size:1.45rem; font-weight:700; letter-spacing:-.02em;
  font-variant-numeric:tabular-nums}
.fact span{display:block; margin-top:4px; color:var(--text-2); font-size:13.5px}
.chip-or{color:var(--muted); font-size:13px; padding:0 1px}
.linkish{background:none; border:0; color:var(--accent); font:inherit; cursor:pointer;
  text-decoration:underline; text-underline-offset:2px; padding:0}
@media (max-width:760px){ .two{grid-template-columns:1fr} }

.foot{border-top:1px solid var(--border); padding:30px 28px 50px; color:var(--muted); font-size:13.5px}
.foot p{max-width:70ch; margin:0 0 .6em}
@media (max-width:860px){
  .wrap{padding:0 16px}
  .top{padding:12px 16px; flex-wrap:wrap}
  .search{order:3; flex-basis:100%; max-width:none}
}
@media (max-width:860px){
  /* A full-width blur recomputed on every composited frame is the single most
     expensive thing on this page while a phone is scrolling, and it buys a
     translucency nobody can see over a near-black ground. */
  .top{backdrop-filter:none; background:var(--bg)}
}
@media (max-width:700px){
  /* 190 monthly cells cannot fit a phone with a gap between them: 190 bars and
     189 gaps need 379px of a 316px card, which is what pushed the ruler -- the
     row that has no scroller of its own -- past the right edge and let the
     whole page pan sideways. Closed up, the cells divide the card exactly and
     the histogram reads as the sparkline it has become at this width. */
  .tlbars{gap:0; overflow-x:hidden}
  .tlb{min-width:1px; border-radius:0}
  .tlyears{gap:0}
  .ty{min-width:1px}
  .ty.jan::before,.ty.jan::after{left:0; width:1px}
  .tlhint{display:none}
  /* One tile per row made a 100-image page 24,000px long and stretched a 320px
     thumbnail across 1,068 device pixels. Two per row halves the scroll and
     brings the tile back within reach of its source. min-width:150px already
     caps the row at two. */
  .cell{flex-basis:calc(var(--ar) * 78px)}
  /* There is no hover on a phone, so the date and contributor were unreachable.
     At two-up the tile is big enough to carry the caption permanently. */
  .cell figcaption{opacity:1; font-size:12px; padding:14px 8px 6px;
    background:linear-gradient(transparent,rgba(6,8,11,.92))}
  /* Six rows of contributor names pushed the first screenshot off the screen.
     Two rows, and the rest on demand. */
  .tllegend{max-height:3.4em; overflow:hidden; position:relative}
  .tllegend.open{max-height:none}
  .tlmore{display:block}
}
@media (prefers-reduced-motion:reduce){*{transition:none!important; animation:none!important}}

/* ---- text read from the screenshots ---- */
/* Unverified is a property of a reading, not an error: amber, quiet, never
   hiding the text it qualifies. */
/* No margin of its own: in a sentence the spaces around it are the sentence's,
   and a list that puts it after a value adds the gap itself. span.unv so a
   row's span styles (.trow span) cannot resize it. */
span.unv{display:inline-block; margin:0; padding:0 6px; border-radius:4px;
  font:500 11.5px/1.7 "JetBrains Mono",monospace; letter-spacing:.03em;
  color:#e0b45a; background:#2b2312; border:1px solid #4a3a17; vertical-align:1px}
.pnote{color:var(--muted); font-size:.9rem; max-width:72ch}
.readout{margin:22px 0 18px; padding:14px 18px 6px; background:var(--surface);
  border:1px solid var(--border); border-radius:6px}
.readout .pnote{margin:0 0 6px}
.readout h2{font-size:.82rem; text-transform:uppercase; letter-spacing:.08em;
  color:var(--muted); margin:16px 0 6px; font-weight:600}
.readout ul{list-style:none; margin:0; padding:0}
.readout li{font-family:"JetBrains Mono",monospace; font-size:13px; line-height:1.55;
  padding:2px 0 2px 10px; border-left:2px solid var(--border-2); margin:2px 0;
  overflow-wrap:anywhere}
.readout li.u{color:var(--text-2); border-left-color:#4a3a17; font-style:italic}
.readout li.u .unv{font-style:normal}
.readout li .unv{margin-left:8px}
.readout .who li i{color:var(--muted); font-style:normal; font-size:13px; margin-left:6px}
.readout details{margin:14px 0 8px; color:var(--text-2); font-size:.88rem}
.readout summary{cursor:pointer; color:var(--muted)}
.readout .mods{font-family:"JetBrains Mono",monospace; font-size:13px; color:var(--muted);
  overflow-wrap:anywhere}
.readout .ver{color:var(--muted); font-size:13.5px}
.readout li a{color:inherit; text-decoration-color:rgba(91,140,255,.55)}
.readout li a:hover{color:var(--accent)}

.player,.find{padding:30px 0 70px}
.player h1,.find h1{margin:6px 0 4px; overflow-wrap:anywhere}
.player h2,.find h2{font-size:.95rem; font-weight:600; margin:26px 0 10px}
.kicker{margin:0; font-size:.9rem}
.psum{color:var(--text-2); margin:0 0 8px}
.player .tl{margin:22px 0 4px}
.player .tlhead h2{margin:0}
/* Two columns once there is room: one 900px column left the right third of a
   desktop empty and halved how many names showed before Show more. */
.plist{display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,520px),1fr)); gap:6px}
.plist .extra{grid-column:1/-1}
.plist .more{grid-column:1/-1; justify-self:start; margin-top:2px; padding:6px 12px; background:none;
  border:1px solid var(--border-2); border-radius:5px; color:var(--accent); font:inherit;
  font-size:13px; cursor:pointer}
.plist .more:hover{border-color:var(--accent)}
.plist .extra[hidden]{display:none}
.prow,.trow{display:flex; flex-wrap:wrap; gap:4px 14px; align-items:baseline;
  padding:8px 12px; background:var(--surface); border:1px solid var(--border);
  border-radius:5px; text-decoration:none; color:var(--text)}
.prow:hover,.trow:hover{border-color:var(--accent); background:var(--surface-2)}
.prow b{font-family:"JetBrains Mono",monospace; font-weight:500; overflow-wrap:anywhere}
.prow > span,.trow > span{color:var(--muted); font-size:.84rem}
.tlist{display:flex; flex-direction:column; gap:6px}
.trow{align-items:center}
.trow .thumb{width:64px; height:36px; object-fit:cover; border-radius:3px; flex:none;
  background:var(--surface-2)}
.trow code{font-family:"JetBrains Mono",monospace; font-size:13px; flex:1 1 420px;
  overflow-wrap:anywhere; color:var(--text)}
.findform{display:flex; gap:10px; flex-wrap:wrap; margin:18px 0 8px; max-width:900px}
.findform input{flex:1 1 300px; min-width:0; padding:10px 12px; font:inherit;
  background:var(--surface); color:var(--text); border:1px solid var(--border-2); border-radius:6px}
.findform input:focus{outline:none; border-color:var(--accent)}
.find select{background:var(--surface); color:var(--text); border:1px solid var(--border-2);
  border-radius:4px; font:inherit; padding:1px 4px}
.gridhead2{font-size:.95rem; font-weight:600; margin:28px 0 12px}
.findform .dl{background:var(--accent-dim); cursor:pointer; font:inherit}

/* Stats: links to each section, under the intro. */
.jump{display:flex; flex-wrap:wrap; gap:8px; margin-top:16px}
.jump a{padding:5px 12px; border:1px solid var(--border-2); border-radius:999px; font-size:13.5px;
  color:var(--text-2); text-decoration:none}
.jump a:hover{border-color:var(--accent); color:var(--accent)}
/* Sections land below the sticky header, not under it. */
.card[id],#facts-head{scroll-margin-top:calc(var(--topH, 70px) + 12px)}

/* ---- image page: picture, who and when, actions; details folded away ---- */
.zoomin{display:block; padding:0; margin:0; border:0; background:none; cursor:zoom-in; max-width:100%}
.shotbar{display:flex; flex-wrap:wrap; justify-content:space-between; align-items:flex-end;
  gap:12px 20px; margin:18px 0 16px}
.shotbar h1{margin:0 0 2px}
.byline{margin:0; color:var(--text-2)}
.moremeta{margin:6px 0 24px}
.moremeta summary{cursor:pointer; color:var(--text-2); font-size:.95rem; margin-bottom:12px}
.moremeta[open] summary{margin-bottom:14px}

/* ---- zoom viewer ---- */
body.viewing{overflow:hidden}
.viewer{position:fixed; inset:0; z-index:50; background:rgba(5,6,8,.96); overflow:hidden;
  display:flex; align-items:center; justify-content:center; touch-action:none; cursor:grab}
.viewer:active{cursor:grabbing}
.viewer img{max-width:100vw; max-height:100vh; width:auto; height:auto; user-select:none;
  transform-origin:center; will-change:transform}
.vbar{position:absolute; left:50%; bottom:16px; transform:translateX(-50%); display:flex;
  align-items:center; gap:8px; padding:6px; background:rgba(21,24,30,.9);
  border:1px solid var(--border-2); border-radius:8px; cursor:default}
.vbar button{background:none; border:1px solid var(--border-2); border-radius:5px; color:var(--text);
  font-size:18px; line-height:1; padding:7px 12px; cursor:pointer}
.vbar button:hover{border-color:var(--accent); color:var(--accent)}
.vbar span{color:var(--muted); font-size:13px; padding:0 6px; white-space:nowrap}
@media (max-width:600px){ .vbar span{display:none} }

/* Search: a count beside each section heading, and Load more under a list. */
.find h2 .n{margin-left:6px; color:var(--muted); font-weight:500; font-variant-numeric:tabular-nums}
.find h2 .n:empty{display:none}
.loadmore{margin-top:10px; padding:7px 14px; background:none; border:1px solid var(--border-2);
  border-radius:5px; color:var(--accent); font:inherit; font-size:13.5px; cursor:pointer}
.loadmore:hover{border-color:var(--accent)}

/* Player page: the screenshot count and its order control on one line. */
.ptools{display:flex; flex-wrap:wrap; justify-content:space-between; align-items:baseline; gap:8px 16px;
  margin-top:28px}
.ptools .gridhead2{margin:0 0 10px}
#pwith{margin-top:26px}
#pmore{margin:16px 0 0}

/* ---- home: highlights, one row that scrolls sideways ---- */
.highlights{margin:0 0 26px}
.hlhead{display:flex; flex-wrap:wrap; align-items:baseline; gap:6px 14px; margin-bottom:10px}
.hlhead h2{margin:0; font-size:1.05rem}
.hlnote{color:var(--muted); font-size:.9rem; flex:1}
.hlhead .loadmore{margin:0}
.hlstrip{display:flex; gap:10px; overflow-x:auto; padding-bottom:8px; scroll-snap-type:x proximity;
  scrollbar-color:var(--border-2) transparent}
.hlcell{flex:none; position:relative; height:150px; border-radius:5px; overflow:hidden;
  border:1px solid var(--border); scroll-snap-align:start; background:var(--surface)}
.hlcell img{height:150px; width:auto; max-width:none}
.hlcell span{position:absolute; left:0; right:0; bottom:0; padding:12px 8px 5px; font-size:12.5px;
  font-family:"JetBrains Mono",monospace; color:#e6e9ef;
  background:linear-gradient(transparent, rgba(0,0,0,.75))}
.hlcell:hover{border-color:var(--accent)}
@media (max-width:600px){ .hlcell, .hlcell img{height:120px} }
/* Inside a search section a note is a line, not a whole empty page. */
.find section .empty-note{padding:6px 0}
#fempty{padding:12px 0}

/* Search page, before a query: what it searches, and a few to try. */
.tries{display:flex; flex-wrap:wrap; align-items:center; gap:8px; color:var(--muted); font-size:.9rem}
.tries a{padding:5px 12px; border:1px solid var(--border-2); border-radius:999px; text-decoration:none;
  color:var(--text-2); font-family:"JetBrains Mono",monospace; font-size:13px}
.tries a:hover{border-color:var(--accent); color:var(--accent)}

/* Player timeline: the player's own years, or the whole archive. */
.tlwide{background:none; border:1px solid var(--border-2); color:var(--text-2); font:inherit;
  font-size:13px; padding:3px 10px; border-radius:4px; cursor:pointer}
.tlwide:hover{border-color:var(--accent); color:var(--accent)}

/* Keyboard users can jump past the header; it shows only when focused. */
.skip{position:absolute; left:12px; top:-60px; z-index:60; padding:10px 16px; border-radius:5px;
  background:var(--accent); color:#fff; font-weight:600; text-decoration:none}
.skip:focus{top:12px}
main:focus{outline:none}

/* Touch screens: every control at least 44px tall (the header links were 24,
   the legend names 19). Padding grows the target without moving the text. */
@media (max-width:700px), (pointer:coarse){
  .top nav{gap:6px}
  .top nav a{display:inline-flex; align-items:center; min-height:44px; padding:0 8px}
  .tllegend a{min-height:36px}
  .tllegend{gap:0 14px}
  .chip button{min-width:32px; min-height:32px}
  .chipclear,.tlclear,.tlwide{min-height:36px}
  .legend button{min-height:40px}
  .plist .more,.loadmore{min-height:40px}
}
@media (max-width:700px){
  /* Two rows of the taller touch targets, the rest behind Show all. */
  .tllegend{max-height:74px}
}

/* Image page: the contributor's other screenshots from the same sitting. */
.sess{margin:4px 0 18px}
.sess h2{font-size:.95rem; font-weight:600; margin:0 0 10px}
.sess .hlcell,.sess .hlcell img{height:96px}
.sess .hlcell.here{border-color:var(--accent); outline:1px solid var(--accent)}

/* Year buttons: phones only, where the timeline is too narrow to drag on. */
.yearchips{display:none}
@media (max-width:700px){
  .yearchips{display:flex; gap:6px; overflow-x:auto; margin:-10px 0 18px; padding-bottom:4px;
    scrollbar-width:none}
  .yearchips button{flex:none; min-height:40px; padding:0 14px; border-radius:999px; font:inherit;
    font-size:14px; background:var(--surface); color:var(--text-2); border:1px solid var(--border-2)}
  .yearchips button[aria-pressed="true"]{background:var(--accent-dim); color:var(--accent); border-color:var(--accent)}
}

/* The words a chat search matched, inside the line. */
.trow mark{background:rgba(91,140,255,.28); color:var(--text); border-radius:2px; padding:0 1px}

/* Footer: the site's pages, so the bottom of a long grid is not a dead end. */
.footnav{display:flex; flex-wrap:wrap; gap:4px 22px; margin:0 0 16px; font-size:14.5px}
.footnav a{color:var(--text-2); text-decoration:none}
.footnav a:hover{color:var(--accent)}
@media (max-width:700px), (pointer:coarse){
  .footnav{gap:0 18px}
  .footnav a{display:inline-flex; align-items:center; min-height:44px}
}
