/* One family, browser-default colours. The page should look like 1996 until you look closer. */
:root {
  --bg: #ffffff;
  --ink: #000000;
  --soft: #555555;
  --link: #0000ee;
  --visited: #551a8b;
  --field: #c0c0c0;
  --panel: #f0f0f0;
  --col: 600px;
  --left: max(20px, 20vw);
  --face: "Times New Roman", Times, "Liberation Serif", "Nimbus Roman", serif;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 20px/1.5 var(--face);
}

a { color: var(--link); }
a:visited { color: var(--visited); }
a:hover { text-decoration-thickness: 2px; }
a:active { color: #ee0000; }
:focus-visible { outline: 3px solid var(--link); outline-offset: 2px; }
/* A heading given focus after a page swap (for screen readers) is not something to point at. */
main h1[tabindex="-1"]:focus { outline: none; }
::selection { background: var(--link); color: #fff; }

nav, main, footer { padding-left: var(--left); padding-right: 20px; }
main > *, footer > * { max-width: var(--col); }
nav { padding-top: 20px; }
nav b { font-weight: bold; }

h1 {
  font-size: clamp(48px, 7vw, 104px);
  line-height: 0.92;
  letter-spacing: -0.03em;
  margin: 18vh 0 28px;
  max-width: none;
}
h1.post-title { font-size: clamp(32px, 3.4vw, 48px); line-height: 1.05; letter-spacing: -0.01em; margin-top: 64px; max-width: 760px; }
h2 { font-size: 32px; line-height: 1.1; margin: 120px 0 20px; }
h3 { font-size: 24px; line-height: 1.2; margin: 48px 0 8px; }
p { margin: 0 0 20px; }
.lead { font-size: 30px; line-height: 1.3; max-width: 640px; }
.soft, figcaption { color: var(--soft); font-size: 16px; }

figure { margin: 64px 0; }
figure img { display: block; width: 100%; height: auto; }
figure.wide { max-width: min(1000px, 100%); }
main > figure.wide { max-width: 1000px; }
figcaption { margin-top: 10px; }

pre { background: var(--panel); padding: 16px; overflow-x: auto; font-size: 15px; line-height: 1.45; max-width: 760px; }
code { font-size: 0.85em; }
pre code { font-size: inherit; }
ul, ol { padding-left: 28px; }
li { margin-bottom: 8px; }

.sign { font-style: italic; font-size: 24px; margin: 32px 0 0; }

/* ---- Footer ---- */
footer { margin-top: 160px; padding-bottom: 64px; font-size: 16px; }
footer p { margin-bottom: 10px; }

/* ---- Blog list ---- */
.find { display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap; margin: 40px 0 8px; }
.find input { font: inherit; font-size: 18px; padding: 4px 6px; width: 260px; max-width: 100%; }
.posts { list-style: none; padding: 0; margin: 0; }
.posts .year { color: var(--soft); margin: 40px 0 6px; }
.posts li.post { display: flex; justify-content: space-between; gap: 24px; align-items: baseline; padding: 5px 0; margin: 0; }
.posts li.post time { color: var(--soft); font-size: 16px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.posts li.post a:focus-visible { outline-offset: 4px; }
.posts li[hidden] { display: none; }
.keys { margin-top: 24px; }
kbd { font-family: var(--face); font-size: 16px; background: var(--panel); padding: 1px 6px; }

/* ---- Contact ---- */
.clock { font-size: 26px; line-height: 1.35; }
form.letter { margin: 40px 0; background: var(--panel); padding: 28px; }
form.letter label { display: block; font-size: 18px; margin: 0 0 4px; }
form.letter select, form.letter textarea { font: inherit; font-size: 18px; width: 100%; margin-bottom: 20px; padding: 6px; }
form.letter textarea { min-height: 140px; }
button, .button {
  font: inherit; font-size: 18px; cursor: pointer;
  background: var(--link); color: #fff; border: 0; border-radius: 0;
  padding: 10px 20px; text-decoration: none; display: inline-block;
  transition: transform 120ms ease;
}
.button:visited { color: #fff; }
button:hover, .button:hover { background: #0000b8; }
button:active, .button:active { transform: translateY(1px); }

/* ---- CV: the one page that got a stylesheet ---- */
body.cv { background: var(--field); }
body.cv nav, body.cv footer { color: var(--ink); }
.sheet {
  background: #fff;
  max-width: 820px;
  margin: 48px 0 0;
  padding: 72px 72px 80px;
}
body.cv main > .sheet { max-width: 820px; }
.sheet h1 { margin: 0 0 12px; font-size: clamp(48px, 6.4vw, 92px); }
.sheet .role { font-size: 26px; margin: 0 0 6px; }
.sheet h2 { font-size: 26px; margin: 72px 0 16px; }
/* One column per month, always one row; the years sit under their Januaries. */
.uptime { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); column-gap: 2px; margin: 40px 0 12px; }
.uptime .m { grid-row: 1; height: 40px; }
.uptime .y { grid-row: 2; font-size: 14px; color: var(--soft); border-left: 2px solid var(--ink); padding: 6px 0 0 4px; margin-top: 4px; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* The three colours of a 1996 link: visited, unvisited, being clicked. */
.dv { background: var(--visited); }
.is { background: var(--link); }
.pc { background: #ee0000; }
.uptime-key { font-size: 16px; display: flex; gap: 8px 20px; flex-wrap: wrap; align-items: center; margin: 0 0 4px; }
.uptime-key > span { white-space: nowrap; }
.uptime-key .k { display: inline-block; width: 14px; height: 14px; margin-right: 6px; vertical-align: -1px; }
.ledger { list-style: none; padding: 0; margin: 0; }
.ledger > li { display: grid; grid-template-columns: 1fr 120px; gap: 8px 24px; margin: 0 0 32px; }
.ledger .when { text-align: right; color: var(--soft); font-size: 16px; font-variant-numeric: tabular-nums; padding-top: 4px; }
.ledger .what { font-weight: bold; }
.ledger .where { color: var(--soft); font-weight: normal; }
.ledger ul { grid-column: 1 / -1; margin: 0; font-size: 18px; }
.skills { display: grid; grid-template-columns: 190px 1fr; gap: 10px 24px; font-size: 18px; margin: 0; }
.skills dt { font-weight: bold; }
.skills dd { margin: 0; }
.sample { background: #ffff66; padding: 0 3px; }
.print { margin: 32px 0 0; }

/* ---- Rack ---- */
.stack { list-style: none; padding: 0; }
.stack li { background: var(--panel); padding: 14px 18px; margin: 0 0 6px; display: flex; justify-content: space-between; gap: 16px; }
.stack li span { color: var(--soft); font-size: 16px; text-align: right; }

@media (max-width: 640px) {
  :root { --left: 20px; }
  body { font-size: 18px; }
  h1 { margin-top: 12vh; }
  h2 { margin-top: 88px; }
  .lead, .clock { font-size: 22px; }
  .sheet { padding: 32px 20px 48px; margin-top: 24px; }
  body.cv main { padding-left: 0; padding-right: 0; }
  .uptime { column-gap: 1px; }
  .uptime .m { height: 32px; }
  .uptime .y { font-size: 13px; padding-left: 3px; }
  .ledger > li { grid-template-columns: 1fr; }
  .ledger .when { text-align: left; padding: 0; }
  .skills { grid-template-columns: 1fr; gap: 2px; }
  .skills dd { margin-bottom: 12px; }
  .posts li.post { flex-direction: column; gap: 0; padding: 8px 0; }
  form.letter { padding: 20px; }
}

@media (prefers-reduced-motion: reduce) {
  button, .button { transition: none; }
}

@media print {
  body.cv { background: #fff; font-size: 11pt; }
  nav, footer, .print, .no-print { display: none !important; }
  body.cv main { padding: 0; }
  .sheet { padding: 0; margin: 0; max-width: none; }
  .sheet h1 { font-size: 40pt; }
  .sheet h2 { margin-top: 24pt; font-size: 15pt; }
  .uptime .m, .uptime .y, .uptime-key .k, .sample { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  a { color: #000; }
}

/* ---- Motion: things arrive the way they did on a 1996 modem, just quicker ---- */
.js .rise { opacity: 0; transform: translateY(20px); }
.js .rise.in { opacity: 1; transform: none; transition: opacity 500ms ease, transform 600ms cubic-bezier(.2,.7,.2,1); transition-delay: var(--d, 0ms); }
.load { display: block; position: relative; overflow: hidden; }
.load::after {
  content: ""; position: absolute; inset: 0; background: var(--bg);
  transform-origin: bottom; transform: scaleY(1);
}
body.cv .load::after { background: #fff; }
.in .load::after { transform: scaleY(0); transition: transform 900ms steps(12, end) 150ms; }
.posts li.post a { transition: padding 160ms ease; }
@media (prefers-reduced-motion: reduce) {
  .js .rise { opacity: 1; transform: none; }
  .js .rise.in { transition: none; }
  .load::after { display: none; }
}

/* ---- Player: top right, in the same plain language as the nav ---- */
#player {
  --pl-ground: var(--bg); --pl-track: var(--panel); --now: #ee0000;
  --big: min(400px, calc(100vw - 48px), calc(100svh - 200px));
  position: absolute; top: 14px; right: 24px; z-index: 5;
  display: flex; align-items: center; gap: 14px;
  font-size: 18px; max-width: min(460px, 46vw);
}
body.cv #player { --pl-ground: var(--field); }
body.photos #player { --now: var(--mark); }
#player button { font: inherit; cursor: pointer; }
#player .play .i-pause, #player.playing .play .i-play { display: none; }
#player.playing .play .i-pause { display: inline; }
#player .name { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--ink); text-decoration: none; }
#player .name:hover { text-decoration: underline; }
#player .play, #player .skip, #player .mute {
  flex: none; width: 44px; height: 44px; padding: 0; display: grid; place-items: center;
  background: transparent; color: var(--ink); border: 0;
}
#player .play svg, #player .skip svg { fill: var(--ink); }
#player .play:hover:not(:disabled), #player .skip:hover:not(:disabled), #player .mute:hover { background: var(--panel); }
#player button:disabled { cursor: default; opacity: 0.45; }
#player button:active:not(:disabled) { transform: translateY(1px); }

/* The cover is the button that opens the player. Without art it is drawn from the song (see site.js). */
#player .cover {
  flex: none; width: 44px; height: 44px; padding: 0; border: 0;
  background: var(--panel) center / cover no-repeat; cursor: zoom-in; transition: none;
}
#player .cover:hover { background-color: var(--panel); }
#player .cover:active:not(:disabled) { transform: none; }
#player .cover canvas { display: block; width: 100%; height: 100%; }
body.cv #player .cover { background-color: #fff; }

/* Open: the cover at full size, the seek bar under it, the controls under that, on a step of tone. */
#player.open, body.cv #player.open { --pl-ground: var(--panel); --pl-track: var(--bg); }
#player.open {
  display: grid; grid-template-columns: 44px minmax(0, 1fr) auto 44px; column-gap: 14px; align-items: center;
  top: 0; right: 8px; width: calc(var(--big) + 32px); max-width: none; padding: 14px 16px 10px;
  background: var(--panel);
}
#player.open .cover, body.cv #player.open .cover { grid-column: 1 / -1; width: var(--big); height: var(--big); background-color: var(--bg); cursor: zoom-out; }
/* With art, the open cover takes the picture's own shape, kept whole inside the height there is. */
#player .cover img { display: none; }
#player.open .cover.art, body.cv #player.open .cover.art { height: auto; aspect-ratio: var(--ar, 1); max-height: calc(100svh - 160px); background-image: none !important; }
#player.open .cover.art img { display: block; width: 100%; height: 100%; object-fit: contain; }
#player.open .cover.art canvas { display: none; }
#player .seek { grid-column: 1 / -1; position: relative; margin-top: 8px; }
#player .seek .bar { position: absolute; left: 0; right: 0; top: 19px; height: 6px; background: var(--pl-track); }
#player .seek .fill { display: block; height: 100%; background: var(--visited); transform-origin: left; transform: scaleX(0); }
#player .times { display: flex; justify-content: space-between; font-size: 16px; color: var(--soft); font-variant-numeric: tabular-nums; margin-top: -6px; }

/* Both sliders are real range inputs: a block of track and an upright tick for the thumb. */
#player :where(input[type=range]) {
  -webkit-appearance: none; appearance: none; display: block; width: 100%; height: 44px; margin: 0;
  background: transparent; cursor: pointer; position: relative;
}
#player :where(input[type=range])::-webkit-slider-runnable-track { height: 6px; background: transparent; }
#player :where(input[type=range])::-moz-range-track { height: 6px; background: transparent; }
#player :where(input[type=range])::-webkit-slider-thumb { -webkit-appearance: none; width: 6px; height: 24px; margin-top: -9px; border: 0; border-radius: 0; background: var(--now); }
#player :where(input[type=range])::-moz-range-thumb { width: 6px; height: 24px; border: 0; border-radius: 0; background: var(--now); }

/* Volume: an icon that opens into a slider to its left, over the song's name. */
#player .vol { position: relative; flex: none; }
#player .mute svg { fill: none; stroke: var(--ink); stroke-width: 2; }
#player .mute .spk { fill: var(--ink); stroke: none; }
#player .vol .x, #player .vol[data-level=off] .w1, #player .vol[data-level=off] .w2, #player .vol[data-level=low] .w2 { display: none; }
#player .vol[data-level=off] .x { display: inline; }
#player .level {
  position: absolute; right: 100%; top: 0; width: 140px; padding: 0 12px; background: var(--pl-ground);
  opacity: 0; clip-path: inset(0 0 0 100%); pointer-events: none;
  transition: opacity 180ms ease, clip-path 240ms cubic-bezier(0.22, 1, 0.36, 1);
}
#player .level::-webkit-slider-runnable-track { background: var(--pl-track); }
#player .level::-moz-range-track { background: var(--pl-track); }
#player .level::-webkit-slider-thumb { background: var(--ink); }
#player .level::-moz-range-thumb { background: var(--ink); }
#player .vol:has(:focus-visible) .level, #player .vol.open .level { opacity: 1; clip-path: inset(0); pointer-events: auto; }
@media (hover: hover) { #player .vol:hover .level { opacity: 1; clip-path: inset(0); pointer-events: auto; } }
#player.fixed-volume .level { display: none; }
@media (prefers-reduced-motion: reduce) {
  #player .level { transition: opacity 180ms ease; }
}

/* ---- Music and photos ---- */
.tracklist { padding-left: 32px; margin: 40px 0; }
.tracklist li { margin: 0 0 6px; }
.tracklist button { font: inherit; background: none; border: 0; padding: 4px 0; color: var(--link); text-decoration: underline; cursor: pointer; text-align: left; }
.tracklist li.now button { color: var(--ink); font-weight: bold; text-decoration: none; }
.tracklist li.now::after { content: " (playing)"; color: var(--soft); font-size: 16px; }
/* ---- Photos: a darkroom page. The set is its contact sheet, the chosen frames come out as full-screen prints,
   and the footer is the back of a print. Colours come from the pictures: film black, paper white, the ferry's fire-box red. */
body.photos {
  --bg: #141414; --surface: #1f1f1f; --ink: #f2f2f2; --soft: #a3a3a3; --panel: #262626;
  --paper: #f5f4f1; --paper-ink: #141414; --film: #0b0b0b; --mark: #e0261b;
  --link: #f2f2f2; --visited: #d0c4ee;
  background: var(--bg); color: var(--ink);
}
body.photos a:active { color: var(--mark); }
body.photos ::selection { background: var(--mark); color: #fff; }
body.photos :focus-visible { outline-color: var(--mark); }
body.photos main { padding: 0; position: relative; z-index: 1; background: var(--bg); }
body.photos main > * { max-width: none; }
body.photos nav { position: relative; z-index: 2; }

.set .field { padding: 0 20px; display: flex; justify-content: center; }
.contact {
  background: var(--paper); color: var(--paper-ink);
  width: min(720px, 100%); margin-top: 120px; padding: 56px 56px 64px;
}
.contact a { color: var(--paper-ink); }
.contact .title { font-style: italic; font-weight: bold; font-size: clamp(56px, 5.6vw, 88px); line-height: 0.95; letter-spacing: -0.03em; margin: 0 0 28px; text-align: center; }
.contact .title span { display: block; }
.contact .title span:first-child { transform: translateX(-12%); }
.contact .title span:last-child { transform: translateX(16%); }
.facts { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 6px 14px; font-size: 16px; margin: 0 0 44px; text-align: center; }
.facts i { width: 8px; height: 8px; background: var(--mark); transform: rotate(45deg); flex: none; }

/* The roll: strips of six frames on film, with the paper showing between strips. */
.roll { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(6, 1fr); row-gap: 14px; }
.roll li { margin: 0; background: var(--film); padding: 9px 4px 4px; display: flex; flex-direction: column; align-items: stretch; }
.roll .slot, .roll img { display: block; width: 100%; aspect-ratio: 3 / 2; height: auto; background: #202020; }
.roll .n { color: #b9b9b9; font-size: 13px; line-height: 1; padding: 5px 0 2px; text-align: center; font-variant-numeric: tabular-nums; }
.roll .printed { position: relative; }
.roll .printed a { display: block; position: relative; }
/* The grease-pencil mark a photographer puts round the frames to print. */
.roll .printed a::after { content: ""; position: absolute; inset: -5px; border: 3px solid var(--mark); border-radius: 3px; transform: rotate(-1.5deg); pointer-events: none; }
.roll .printed .n { color: #fff; font-weight: bold; }
.roll .printed a:hover img { opacity: 0.85; }

/* The interlock: a tipped-in note pulled down over the first print's top edge. */
.interlock { position: relative; z-index: 2; width: 240px; margin: -120px 0 -16px calc(50% + 380px); padding: 16px 18px; background: var(--bg); font-size: 16px; line-height: 1.5; }

/* The prints: one screen each; the next slides up over the last. */
.prints { position: relative; }
.print { position: sticky; top: 0; height: 100svh; margin: 0; background: var(--film); overflow: hidden; }
.print .open, .print .load, .print picture { display: block; height: 100%; }
.print img { width: 100%; height: 100%; object-fit: cover; }
@media (min-aspect-ratio: 9/5), (max-aspect-ratio: 13/10) { .print img { object-fit: contain; } }
.print figcaption {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 72px max(28px, calc(100% - 860px)) 22px 28px; font-size: 18px; color: #fff; max-width: none;
  background: linear-gradient(to top, rgb(0 0 0 / 0.72), rgb(0 0 0 / 0)); /* neutral scrim over a photo: taste-skill-ignore */
}
.print .frame { color: #fff; font-weight: bold; }
.print .exif { color: #d6d6d6; font-size: 16px; white-space: nowrap; }
.print .load::after { background: var(--film); }
@media (prefers-reduced-motion: no-preference) {
  .js .print.in img { animation: drift 24s ease-out both; }
  @keyframes drift { from { transform: scale(1.06); } to { transform: scale(1); } }
}

/* The back of the print. */
body.photos footer { margin: 0; padding: 120px 20px 20px; background: var(--bg); }
body.photos footer > * { max-width: none; }
.back {
  background: var(--paper); color: var(--paper-ink); max-width: 1100px; margin: 0 auto;
  display: grid; grid-template-columns: 1fr 300px; gap: 32px 56px; padding: 72px 56px 28px; position: relative;
  /* Deckle edge along the top, the way old prints were cut: a row of bites, drawn once and repeated. */
  --deckle: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='4000'%3E%3Cpath d='M0 0H0A24 24 0 0 0 48 0V4000H0Z'/%3E%3C/svg%3E");
  -webkit-mask: var(--deckle) 0 0 / 48px 4000px repeat-x;
          mask: var(--deckle) 0 0 / 48px 4000px repeat-x;
}
.back a { color: #0000ee; }
.back a:visited { color: #551a8b; }
.back .note p { font-size: 18px; }
.back .address { position: relative; padding-top: 112px; font-size: 18px; line-height: 1.75; }
.back .stamp { position: absolute; top: 0; right: 0; width: 120px; height: 90px; object-fit: cover; object-position: 50% 92%; border: 6px solid var(--paper); outline: 4px dotted #b7b4ad; outline-offset: -2px; }
.back .imprint { grid-column: 1 / -1; font-size: 16px; color: var(--paper-ink); padding-top: 24px; }
.back .imprint > p { max-width: 640px; }
.back .imprint p { margin-bottom: 6px; }

@media (max-width: 1240px) {
  .interlock { margin: -48px 20px -40px auto; }
}
@media (max-width: 900px) {
  .contact .title span { transform: none !important; }
}
@media (max-width: 640px) {
  .contact { margin-top: 40px; padding: 36px 16px 20px; }
  .contact .title { font-size: 12vw; }
  .contact .title span { transform: none !important; }
  .roll { grid-template-columns: repeat(4, 1fr); row-gap: 10px; }
  .roll .n { font-size: 13px; }
  .interlock { width: auto; margin: 32px 20px 24px; padding: 0; }
}
@media (max-width: 640px) {
  .print { height: auto; }
  .print img { height: auto; object-fit: contain; }
  .print figcaption { position: static; background: var(--film); padding: 12px 20px 28px; font-size: 16px; }
  .print .exif { white-space: normal; }
  body.photos footer { padding: 72px 0 0; }
  .back { grid-template-columns: 1fr; padding: 56px 20px 20px; gap: 8px; }
  .back .address { padding-top: 0; }
  .back .stamp { position: static; width: 96px; height: 72px; margin-bottom: 12px; }
}

/* ---- Dumps: the archive box. Every export folder is a sleeve whose strips are as long as the roll really is;
   on a dump's page the box's tabs run down the sheet's left edge, and the one pulled out is the sheet itself. */
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.roll .slot, .roll img, .strip img, .strip .slot { object-fit: cover; }
.print.tall img { object-fit: contain; }
.print .frame a { color: #fff; }

/* The box, on photos.html: one wide sheet listing every sleeve, grouped by year. */
.contact.box { width: min(1120px, 100%); }
.shelf { margin-top: 64px; }
.shelf .year { font-size: 40px; line-height: 1; letter-spacing: -0.02em; margin: 0 0 20px; }
.sleeves { list-style: none; padding: 0; margin: 0; }
.sleeve { display: grid; grid-template-columns: 280px 1fr; gap: 12px 40px; margin: 0 0 36px; align-items: start; }
.sleeve .label { display: block; margin: 0; line-height: 1.3; text-decoration: none; }
.sleeve .label span { display: block; font-size: 16px; }
.sleeve .label .place { font-size: 32px; line-height: 1.05; font-style: italic; font-weight: bold; letter-spacing: -0.02em; margin-bottom: 6px; }
.sleeve a.label .place { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 0.12em; }
.sleeve.sealed .label { color: #5f5e5a; }
.sleeve.sealed .label .place { font-weight: normal; }
.strips { display: grid; gap: 8px; }
.strip { background: var(--film); padding: 6px 6px 4px; }
.strip .edge { color: #b9b9b9; font-size: 13px; line-height: 1; margin: 2px 2px 6px; }
.strip ol { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(40px, 1fr)); gap: 6px 4px; }
.strip li { margin: 0; display: flex; flex-direction: column; }
.strip .slot, .strip img { display: block; width: 100%; aspect-ratio: 3 / 2; height: auto; background: #202020; }
.strip .n { color: #9a9a9a; font-size: 13px; line-height: 1; padding-top: 3px; text-align: center; font-variant-numeric: tabular-nums; }
.strip .printed a { display: block; position: relative; }
.strip .printed a::after { content: ""; position: absolute; inset: -4px; border: 3px solid var(--mark); border-radius: 3px; transform: rotate(-2deg); pointer-events: none; }
.strip .printed .n { color: #fff; font-weight: bold; }
.sealed .strip { background: #2b2b2b; }

/* Rolls on a dump's contact sheet. */
.roll-name { font-size: 18px; line-height: 1.3; margin: 32px 0 10px; }
.contact .facts + .roll-name { margin-top: 0; }
.roll-name span { font-weight: normal; color: #5f5e5a; }

/* The tabs, on a dump's page. */
.tabs { font-size: 16px; }
.tabs .all { margin: 0 0 12px; }
.tabs .all a { color: var(--ink); }
.tabs ol { list-style: none; padding: 0; margin: 0; }
.tabs li { margin: 0 0 4px; }
.tabs li > a, .tabs li > span { position: relative; display: grid; grid-template-columns: 1fr auto; align-items: baseline; gap: 4px 12px; padding: 10px 16px 10px 14px; min-height: 44px; background: var(--surface); color: var(--ink); text-decoration: none; }
.tabs .place { font-size: 18px; font-style: italic; font-weight: bold; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tabs .yr { display: none; }
.tabs .n { color: var(--soft); font-variant-numeric: tabular-nums; }
.tabs .bar { grid-column: 1 / -1; position: relative; display: block; height: 6px; width: calc(var(--w) * 100%); min-width: 12px; background: #3a3a3a; }
.tabs .bar i { position: absolute; top: 0; bottom: 0; left: var(--at); width: 3px; margin-left: -1px; background: var(--mark); }
.tabs .sealed > span { color: var(--soft); background: transparent; }
.tabs .sealed .place { font-weight: normal; }
.tabs .here > a { background: var(--paper); color: var(--paper-ink); }
.tabs .here .n { color: #5f5e5a; }
.tabs .here .bar { background: #c9c7c1; }
.tabs li > a { transition: background-color var(--t-hover, 180ms) ease, transform 140ms cubic-bezier(.22,1,.36,1); }
@media (hover: hover) and (pointer: fine) {
  .tabs li:not(.here) > a:hover { background: #2c2c2c; }
  .tabs li:not(.here) > a:hover .place, .sleeve a.label:hover .place { text-decoration-thickness: 4px; }
  .tabs li:not(.here) > a:hover .place { text-decoration: underline; text-decoration-thickness: 2px; }
}
.tabs li > a:active { transform: translateX(-2px); }

/* A row of tabs that scrolls sideways is the default; a dump page can put it anywhere. */
.tabs ol { display: flex; gap: 4px; overflow-x: auto; scroll-snap-type: x proximity; scrollbar-width: none; }
.tabs ol::-webkit-scrollbar { display: none; }
.tabs li { flex: none; width: 168px; margin: 0; scroll-snap-align: start; }
.tabs li > a, .tabs li > span { height: 100%; }
.tabs .here > a { padding-bottom: 14px; }
.set .field > .tabs { width: min(720px, 100%); margin-top: 64px; }
.tabs + .contact { margin-top: 0; }
@media (max-width: 1099px) { .set:not(.archive) .field { flex-direction: column; align-items: center; } }
/* Inside the kit's field on a wide screen, the tabs hang down the left of the sheet like index cards. */
@media (min-width: 1100px) {
  .set:not(.archive) .field { display: grid; grid-template-columns: 1fr min(720px, 100%) 1fr; align-items: start; }
  .set:not(.archive) .contact { grid-column: 2; }
  .set .field > .tabs { grid-column: 1; grid-row: 1; justify-self: end; width: min(270px, 100%); margin-top: 176px; }
  .field > .tabs .all { padding-right: 16px; text-align: right; }
  .field > .tabs ol { display: block; overflow: visible; }
  .field > .tabs li { width: auto; margin: 0 14px 4px 0; }
  .field > .tabs li.here { margin-right: 0; }
  .field > .tabs .here > a { padding-bottom: 10px; }
}

/* The stub after a dump's prints: tear it off for the next sleeve. */
.stub { background: var(--paper); color: var(--paper-ink); width: min(720px, calc(100% - 40px)); margin: 120px auto 0; padding: 40px 48px 32px; border-top: 8px dotted var(--bg); }
.stub a { color: var(--paper-ink); }
.stub .next { font-size: 32px; line-height: 1.15; font-style: italic; font-weight: bold; letter-spacing: -0.02em; margin-bottom: 20px; }
.stub p:last-child { font-size: 18px; margin: 0; }

@media (max-width: 1240px) { .contact.box { padding-left: 40px; padding-right: 40px; } }
@media (max-width: 900px) {
  .sleeve { grid-template-columns: 1fr; }
  .sleeve .label { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 12px; }
  .sleeve .label .place { width: 100%; }
}
@media (max-width: 640px) {
  .contact.box { padding: 36px 14px 20px; }
  .shelf { margin-top: 40px; }
  .shelf .year { font-size: 32px; margin-bottom: 14px; }
  .sleeve { margin-bottom: 28px; gap: 8px; }
  .sleeve .label .place { font-size: 28px; }
  .strip ol { grid-template-columns: repeat(auto-fill, minmax(36px, 1fr)); }
  .set .field > .tabs { margin-top: 24px; width: 100%; }
  .tabs .all { margin-left: 0; }
  .tabs li { width: 148px; }
  .stub { width: auto; margin: 72px 20px 0; padding: 28px 20px 24px; }
  .stub .next { font-size: 24px; }
}

/* The grease pencil lands on each printed frame as its strip arrives. */
@media (prefers-reduced-motion: no-preference) {
  .js .rise .printed a::after { opacity: 0; transform: rotate(-9deg) scale(1.25); }
  .js .rise.in .printed a::after { opacity: 1; transform: rotate(-2deg); transition: opacity 260ms ease, transform 420ms cubic-bezier(.22,1,.36,1); transition-delay: calc(var(--d, 0ms) + 380ms); }
  .js .tabs .rise { transform: translateX(-18px); }
  .js .tabs .rise.in { transform: none; }
}

/* The viewer: a plain white page with one picture on it. */
.viewer { border: 0; padding: 0; margin: 0; width: 100vw; height: 100dvh; max-width: none; max-height: none; background: var(--bg); color: var(--ink); }
.viewer::backdrop { background: var(--bg); }
.viewer[open] { display: flex; flex-direction: column; justify-content: center; padding: 20px; }
.viewer figure { margin: 0; display: flex; flex-direction: column; align-items: center; min-height: 0; }
html:has(.viewer[open]) { overflow: hidden; }
.viewer .touch { display: none; }
@media (pointer: coarse) { .viewer .mouse { display: none; } .viewer .touch { display: inline; } }
.viewer img { max-width: 100%; max-height: calc(100dvh - 150px); width: auto; height: auto; object-fit: contain; cursor: pointer; }
.viewer figcaption { margin-top: 12px; font-size: 18px; color: var(--ink); max-width: 1000px; text-align: center; }
.viewer .where { color: var(--soft); }
.viewer .keys { text-align: center; margin: 8px 0 0; font-size: 18px; }
.viewer .keys button { font: inherit; background: none; color: var(--link); text-decoration: underline; padding: 6px 8px; }
.viewer .keys button:hover { background: var(--panel); }

/* The day grid: one part of a dump (a day) as a large grid on a plain page. Rows keep each picture whole: every cell grows
   in proportion to its picture's width, so a row shares one height; the last row is not stretched. */
.daygrid { border: 0; margin: 0; padding: 0 20px 48px; width: 100vw; height: 100dvh; max-width: none; max-height: none; overflow-y: auto; background: var(--bg); color: var(--ink); }
.daygrid::backdrop { background: var(--bg); }
html:has(.daygrid[open]) { overflow: hidden; }
.daygrid .top { position: sticky; top: 0; z-index: 1; display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 16px 0 8px; background: var(--bg); }
.daygrid h2 { outline: 0; margin: 0; font-size: clamp(28px, 3.6vw, 52px); line-height: 1.05; letter-spacing: -0.02em; }
.daygrid button { font: inherit; font-size: 18px; min-height: 44px; padding: 6px 10px; background: none; color: var(--link); text-decoration: underline; cursor: pointer; }
.daygrid button:hover { background: var(--panel); }
.daygrid .parts { list-style: none; margin: 0 0 20px -10px; padding: 0; display: flex; flex-wrap: wrap; }
.daygrid .parts [aria-current] { color: var(--ink); text-decoration: none; font-weight: bold; }
.daygrid .grid { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 12px; }
.daygrid .grid::after { content: ""; flex: 1000 1 0; }
.daygrid .grid li { flex: var(--r) 1 calc(var(--r) * 320px); margin: 0; }
.daygrid .grid a { display: block; }
.daygrid .grid img { display: block; width: 100%; height: auto; transition: opacity 200ms ease; }
.daygrid .grid a:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; }
@media (hover: hover) and (pointer: fine) { .daygrid .grid a:hover img { opacity: 0.85; } }
@media (max-width: 640px) {
  .daygrid { padding: 0 8px 32px; }
  .daygrid .top { padding-top: 8px; }
  .daygrid .grid { gap: 6px; }
  .daygrid .grid li { flex-basis: calc(var(--r) * 150px); }
}

/* ---- Back to the top: a small square in the bottom right corner, in the page's link colour, ringed in its ground so it
   shows on black too. Hidden until the page has been scrolled most of a screen down. */
#top {
  position: fixed; z-index: 6; right: calc(16px + env(safe-area-inset-right)); bottom: calc(16px + env(safe-area-inset-bottom));
  width: 44px; height: 44px; padding: 0; display: grid; place-items: center;
  background: var(--link); color: var(--bg); border: 2px solid var(--bg);
  opacity: 0; visibility: hidden; translate: 0 8px;
  transition: opacity 200ms ease, translate 200ms ease, visibility 0s linear 200ms;
}
#top svg { fill: currentColor; }
#top.on { opacity: 1; visibility: visible; translate: none; transition: opacity 200ms ease, translate 200ms ease; }
#top:hover { background: var(--link); opacity: 0.85; }
#top:active { translate: 0 1px; }
@media (prefers-reduced-motion: reduce) { #top, #top.on { translate: none; transition: none; } }

@media (max-width: 900px) {
  #player { position: static; max-width: none; margin: 0; padding: 12px 20px 0; }
  #player.open { width: auto; padding: 12px 20px 8px; --big: min(calc(100vw - 40px), 520px, calc(100svh - 220px)); }
  #player.open .cover.art { max-height: calc(100svh - 150px); }
}
