/* ------------------------------------------------------------------
   jacksovelove.com

   Courier New, black on white, thin rules, no letterspacing,
   no dark mode, no fluid type. Sizes are fixed. Layout is fluid.
   ------------------------------------------------------------------ */


/* RESET ----------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

/* Courier Prime. A typewriter face redrawn for screens: lighter stems
   and a smaller x-height than Plex, which reads as paper rather than
   terminal. Self-hosted, no third-party requests. SIL OFL — licences
   in fonts/.

   IBM Plex Mono is still in fonts/ if you want it back: swap the two
   names in --mono and the @font-face family below. */
@font-face {
  font-family: "Courier Prime";
  src: url("/fonts/courier-prime-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Courier Prime";
  src: url("/fonts/courier-prime-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Courier Prime";
  src: url("/fonts/courier-prime-bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --mono: "Courier Prime", "Courier New", Courier, monospace;
}

html {
  color-scheme: light;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: #fff;
  color: #000;
  font-family: var(--mono);
  font-size: 16px;
  line-height: 1.5;
}

img, video, canvas, iframe, svg { display: block; max-width: 100%; }
img, video { height: auto; }

h1, h2, h3, p, ul, ol, dl, figure, blockquote { margin: 0; }

a { color: #000; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 10;
  background: #000; color: #fff;
  padding: 12px 16px;
}
.skip:focus { left: 0; }

:focus-visible { outline: 2px solid #000; outline-offset: 2px; }


/* PAGE ------------------------------------------------------------ */

.page {
  width: 100%;
  max-width: 96ch;          /* ~90 characters of Courier once the padding
                               comes off; long entries stay on one line */
  margin: 0 auto;
  padding: 48px 24px 96px;
}

.masthead { margin-bottom: 48px; }

.masthead .name {
  font-size: 24px;
  font-weight: bold;
  margin: 0 0 24px;
}

.masthead p {
  max-width: 60ch;
  margin: 0 0 24px;        /* one blank line, as it was typed */
}

/* set as verse: one line per line, turned lines hang so the
   shape survives a narrow screen */
.verse span {
  display: block;
  padding-left: 2ch;
  text-indent: -2ch;
}

.channels {
  list-style: none;
  padding: 0;
  margin: 24px 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0 24px;
}

.channels a {
  display: inline-block;
  padding: 11px 0;          /* keeps the tap target at 44px */
}

h2.plain {
  font-size: 16px;
  font-weight: bold;
  margin: 0 0 8px;
}

/* The heading and the one link out of the list sit on the same baseline,
   at either end of the column, directly above the drawer's own rule. */
.drawer-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin: 0 0 8px;
}

.drawer-head h2.plain { margin: 0; }

.drawer-head .aside { font-size: 14px; }

/* Sits with the heading rather than being spread across by the flex,
   so the map link stays on the right where it was. */
.drawer-head .count {
  font-size: 14px;
  margin-right: auto;
}


/* THE DRAWER ------------------------------------------------------- */

.drawer {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid #000;
}

.entry {
  display: block;
  padding: 12px 0;          /* 48px tall at one line — tap target */
  border-bottom: 1px solid #000;
  color: #000;
  text-decoration: none;
}

/* the title carries the underline; the whole row is the click area */
a.entry .title { text-decoration: underline; }
a.entry:hover .title,
a.entry:focus-visible .title { background: #000; color: #fff; }

.entry .clause::before { content: ", "; }

.entry .mark { white-space: nowrap; }



/* THING PAGE ------------------------------------------------------ */

.backlink {
  display: inline-block;
  padding: 11px 0;
  margin-bottom: 32px;
}

.media { margin: 0 0 32px; }

/* a run of photographs down the page: each one its own block, with
   the same gap the lead image already leaves beneath it */
.page > figure + figure,
.page > .prose + figure,
.page > figure + .prose { margin-top: 32px; }

.media > canvas,
.media > .placeholder,
.media > .stage {
  width: 100%;
}

/* same rule for the lead image: fill the column, but never upscale.
   Capped to the viewport height too, so a tall portrait shot never
   runs off the bottom of the screen. object-fit keeps it proportional
   once both max-width and max-height are constraining it at once —
   without it the browser stretches the image to fill that box. */
.media > img,
.media > video {
  max-width: 100%;
  max-height: 80vh;
  object-fit: contain;
}

.media > iframe {
  width: 100%;
  aspect-ratio: 16 / 9;
  height: auto;
}

/* stand-in until real media exists — delete when you swap in an <img> */
.placeholder {
  aspect-ratio: 3 / 2;
  display: grid;
  place-items: center;
  padding: 16px;
  text-align: center;
}

/* A track sitting under the photograph it belongs to: transport, a
   scrubber, the clock, and volume — all in the site's own furniture,
   1px rules and square handles. track.js drives it. */
.track {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 8px;
  font-size: 12px;
}

.track button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex: none;
  padding: 0;
  border: 1px solid #000;
  background: none;
  color: #000;
  cursor: pointer;
}
.track button:hover { background: #000; color: #fff; }
.track button svg { width: 10px; height: 12px; fill: currentColor; }
/* the reset makes every svg a block, which outranks the hidden attribute */
.track button svg[hidden] { display: none; }

.track input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  height: 20px;             /* a real grab target — the visible line is drawn
                               on the track below, not by the box itself */
  background: none;
  cursor: pointer;
  outline-offset: 4px;
}
.track input[type="range"]::-webkit-slider-runnable-track {
  height: 1px;
  background: #000;
}
.track input[type="range"]::-moz-range-track {
  height: 1px;
  background: #000;
}
.track input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 9px;
  height: 9px;
  margin-top: -4px;         /* centre the handle on the 1px line */
  background: #000;
  cursor: ew-resize;
}
.track input[type="range"]::-moz-range-thumb {
  width: 9px;
  height: 9px;
  border: 0;
  border-radius: 0;
  background: #000;
  cursor: ew-resize;
}

.track .seek { flex: 1 1 120px; min-width: 80px; }

/* Volume keeps to a speaker until it is wanted: the slider unrolls on
   hover, on keyboard focus, and on a press for touch, where there is no
   hover to rely on. */
.track .volume {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: none;
}
.track .volume button {
  width: 20px;
  height: 20px;
  border: 0;
  background: none;
}
.track .volume button:hover { background: none; color: #000; }
.track .volume .icon-vol { width: 12px; height: 12px; fill: currentColor; }

.track .vol {
  width: 0;
  opacity: 0;
  pointer-events: none;
  transition: width 120ms ease, opacity 120ms ease;
}
.track .volume:hover .vol,
.track .volume:focus-within .vol,
.track .volume.open .vol {
  width: 56px;
  opacity: 1;
  pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
  .track .vol { transition: none; }
}

.track .time {
  flex: none;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

figcaption {
  margin-top: 8px;
  max-width: 66ch;
  font-size: 14px;
}

.thing h1,
.essay h1 {
  font-size: 24px;
  font-weight: bold;
  line-height: 1.3;
  max-width: 30ch;
  margin: 0 0 8px;
}

/* the one line of what-it-is */
.dek {
  max-width: 66ch;
  margin: 0 0 32px;
  padding-bottom: 32px;
  border-bottom: 1px solid #000;
}


/* ESSAY ----------------------------------------------------------- */
/* One face on the whole site. Essays get a point more size and more
   leading than the drawer, which is what Courier Prime needs to hold a
   long piece at its lighter weight.

   On an essay the page IS the reading column: title, dateline, text
   and figures all share one left edge, and the column sits in
   the middle of the window instead of hugging the left of a wider
   page. Text stays ragged-right inside it; lines that are meant to be
   centred (.refrain, figures) still centre within the column. */
.page.essay { max-width: 69ch; }

.essay h1,
.essay .dek,
.essay .dateline,
.essay .prose,
.essay figcaption { max-width: none; }

/* On an essay the dateline closes the header block, so a dek above it is
   a line of type rather than the thing carrying the rule. Same handoff as
   .thing .dateline, the other way round. */
.essay .dek {
  margin: 0 0 8px;
  padding-bottom: 0;
  border-bottom: 0;
}

.essay .prose {
  font-size: 17px;
  line-height: 1.65;
}
.essay .prose > * + * { margin-top: 28px; }

/* a line that repeats to mark time — centred, standing apart from the
   paragraphs it interrupts */
.prose p.refrain { text-align: center; }

.dateline {
  margin: 0 0 32px;
  padding-bottom: 32px;
  border-bottom: 1px solid #000;
  font-size: 14px;
}

/* A thing's date sits between the title and the dek rather than
   carrying the rule itself. The dek keeps the rule, and the header
   block still closes with one line, not two — but only where there is
   a dek. Without one the date carries the rule, as on an essay. */
.thing .dateline:has(+ .dek) {
  margin: 0 0 8px;
  padding-bottom: 0;
  border-bottom: 0;
}

.prose code {
  font-family: var(--mono);
  background: #eee;
  padding: 0 0.3ch;
}

/* someone pasting a poem as a code block to hold the spacing —
   keep every space, and scroll rather than overflow the page */
.prose pre {
  font-family: var(--mono);
  white-space: pre;
  overflow-x: auto;
  border-left: 1px solid #000;
  padding-left: 2ch;
}

/* Concrete poetry keeps its own horizontal spacing, so it arrives as
   <pre> — but it is the writing, not a quotation, and carries no rule.
   Long lines still scroll inside their own block on a narrow screen. */
.prose pre.poem {
  border-left: 0;
  padding-left: 0;
}

.prose hr {
  border: 0;
  border-top: 1px solid #000;
}
.prose pre code { background: none; padding: 0; }


/* WRITING --------------------------------------------------------- */

.prose { max-width: 66ch; }

.prose > * + * { margin-top: 24px; }

.prose h2 {
  font-size: 16px;
  font-weight: bold;
  margin-top: 48px;
}

.prose ul, .prose ol { padding-left: 3ch; }

.prose blockquote {
  border-left: 1px solid #000;
  padding-left: 2ch;
}

/* The spacing rule above only reaches .prose's own children, so a
   quotation of more than one paragraph needs its own. */
.prose blockquote > * + * { margin-top: 24px; }

/* A quotation and its source. The attribution belongs to the quote, so
   it sits under the rule the blockquote carries rather than centred the
   way a caption under a picture is. */
.prose figure.quote figcaption {
  text-align: left;
  margin-left: 2ch;
  margin-right: 0;
}

.prose figure { margin: 32px 0; width: 100%; }

/* A figure that is a drawn mark rather than a picture: it keeps the size
   it was drawn at and sits in the middle of the column. */
.prose figure.glyph svg { margin: 0 auto; }

/* Never blow an image up past its own pixels. A small picture stays
   small — which matters when the size of the picture is the subject. */
.prose figure img,
.prose figure video {
  max-width: 100%;
  margin-left: auto;
  margin-right: auto;
}

.prose figcaption {
  text-align: center;
  font-size: 14px;
  margin-left: auto;
  margin-right: auto;
}

/* A cutout is a figure standing in the text, not a picture in a frame:
   small, sitting in the flow between paragraphs. */
.prose figure.cutout { width: 100%; }
.prose figure.cutout img { max-width: 110px; }


/* VIDEO ----------------------------------------------------------- */

.videos { margin-top: 48px; }

.video { margin: 0 0 48px; }

.video iframe {
  display: block;
  border: 0;
  width: 100%;
  aspect-ratio: 16 / 9;
  height: auto;
}

.video figcaption { text-align: left; margin-top: 8px; }


/* METADATA -------------------------------------------------------- */

.meta {
  margin-top: 64px;
  padding-top: 24px;
  border-top: 1px solid #000;
}

.meta dl {
  display: grid;
  grid-template-columns: 18ch 1fr;
  column-gap: 1ch;
  row-gap: 4px;
}

.meta dt { font-weight: bold; }
.meta dd { margin: 0; }
.meta dd ul { list-style: none; padding: 0; margin: 0; }
.meta dd a { display: inline-block; padding: 11px 0; }

@media (max-width: 34em) {
  .meta dl { grid-template-columns: 1fr; row-gap: 0; }
  .meta dd { margin-bottom: 16px; }
}


/* INTERACTIVE STAGE ----------------------------------------------- */
/* Only used on pages that run something. The page reads fine
   without it; this is the box the canvas lives in when there is one. */

.stage {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 2;
  touch-action: manipulation;
  overflow: hidden;
}
.stage > canvas { width: 100%; height: 100%; }

/* the tap-to-start button — audio never begins on its own */
.stage-start {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  min-height: 44px;
  font: inherit;
  color: #000;
  background: #fff;
  border: 0;
  cursor: pointer;
}


/* THE MAP ---------------------------------------------------------- */

/* the two links under the masthead, stacked as one block */
.asides { margin: 0 0 24px; }

.asides a {
  display: block;
  width: fit-content;
  padding: 11px 0;
}

.map-body {
  background: #07070a;
  overflow: hidden;
  overscroll-behavior: none;
}

.map-host {
  position: fixed;
  inset: 0;
  touch-action: none;         /* the canvas handles pan and zoom itself */
}

.map-chrome {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2;
  display: flex;
  align-items: baseline;
  gap: 24px;
  padding: 16px 24px;
  font-size: 14px;
  pointer-events: none;       /* the map is under here; only the controls take clicks */
}
.map-chrome > * { pointer-events: auto; }

.map-body .backlink,
.map-fit {
  margin: 0;
  padding: 0;
  color: #d4c9b0;
  background: none;
  border: 0;
  font: inherit;
  font-family: var(--mono);
  cursor: pointer;
  text-decoration: underline;
}
.map-body .backlink:hover,
.map-fit:hover { background: #d4c9b0; color: #07070a; }

/* Says what you are pointing at. Also the live region a screen reader
   hears, which is why it is text rather than a tooltip on the canvas. */
.map-status {
  color: #8a8478;
  pointer-events: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.map-hint {
  position: fixed;
  bottom: 16px;
  left: 24px;
  z-index: 2;
  font-size: 12px;
  color: #4a4740;
  pointer-events: none;
}

.map-body :focus-visible { outline-color: #d4c9b0; }


/* NARROW ---------------------------------------------------------- */

@media (max-width: 34em) {
  .page { padding: 32px 16px 64px; }
  .masthead { margin-bottom: 32px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

@media print {
  .skip, .backlink, .stage-start { display: none; }
}
