/* ==========================================================
   ARKIV — a theme for oerum.org, on Grav.
   No webfonts, no frameworks, no libraries. System stacks only.
   Every colour on the page comes from the token block below.
   Lifted unchanged from the specimen this theme was designed in;
   the specimen is the reference rendering.
   ========================================================== */
/* One ground, deliberately: black on white, on screen and on paper alike.
   This does NOT follow the OS theme — a visitor in dark mode still gets white,
   and there is no prefers-color-scheme block anywhere in this file. */
:root{
  --paper:#ffffff;
  --ink:#111318;            /* not #000: pure black on pure white glares at 17px */
  --rule:#c9ccc4;
  --dim:#5f645b;

  --flash:#0047ff;          /* set per work type, see below */
  --flash-on:#ffffff;

  --mono:ui-monospace,"Cascadia Mono","Segoe UI Mono",Consolas,"SF Mono",Menlo,monospace;
  --text:ui-serif,Charter,"Iowan Old Style",Georgia,"Times New Roman",serif;

  --pad:.8rem;
}

/* work type carries the colour; a work with no type flashes plain ink */
.t-ex  {--flash:#0047ff;--flash-on:#ffffff}
.t-pub {--flash:#c4001a;--flash-on:#ffffff}
.t-on  {--flash:#00674b;--flash-on:#ffffff}
.t-no  {--flash:#111318;--flash-on:#ffffff}

/* ---------- ground ---------- */
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0; background:var(--paper); color:var(--ink);
  font-family:var(--text); font-size:17px; line-height:1.5;
}
::selection{background:var(--flash); color:var(--flash-on)}
a{color:inherit; text-underline-offset:.18em; text-decoration-thickness:from-font}
a:hover,a:focus-visible{background:var(--flash); color:var(--flash-on); text-decoration:none; outline:none}
:focus-visible{outline:2px solid var(--flash); outline-offset:1px}
/* Headings take focus on navigation so a keyboard user is not dropped back at
   the top of the document. They cannot be tabbed to — only focused in code —
   so the ring is noise: it drew a box round every page title. Screen readers
   still announce the move. */
[tabindex="-1"]:focus,[tabindex="-1"]:focus-visible{outline:none}
button{font:inherit; color:inherit}
hr{border:0; border-top:1px solid var(--rule); margin:0}

.mono{font-family:var(--mono); font-variant-numeric:tabular-nums lining-nums}
.lab{font-family:var(--mono); font-size:.68rem; letter-spacing:.08em;
     text-transform:uppercase; color:var(--dim)}

/* ---------- masthead ---------- */
#top{
  position:sticky; top:0; z-index:20; background:var(--paper);
  border-bottom:1px solid var(--ink); display:flex; flex-wrap:wrap; align-items:stretch;
}
#top .id{display:flex; flex-wrap:wrap; align-items:baseline; gap:.2em .7em;
  padding:.5rem var(--pad); flex:1 1 auto; min-width:0}
#top .id b{font-family:var(--mono); font-size:.72rem; font-weight:700; letter-spacing:.1em; text-transform:uppercase}
#top .id span{font-family:var(--mono); font-size:.68rem; color:var(--dim);
  min-width:0; overflow-wrap:anywhere}
#nav{display:flex; flex-wrap:wrap; align-items:stretch; flex:1 1 auto}
#nav a{
  display:flex; align-items:center; text-decoration:none;
  background:none; border:0; border-left:1px solid var(--rule);
  font-family:var(--mono); font-size:.68rem; letter-spacing:.06em; text-transform:uppercase;
  color:var(--dim); padding:.5rem .7rem; cursor:pointer; white-space:nowrap;
}
#nav a:hover,#nav a:focus-visible{background:var(--flash); color:var(--flash-on); outline:none}
#nav a[aria-current="page"]{color:var(--ink); font-weight:700}

/* ---------- page head ---------- */
.head{padding:1.5rem var(--pad) 1.1rem; border-bottom:1px solid var(--ink);
      display:flex; flex-wrap:wrap; align-items:baseline; gap:.5rem 2rem}
.head h1{font-size:clamp(1.5rem,4vw,2.2rem); font-weight:400; margin:0;
         letter-spacing:-.01em; line-height:1.1; text-wrap:balance}
.head p{margin:0; max-width:58ch; color:var(--dim); font-size:.95rem}

/* ---------- toolbar ---------- */
#tools{display:flex; flex-wrap:wrap; align-items:stretch; border-bottom:1px solid var(--rule)}
#tools>*{border-right:1px solid var(--rule)}
#tools .srch{display:flex; align-items:center; gap:.55em; padding:.45rem var(--pad)}
#find{border:0; background:none; color:var(--ink); font-family:var(--mono); font-size:.82rem;
      padding:.1rem 0; width:14ch; border-bottom:1px solid var(--ink)}
#find::placeholder{color:var(--dim)}
#find:focus{outline:none; border-bottom-color:var(--flash); box-shadow:0 1px 0 var(--flash)}
#chips{display:flex; flex-wrap:wrap}
#chips button{
  background:none; border:0; border-right:1px solid var(--rule);
  font-family:var(--mono); font-size:.68rem; letter-spacing:.05em; text-transform:uppercase;
  color:var(--dim); padding:.55rem .7rem; cursor:pointer; display:flex; align-items:center; gap:.45em;
}
#chips button:last-child{border-right:0}
#chips i{width:.6em; height:.6em; background:var(--flash); display:block; flex:none}
#chips button:hover,#chips button:focus-visible,#chips button[aria-pressed="true"]{
  background:var(--flash); color:var(--flash-on); outline:none}
#chips button:hover i,#chips button:focus-visible i,#chips button[aria-pressed="true"] i{background:var(--flash-on)}
#count{padding:.55rem var(--pad); font-family:var(--mono); font-size:.68rem;
       letter-spacing:.05em; color:var(--dim); text-transform:uppercase; display:flex; align-items:center}
#modes{margin-left:auto; display:flex; border-right:0}
#modes button{background:none; border:0; border-left:1px solid var(--rule);
  font-family:var(--mono); font-size:.68rem; letter-spacing:.06em; text-transform:uppercase;
  color:var(--dim); padding:.55rem .7rem; cursor:pointer}
#modes button[aria-pressed="true"]{color:var(--ink); font-weight:700}
#modes button:hover,#modes button:focus-visible{background:var(--flash); color:var(--flash-on); outline:none}

/* ---------- list ---------- */
/* `overflow-x:auto` makes this a scroll container, and a scroll container
   captures any position:sticky inside it — so the sticky table head stopped
   sticking to the viewport and simply scrolled away. The wrapper only needs to
   scroll where the table genuinely does not fit, so above 900px it is let go
   and the head sticks properly again.
   NOTE: computed `top` being 67px proves nothing here. Measure the rect after
   scrolling; that is what caught this. */
.tablewrap{overflow-x:auto}
@media (min-width:900px){ .tablewrap{overflow-x:visible} }
/* below that the wrapper must keep scrolling, so the head cannot stick to the
   viewport anyway — make it static rather than leave it half-stuck, which
   collided with the masthead by a few pixels */
@media (max-width:899px){ thead th{position:static} }
table{border-collapse:collapse; width:100%; font-size:.98rem}
thead th{position:sticky; top:var(--stick,0px); z-index:5; background:var(--paper);
  text-align:left; padding:0; border-bottom:1px solid var(--ink); white-space:nowrap}
thead button{
  width:100%; text-align:left; background:none; border:0; cursor:pointer;
  font-family:var(--mono); font-size:.66rem; letter-spacing:.08em; text-transform:uppercase;
  color:var(--dim); padding:.5rem var(--pad); display:flex; gap:.4em; align-items:center;
}
thead th[aria-sort] button{color:var(--ink); font-weight:700}
thead button:hover,thead button:focus-visible,thead th[aria-sort] button:hover{
  background:var(--flash); color:var(--flash-on); outline:none}
thead .arrow{font-size:.8em; opacity:0}
thead th[aria-sort] .arrow{opacity:1}
tbody td{padding:.4rem var(--pad); border-bottom:1px solid var(--rule); vertical-align:baseline}
tbody tr:hover td,tbody tr:has(a:focus-visible) td{background:var(--flash); color:var(--flash-on)}
tbody tr:hover .num,tbody tr:hover .date,tbody tr:hover .type,tbody tr:hover .place,
tbody tr:has(a:focus-visible) .num,tbody tr:has(a:focus-visible) .date,
tbody tr:has(a:focus-visible) .type,tbody tr:has(a:focus-visible) .place{color:var(--flash-on)}
tbody tr:hover a{background:none; color:inherit}
.num,.date{font-family:var(--mono); font-variant-numeric:tabular-nums lining-nums;
  font-size:.74rem; color:var(--dim); white-space:nowrap}
.ttl{line-height:1.25}
.ttl a{text-decoration:underline}
.ttl a:hover{background:none}
.ttl small{display:block; font-family:var(--mono); font-size:.66rem; color:var(--dim); margin-top:.1em}
tbody tr:hover .ttl small{color:var(--flash-on)}
.type,.place{font-family:var(--mono); font-size:.7rem; color:var(--dim)}
.type{white-space:nowrap}
.type i{width:.55em; height:.55em; background:var(--flash); display:inline-block; margin-right:.5em}
tbody tr:hover .type i{background:var(--flash-on)}
.place{max-width:24ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.none{opacity:.45}
/* A work that PREDATES the numbering, which is not the same as one waiting for
   a number. The archive system starts around 2015 and holds nothing before it,
   so these will never get one — and an em dash identical to the waiting rows
   would say the sequence has holes in it where it has an edge. Lower case
   against the figures, so it reads as a note and not as a value. */
.num .pre{font-size:.82em; letter-spacing:.06em; opacity:.55;
  font-variant-numeric:normal}

/* the resemblance column: a number and nothing else, deliberately unexplained
   in the row itself. It is a button because it goes somewhere. */
.like{width:1%; white-space:nowrap; text-align:right}
.like a,.like button{background:none; border:0; cursor:pointer; padding:0 0 0 .4em;
  text-decoration:none;
  font-family:var(--mono); font-variant-numeric:tabular-nums lining-nums;
  font-size:.74rem; color:var(--dim)}
.like a::before,.like button::before{content:"≈ "; opacity:.55}
.like a:hover,.like a:focus-visible,.like button:hover,.like button:focus-visible{
  background:var(--flash); color:var(--flash-on); outline:none}
tbody tr:hover .like a,tbody tr:hover .like button{color:var(--flash-on)}
tbody tr:hover .like a:hover,tbody tr:hover .like button:hover{background:var(--flash-on); color:var(--flash)}

/* ---------- grid ---------- */
#grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(180px,1fr));
      gap:1px; background:var(--rule); border-bottom:1px solid var(--rule)}
.cell{background:var(--paper); display:flex; flex-direction:column; text-decoration:none}
.cell img{width:100%; aspect-ratio:1/1; object-fit:cover; display:block;
          filter:grayscale(1) contrast(1.05); background:var(--rule)}
/* A work can have no photograph at all — `speaker1` is a text and a film, and
   it is the first one. Without this the cell collapses to its caption and the
   grid goes ragged around it. An empty square holds the rhythm and says plainly
   that there is no picture, which is the choice the untyped works already make:
   absence reads as absence, not as another kind of thing. */
.cell:not(:has(img))::before{content:""; display:block; aspect-ratio:1/1;
  background:var(--paper); border-bottom:1px solid var(--rule)}
.cell .cap{padding:.4rem .5rem .5rem; display:flex; flex-direction:column; gap:.1rem}
.cell .ct{font-size:.9rem; line-height:1.2}
.cell .cd{font-family:var(--mono); font-size:.66rem; color:var(--dim);
          font-variant-numeric:tabular-nums lining-nums}
.cell:hover img,.cell:focus-visible img{filter:none}
.cell:hover .cap,.cell:focus-visible .cap{background:var(--flash); color:var(--flash-on)}
.cell:hover .cd,.cell:focus-visible .cd{color:var(--flash-on)}
.cell:hover,.cell:focus-visible{background:var(--paper); color:var(--ink);
  outline:2px solid var(--flash); outline-offset:-2px}

/* ---------- record ---------- */
.rechead{padding:1.4rem var(--pad) 1.1rem; border-bottom:1px solid var(--ink)}
.back{font-family:var(--mono); font-size:.68rem; letter-spacing:.06em;
      text-transform:uppercase; text-decoration:none; color:var(--dim)}
.rechead h1{font-size:clamp(1.7rem,4.6vw,2.9rem); font-weight:400; margin:.45rem 0 0;
  letter-spacing:-.015em; line-height:1.05; text-wrap:balance; max-width:24ch}
/* Details is a native <details>, shut by default. It used to be a sticky
   column beside the text; a grid item's sticky containing block is the whole
   grid, not its row, so it went on sticking over the image band below. */
details.facts{border-bottom:1px solid var(--rule)}
details.facts>summary{
  list-style:none; cursor:pointer; display:flex; align-items:baseline; gap:.6em;
  font-family:var(--mono); font-size:.7rem; letter-spacing:.07em; text-transform:uppercase;
  color:var(--dim); padding:.55rem var(--pad);
}
details.facts>summary::-webkit-details-marker{display:none}
details.facts>summary::before{content:"+"; width:1ch; display:inline-block; font-weight:700}
details.facts[open]>summary::before{content:"\2212"}
details.facts>summary:hover,details.facts>summary:focus-visible{
  background:var(--flash); color:var(--flash-on); outline:none}
details.facts>summary .n{margin-left:auto; font-variant-numeric:tabular-nums lining-nums}
details.facts dl{margin:0; padding:.2rem 0 .7rem; border-top:1px solid var(--rule)}
details.facts dl div{display:grid; grid-template-columns:6.5rem minmax(0,1fr); gap:.5rem;
  padding:.3rem var(--pad); align-items:baseline; max-width:78ch}
details.facts dl div:hover{background:var(--flash); color:var(--flash-on)}
details.facts dl div:hover dt{color:var(--flash-on)}
details.facts dt{font-family:var(--mono); font-size:.64rem; letter-spacing:.06em;
  text-transform:uppercase; color:var(--dim); margin:0}
details.facts dd{margin:0; font-size:.9rem; line-height:1.35;
  min-width:0; overflow-wrap:anywhere}   /* a bare URL has nothing to break on */
details.facts dd.mono{font-size:.76rem}
.prose{padding:1.4rem 1.3rem 2.2rem; border-bottom:1px solid var(--rule)}
.prose p{margin:0 0 1em; max-width:64ch; font-size:1.02rem; line-height:1.6; text-wrap:pretty}
.prose p.empty{font-family:var(--mono); font-size:.8rem; color:var(--dim)}
/* A work's own text may carry headings, and EIGHT pages do - `## Project
   Description`, `### Process`, `### Results`. There was no rule for them here,
   so they fell through to the browser's defaults: bold Times at 1.5em in the
   middle of a page whose whole argument is that every size and face is chosen.
   Nobody had noticed because the sub-page renderer (.doc) has its own heading
   styles and the record page does not share them.

   The mono label is the same gesture the section rail uses, one level quieter:
   a heading inside a work's text is a marker in a column, not a new document. */
.prose h2,.prose h3,.prose h4{
  max-width:64ch; font-family:var(--mono); font-weight:400;
  letter-spacing:.08em; text-transform:uppercase; color:var(--dim);
  margin:2em 0 .7em}
.prose h2{font-size:.72rem}
.prose h3,.prose h4{font-size:.68rem}
.prose>:first-child{margin-top:0}
.prose ul,.prose ol{max-width:64ch; margin:0 0 1em; padding-left:1.2em}
.prose li{margin:0 0 .3em; line-height:1.6}
.prose blockquote{margin:0 0 1em; padding-left:1rem;
  border-left:1px solid var(--rule); color:var(--dim)}
/* ---------- other media ----------
   The gallery is not only photographs: a work can carry film, sound, a PDF or
   an outward link. Each is a typed card rather than a naked embed, so the row
   reads as a list of what exists before anything loads. */
.recmedia{display:grid; gap:1px; background:var(--rule);
  grid-template-columns:repeat(auto-fill,minmax(260px,1fr));
  border-bottom:1px solid var(--rule)}
.recmedia .m{background:var(--paper); display:flex; flex-direction:column;
  gap:.35rem; padding:.7rem var(--pad) .8rem; text-decoration:none; min-width:0}
.recmedia .k{font-family:var(--mono); font-size:.62rem; letter-spacing:.11em;
  text-transform:uppercase; color:var(--dim); display:flex; gap:.5em; align-items:center}
.recmedia .k::before{content:""; width:.55em; height:.55em; background:var(--flash)}
.recmedia .t{font-size:.95rem; line-height:1.25; overflow-wrap:anywhere}
.recmedia .u{font-family:var(--mono); font-size:.66rem; color:var(--dim);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
a.m:hover,a.m:focus-visible,button.m:hover,button.m:focus-visible{
  background:var(--flash); color:var(--flash-on); outline:none}
a.m:hover .k,a.m:hover .u,button.m:hover .k,button.m:hover .u{color:var(--flash-on)}
a.m:hover .k::before,button.m:hover .k::before{background:var(--flash-on)}
button.m{border:0; cursor:pointer; font:inherit; text-align:left; color:inherit}
.recmedia audio{width:100%; height:32px}
.recmedia .demo{font-family:var(--mono); font-size:.62rem; color:var(--dim);
  border:1px solid var(--rule); padding:.05em .4em; align-self:flex-start}
.recmedia .film{aspect-ratio:16/9; width:100%; border:0; display:block; background:var(--rule)}

.recimgs{display:grid; gap:1px; background:var(--rule);
  grid-template-columns:repeat(auto-fill,minmax(290px,1fr))}
.recimgs figure{margin:0; background:var(--paper)}
.recimgs img{width:100%; display:block; filter:grayscale(1) contrast(1.05)}
.recimgs figure:hover img{filter:none}

/* ==========================================================
   CAPTIVE PORTAL — a different entity, and it has to look like one.

   It is Kristoffer's artist-run space, not part of the portfolio, so it does
   not wear the portfolio's identity. Three things change at once, which is
   about as far as you can go while still plainly being the same website:

     ground     inverted. You walk into a dark room.
     type       mono throughout — a notice board, not a register. The main
                site's serif is what carries the archive's prose; dropping it
                is the clearest possible signal that this is somewhere else.
     accent     one signal amber, its own. The portfolio's four colours mean
                work-type and mean nothing here.

   ALL OF THIS IS A TOKEN BLOCK. Because every colour and both faces in this
   stylesheet already come from custom properties, an entire second identity is
   nine declarations — which is the payoff for having been strict about it.
   ========================================================== */
body.cp{
  --paper:#0b0b0b;
  --ink:#f2f2ee;
  --rule:#2b2b26;
  --dim:#8e8e86;
  --flash:#ffd400;          /* a system notice, not a work type */
  --flash-on:#0b0b0b;
  --text:var(--mono);       /* one line, and the whole page changes voice */
}
body.cp .doc section{grid-template-columns:minmax(0,1fr); gap:0}
body.cp .doc section>h2{
  text-align:left; padding:.9rem var(--pad) .3rem 0; color:var(--ink);
  font-size:.78rem; letter-spacing:.14em}
body.cp .doc .sec-body{padding:.2rem 1.3rem 1.3rem 0; font-size:.86rem; line-height:1.65}
body.cp .doc p{max-width:74ch}
body.cp .doc li{margin-bottom:.45em}
body.cp .rechead h1{font-family:var(--mono); font-size:clamp(1.3rem,3.4vw,2rem);
  letter-spacing:.06em; text-transform:uppercase}
body.cp .head h1{font-family:var(--mono)}
body.cp #top .id b{color:var(--flash)}

/* on paper it goes back to black on white like everything else: an inverted
   ground is a screen decision, not a printing one */
@media print{
  body.cp{--paper:#fff; --ink:#000; --rule:#000; --dim:#444;
          --flash:#000; --flash-on:#fff}
}

/* ---------- third level: blog posts, Captive Portal exhibitions ----------
   A listing and an item, twice over. The two share this CSS and differ only by
   which identity is on the body — which is the whole point of the token
   discipline, and is what the Grav templates should inherit. */
.listing{border-bottom:1px solid var(--rule)}
.entry{display:grid; grid-template-columns:minmax(0,7rem) minmax(0,1fr);
  gap:0 1.4rem; align-items:start; border-bottom:1px solid var(--rule);
  width:100%; background:none; border-left:0; border-right:0; border-top:0;
  text-align:left; cursor:pointer; padding:0; color:inherit; font:inherit}
.entry .when{padding:.9rem var(--pad) .9rem 0; text-align:right;
  font-family:var(--mono); font-size:.7rem; color:var(--dim);
  font-variant-numeric:tabular-nums lining-nums; white-space:nowrap}
.entry .body{padding:.9rem 1.3rem .9rem 0; min-width:0; display:grid;
  grid-template-columns:minmax(0,1fr) auto; gap:0 1rem; align-items:start}
.entry .body>*{min-width:0}   /* or the 1fr track refuses to shrink and pushes
                                 the thumbnail past the edge */
.entry h3{margin:0 0 .2em; font-size:1.05rem; font-weight:400; line-height:1.25}
.entry p{margin:0; color:var(--dim); font-size:.9rem; line-height:1.45;
  max-width:64ch; overflow:hidden; display:-webkit-box;
  -webkit-line-clamp:2; -webkit-box-orient:vertical}
.entry .thumb{width:76px; height:76px; object-fit:cover; display:block;
  filter:grayscale(1) contrast(1.05); background:var(--rule)}
.entry:hover,.entry:focus-visible{background:var(--flash); color:var(--flash-on); outline:none}
.entry:hover .when,.entry:hover p,.entry:focus-visible .when,.entry:focus-visible p{
  color:var(--flash-on)}
.entry:hover .thumb{filter:none}
.listnote{padding:1rem var(--pad) 2rem; color:var(--dim); font-size:.85rem;
  font-family:var(--mono); max-width:70ch; line-height:1.6}

@media (max-width:719px){
  .entry{grid-template-columns:1fr; gap:0}
  .entry .when{text-align:left; padding:.7rem var(--pad) 0}
  .entry .body{padding:.2rem var(--pad) .9rem}
}

/* ---------- text pages: C.V., Press, Didactics… ---------- */
/* Each page is split on whichever heading level it uses (h2 on the C.V., h3 on
   Press) and the heading goes in a rail, so a year or a section name reads as
   an index down the left edge instead of interrupting the column. */
.doc section{display:grid; grid-template-columns:minmax(0,11rem) minmax(0,1fr);
  gap:0 1.4rem; border-bottom:1px solid var(--rule); align-items:start}
/* a section with no heading of its own takes the full measure */
.doc section:has(h2:empty){grid-template-columns:minmax(0,1fr)}
.doc section:has(h2:empty)>h2{display:none}
.doc section:has(h2:empty)>.sec-body{padding-left:var(--pad)}
.doc section>h2{margin:0; padding:1rem var(--pad) 1rem 0;
  font-family:var(--mono); font-size:.7rem; font-weight:400; letter-spacing:.08em;
  text-transform:uppercase; color:var(--dim); text-align:right;
  font-variant-numeric:tabular-nums lining-nums}
.doc .sec-body{padding:1rem 1.3rem 1.1rem 0; min-width:0}
.doc .sec-body>*:first-child{margin-top:0}
.doc .sec-body>*:last-child{margin-bottom:0}
.doc p{margin:0 0 .55em; max-width:64ch; line-height:1.5}
.doc h3{margin:1.1em 0 .35em; font-size:1.05rem; font-weight:400; letter-spacing:-.01em}
.doc h4{margin:1em 0 .3em; font-family:var(--mono); font-size:.72rem;
  letter-spacing:.06em; text-transform:uppercase; color:var(--dim); font-weight:400}
.doc ul,.doc ol{margin:0 0 .6em; padding:0; list-style:none; max-width:74ch}
.doc li{margin:0 0 .3em; line-height:1.45; padding-left:1.1em; text-indent:-1.1em}
.doc li::before{content:"·"; color:var(--dim); margin-right:.6em}
.doc li strong{font-family:var(--mono); font-size:.76rem; font-weight:400;
  color:var(--dim); font-variant-numeric:tabular-nums lining-nums}
.doc img{max-width:100%; height:auto; display:block; filter:grayscale(1) contrast(1.05)}
.doc img:hover{filter:none}
.doc hr{margin:.8em 0}
.doc .away{font-family:var(--mono); font-size:.8rem}

/* ---------- lightbox ----------
   A native <dialog> opened with showModal(), which puts it in the browser's
   top layer — above the arcade canvas and the falling words without any
   z-index arms race, and with Escape and the backdrop handled for free. */
/* inset:0 with auto sizing, NOT width:100vw — 100vw includes the scrollbar of
   the page underneath, which pushed the Close button off the right edge */
#lightbox{border:0; padding:0; inset:0; width:auto; height:auto;
  max-width:100%; max-height:100%; background:var(--paper); color:var(--ink)}
#lightbox::backdrop{background:var(--paper)}
#lightbox .frame{display:grid; grid-template-rows:1fr auto; height:100%}
#lightbox .stage{display:grid; place-items:center; overflow:hidden; padding:1rem}
#lightbox img{max-width:100%; max-height:100%; object-fit:contain; display:block;
  filter:none}                      /* the greyscale comes off here: this is the look */
#lightbox .bar{display:flex; align-items:stretch; border-top:1px solid var(--ink);
  font-family:var(--mono); font-size:.72rem}
#lightbox .bar>*{display:flex; align-items:center; padding:.5rem .8rem;
  border-right:1px solid var(--rule)}
#lightbox .bar>*:last-child{border-right:0}
#lightbox button{background:none; border:0; cursor:pointer; color:var(--dim);
  font-family:var(--mono); font-size:.72rem; letter-spacing:.08em; text-transform:uppercase}
#lightbox button:hover,#lightbox button:focus-visible{
  background:var(--flash); color:var(--flash-on); outline:none}
#lightbox button[disabled]{opacity:.3; cursor:default}
#lightbox .count{font-variant-numeric:tabular-nums lining-nums;
  background:var(--flash); color:var(--flash-on)}
#lightbox .cap{color:var(--dim); flex:1; min-width:0; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap}
#lightbox .hint{color:var(--dim); font-size:.66rem}
.recimgs img,.doc img{cursor:zoom-in}

/* ---------- arcade ---------- */
/* The canvas never takes a pointer event, so the archive underneath stays
   usable with the game running. The HUD sits IN the masthead rather than
   floating over the page — an overlay would cover the first row of the list
   on a short window, which is the one thing this layer must not do. */
#arcade{position:fixed; inset:0; z-index:30; pointer-events:none}
/* the score is drawn in the 3x5 bitmap type, not set in the page's mono face:
   it should read as a machine's counter, not as one more line of metadata */
#hud[hidden]{display:none}
#hud{display:flex; align-items:stretch; margin-left:auto; flex-wrap:wrap;
     border-left:1px solid var(--rule); font-family:var(--mono); min-width:0}
#hud button{background:none; border:0; cursor:pointer; color:var(--dim);
            border-right:1px solid var(--rule); display:flex; align-items:center;
            padding:.5rem .6rem; font-size:.68rem; letter-spacing:.06em}
#hud button:last-child{border-right:0}
#hud button:hover,#hud button:focus-visible{
  background:var(--flash); color:var(--flash-on); outline:none}
#hud-toggle{text-transform:uppercase; letter-spacing:.1em}
#hud-toggle #hud-onoff{margin-left:.5em; color:var(--ink); font-weight:700}
#hud-toggle[aria-pressed="false"]{color:var(--dim)}
#hud-toggle[aria-pressed="false"] #hud-onoff{color:var(--dim); font-weight:400}
#hud-canvas{display:block; image-rendering:pixelated}
.sr{position:absolute; width:1px; height:1px; margin:-1px; padding:0;
    overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0}
/* Eleven tab stops stood between the top of the page and the content.
   Clipped rather than pushed to left:-9999px: an off-screen box still has a
   box, and a width audit has to special-case it forever. */
.skip{position:absolute; width:1px; height:1px; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap;
  background:var(--flash); color:var(--flash-on);
  font-family:var(--mono); font-size:.72rem; text-decoration:none}
.skip:focus{position:fixed; top:0; left:0; z-index:40;
  width:auto; height:auto; clip-path:none; padding:.5rem .8rem}

/* falling targets are real buttons, so they can be clicked, focused and read.
   The container ignores the pointer; only the words themselves take it. */
/* width:0 on purpose. A fixed `inset:0` box is sized from the initial
   containing block, which INCLUDES the scrollbar, so it hung ten pixels past
   the right edge and made the page scroll sideways. This element only needs to
   be an origin for its absolutely positioned children. */
#targets{position:fixed; top:0; left:0; width:0; height:0; z-index:31; pointer-events:none}
#targets button{position:absolute; top:0; left:0; padding:.35em .5em;
  background:var(--flash); border:0; cursor:pointer; pointer-events:auto;
  will-change:transform; line-height:0}
#targets canvas{display:block; image-rendering:pixelated}
#targets button:hover,#targets button:focus-visible{
  outline:3px solid var(--ink); outline-offset:0}

#scores{border:3px solid var(--ink); background:var(--paper); color:var(--ink);
        padding:1.2rem; max-width:92vw; font-family:var(--mono)}
#scores::backdrop{background:color-mix(in srgb, var(--ink) 55%, transparent)}
#board{display:block; image-rendering:pixelated; margin-bottom:1rem}
#scores footer{padding:0}
#scores button{font-family:var(--mono); font-size:.68rem; letter-spacing:.08em;
  text-transform:uppercase; background:none; border:1px solid var(--ink);
  padding:.35rem .8rem; cursor:pointer}
#scores button:hover{background:var(--flash); color:var(--flash-on); border-color:var(--flash)}

/* ---------- forms ----------
   Nothing styled a form field, and Grav's form plugin renders real ones on
   Contact — they would have arrived as browser defaults against everything
   else. Same tokens as the rest: a hairline under the field, no rounding, the
   flash on focus. */
/* THE CLASS NAMES BELOW ARE THE FORM PLUGIN'S, NOT THIS THEME'S — and that was
   the fault worth catching. These rules were written against `.f` and `.row`,
   invented here, while the plugin emits `.form-field`, `.form-label`,
   `.form-data` and `.buttons`. Everything element-based inside `.form` would
   have worked and the layout would have collapsed, which is the same mistake
   CLAUDE.md records about the first Twig build: markup styled against what was
   assumed rather than what is emitted.

   Both sets are kept. The plugin's markup has changed across versions, so the
   element selectors are the ones actually load-bearing; the classes only add
   spacing. */
.form{max-width:34rem; padding:1.2rem var(--pad) 2rem 0}
.form form,.form>.f{display:grid; gap:1rem}
.form .f,.form .form-field{display:grid; gap:.3rem}
.form .form-field{margin:0 0 1rem}
.form .form-fields{display:grid; gap:0}
.form label,.form .form-label{font-family:var(--mono); font-size:.66rem; letter-spacing:.09em;
  text-transform:uppercase; color:var(--dim)}
.form input,.form textarea,.form select{
  font:inherit; font-size:.95rem; color:var(--ink); background:none;
  border:0; border-bottom:1px solid var(--ink); border-radius:0;
  padding:.35rem 0; width:100%; min-width:0}
.form textarea{resize:vertical; min-height:6.5em; line-height:1.5}
.form input:focus,.form textarea:focus,.form select:focus{
  outline:none; border-bottom-color:var(--flash); box-shadow:0 1px 0 var(--flash)}
.form input:user-invalid,.form textarea:user-invalid{
  border-bottom-color:var(--flash); box-shadow:0 1px 0 var(--flash)}
.form .hint,.form .form-field .field-description{font-family:var(--mono); font-size:.66rem; color:var(--dim)}
.form .row,.form .buttons{display:flex; align-items:center; gap:1rem; flex-wrap:wrap}
.form button{font-family:var(--mono); font-size:.72rem; letter-spacing:.1em;
  text-transform:uppercase; background:none; color:var(--ink);
  border:1px solid var(--ink); padding:.5rem 1.1rem; cursor:pointer}
.form button:hover,.form button:focus-visible{
  background:var(--flash); color:var(--flash-on); border-color:var(--flash); outline:none}
.form button[disabled]{color:var(--dim); border-color:var(--rule); cursor:default}
.form .form-messages,.form .alert{font-family:var(--mono); font-size:.72rem; color:var(--ink); border-left:2px solid var(--flash); padding-left:.7rem; margin:0 0 1rem}
.form .note{font-family:var(--mono); font-size:.66rem; color:var(--dim);
  border-left:2px solid var(--rule); padding-left:.7rem; line-height:1.6}

/* ---------- the two pages that are really tables ----------
   The C.V. and Press are dated records, not prose. Giving them the generic
   section layout made them read as essays that happen to begin with a year;
   aligning the dates is the whole difference between a list you scan and a
   list you have to read. */
.rows{display:grid; grid-template-columns:minmax(0,8.5rem) minmax(0,1fr); gap:0}
.rows>*{padding:.3rem 0; border-bottom:1px solid var(--rule); min-width:0}
.rows .when{font-family:var(--mono); font-size:.72rem; color:var(--dim);
  font-variant-numeric:tabular-nums lining-nums; white-space:nowrap;
  padding-right:1rem}
.rows .what{line-height:1.4}
.rows .what a{text-decoration:underline}
.rows .out{font-family:var(--mono); font-size:.7rem; color:var(--dim);
  margin-left:.6em; white-space:nowrap}
.rows .pdf{font-family:var(--mono); font-size:.62rem; letter-spacing:.08em;
  border:1px solid var(--rule); padding:0 .35em; margin-left:.5em;
  text-decoration:none; white-space:nowrap}
.rows .pdf:hover{background:var(--flash); color:var(--flash-on); border-color:var(--flash)}
.rows .r:hover .when,.rows .r:hover .what{background:var(--flash); color:var(--flash-on)}
.rows .r{display:contents}
@media (max-width:719px){
  .rows{grid-template-columns:1fr}
  .rows .when{padding:.5rem 0 0; border-bottom:0}
  .rows .what{padding-top:0}
}

/* ---------- 404 ---------- */
.e404 .big{font-family:var(--mono); font-size:clamp(3rem,14vw,7rem);
  line-height:1; letter-spacing:.04em; margin:0; font-weight:700}
.e404 .said{font-family:var(--mono); font-size:.8rem; color:var(--dim);
  word-break:break-all; padding:.6rem var(--pad) 0 0}
/* borders on the cells, not gap-as-background: a grid whose last row is not
   full shows the gap colour through the empty cells, which prints and reads as
   a grey block sitting in the corner for no reason */
.e404 .ways{display:grid; grid-template-columns:repeat(auto-fill,minmax(190px,1fr));
  gap:0; border-top:1px solid var(--ink); margin-top:1.4rem}
.e404 .ways a,.e404 .ways button{background:var(--paper);
  border:0; border-right:1px solid var(--rule); border-bottom:1px solid var(--rule);
  padding:.7rem var(--pad); text-align:left; font:inherit; color:inherit;
  cursor:pointer; text-decoration:none; display:flex; flex-direction:column; gap:.2rem}
.e404 .ways .k{font-family:var(--mono); font-size:.62rem; letter-spacing:.1em;
  text-transform:uppercase; color:var(--dim)}
.e404 .ways a:hover,.e404 .ways button:hover,
.e404 .ways a:focus-visible,.e404 .ways button:focus-visible{
  background:var(--flash); color:var(--flash-on); outline:none}
.e404 .ways a:hover .k,.e404 .ways button:hover .k{color:var(--flash-on)}

/* ---------- note + status ---------- */
#status{display:none}
#peek{display:none}
@media (min-width:900px) and (hover:hover){
  #status{
    display:block; position:fixed; left:0; right:0; bottom:0; z-index:20;
    background:var(--paper); border-top:1px solid var(--ink);
    font-family:var(--mono); font-size:.68rem; letter-spacing:.04em; color:var(--dim);
    padding:.4rem var(--pad); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  #status b{color:var(--ink); font-weight:400}
  body{padding-bottom:2rem}
  #peek{
    display:block; position:fixed; right:0; bottom:2rem; z-index:15; width:200px;
    border:2px solid var(--flash); border-right:0; background:var(--paper); margin:0;
  }
  #peek .pair{display:grid; grid-template-columns:1fr 1fr}
  /* no resemblance yet — one picture, one column, no blank half */
  #peek.solo .pair{grid-template-columns:1fr}
  #peek.solo #peek-like{display:none}
  #peek.solo figcaption{grid-template-columns:1fr}
  #peek img{display:block; width:100%; aspect-ratio:1/1; object-fit:cover}
  #peek figcaption{font-family:var(--mono); font-size:.66rem;
    background:var(--flash); color:var(--flash-on); padding:.25rem .4rem;
    display:grid; grid-template-columns:1fr 1fr; gap:.4em}
  #peek figcaption span:last-child{text-align:right; opacity:.75}
}
#peek[hidden]{display:none!important}

/* Four columns want 391px and a phone has 375, so the Type column goes and its
   colour comes with it as a dot on the title. No dot means no type, which is
   the same distinction the column made. */
@media (max-width:559px){
  thead th:nth-child(4),tbody td.type{display:none}
  .ttl a::before{content:""; display:inline-block; width:.5em; height:.5em;
    background:var(--flash); margin-right:.5em; vertical-align:.05em}
  .t-no .ttl a::before{display:none}
  tbody tr:hover .ttl a::before{background:var(--flash-on)}
}

@media (max-width:719px){
  #top{position:static}
  .prose{padding:1.1rem var(--pad) 1.8rem}
  .place,.like{display:none}
  thead th:nth-child(5),thead th:nth-child(6){display:none}
  .doc section{grid-template-columns:1fr; gap:0}
  .doc section>h2{text-align:left; padding:.8rem var(--pad) .1rem;
    border-bottom:0; color:var(--ink)}
  .doc .sec-body{padding:.3rem var(--pad) 1rem}
}
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}

/* ==========================================================
   PRINT — same ground as the screen, harder. The ink goes to
   true black and the rules with it, because a #c9ccc4 hairline
   that reads as a rule on a backlit screen prints as nothing.
   Nothing here is a colour literal outside this block's tokens.
   ========================================================== */
@media print{
  :root{
    --paper:#ffffff; --ink:#000000; --rule:#000000; --dim:#444444;
    --flash:#000000; --flash-on:#ffffff;
  }
  /* the type colours go: hover does not exist on paper, and four inks on a
     page that is otherwise plain would be the only decoration on it */
  .t-ex,.t-pub,.t-on,.t-no{--flash:#000000;--flash-on:#ffffff}

  @page{margin:16mm 14mm}
  html,body{background:#fff; color:#000}
  body{font-size:10.5pt; line-height:1.4; padding:0}

  /* controls do not print, and neither does the game */
  #nav,#tools,#status,#peek,.back,#modes,#chips,#hud,#arcade,#targets,#lightbox{display:none!important}
  #top{position:static; border-bottom:1.5pt solid #000; padding-bottom:.2em}
  #top .id{padding-left:0}
  thead th{position:static}

  /* the list prints; the grid does not, and vice versa — whichever is on
     screen is what comes out, so print from the view you are looking at */
  .tablewrap{overflow:visible}
  table{font-size:9.5pt}
  thead{display:table-header-group}          /* repeat the head on every sheet */
  tr,figure,.doc section,.recimgs figure,.entry{break-inside:avoid}
  tbody td{padding:.18em .5em .18em 0; border-bottom:.25pt solid #999}
  .num,.date,.type,.place{color:#000}
  .like{display:none}                         /* the pairing is a screen gesture */
  thead th:nth-child(6){display:none}
  .type i{display:none}                       /* the swatch carries no ink meaning */

  #grid{grid-template-columns:repeat(4,1fr); gap:4mm; background:none}
  .cell img,.recimgs img,.doc img{filter:none; max-height:70mm; object-fit:contain}

  .head,.rechead{padding-left:0; border-bottom:1.5pt solid #000}
  .rechead h1,.head h1{font-size:20pt}
  .prose{padding:.6em 0 1em}
  .prose p{max-width:none; font-size:10.5pt}
  /* Grey reads as a quieter voice on a backlit screen and as weak ink on
     paper, which is the same reasoning that hardens the hairlines above. */
  .prose h2,.prose h3,.prose h4{color:#000; max-width:none;
    margin:1.4em 0 .4em; break-after:avoid}
  .prose ul,.prose ol,.prose blockquote{max-width:none}
  .doc section{grid-template-columns:22mm minmax(0,1fr)}
  .doc .sec-body{padding-right:0}

  /* a shut <details> would print as one word; the beforeprint handler opens
     every one and shuts them again afterwards */
  details.facts>summary{list-style:none}
  details.facts>summary::before{content:""}

  /* a printed link is a dead end without its address — but only in running
     text, never in the index, where 71 URLs would drown the table */
  .prose a[href^="http"]::after,.doc a[href^="http"]::after{
    content:" <" attr(href) ">"; font-family:var(--mono); font-size:8pt; word-break:break-all}
}
