/* DirtyHarry26 site styles. Black and yellow, heavy condensed type, rounded squares, map contours and smoke behind everything.
   Phone first: base rules are for 390 wide, checked at 360. Fonts are open licence: see fonts/OFL-*.txt. */

a, button, label { touch-action: manipulation; }

@font-face {
  font-family: "Anton";
  src: url("fonts/Anton-Regular.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "Barlow";
  src: url("fonts/Barlow-Regular.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "Barlow Condensed";
  src: url("fonts/BarlowCondensed-SemiBold.woff2") format("woff2");
  font-weight: 600;
  font-display: swap;
}

:root {
  --yellow: #FFD000;
  --red: #E3000F; /* One accent: the red lines and the "!". Nothing else. */
  --bg: #0B0C0D;
  --black: #000000;
  --panel: #24272A;
  --raised: #30343A;
  --white: #FFFFFF;
  --text: #CDD1D5;
  --muted: #AEB4BA;
  --line: rgba(255, 255, 255, 0.16);
  --scrim: rgba(0, 0, 0, 0.55); /* Behind headings that sit on the smoke, strong enough for AA at the smoke's brightest. */

  --display: "Anton", Impact, "Arial Narrow", sans-serif;
  --body: "Barlow", system-ui, -apple-system, "Segoe UI", sans-serif;
  --label: "Barlow Condensed", "Arial Narrow", system-ui, sans-serif;

  --r: 10px; /* Buttons and inputs. */
  --r-card: 14px; /* Cards and panels. */
  --fade: 12px;
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --gutter-l: max(16px, env(safe-area-inset-left, 0px));
  --gutter-r: max(16px, env(safe-area-inset-right, 0px));
  --header-h: calc(52px + var(--safe-top));
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);

  color-scheme: dark;
}

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

html {
  -webkit-tap-highlight-color: transparent; /* Every control has its own press state, so the grey iOS flash only adds noise. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  background: var(--bg);
  scroll-padding-top: var(--header-h);
}

body {
  margin: 0;
  background: var(--bg) url("contour.svg") center top / 1400px repeat; /* Scrolls with the page, under the smoke. Costs no repaint. */
  color: var(--text);
  font: 400 1.0625rem/1.55 var(--body);
  font-variant-numeric: tabular-nums;
}

h1, h2, h3 { margin: 0; color: var(--white); font-family: var(--display); font-weight: 400; line-height: 1.1; letter-spacing: 0.01em; }
h2 { font-size: 2rem; }
h3 { font-size: 1.25rem; }
p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
b, strong { font-family: var(--label); font-weight: 600; }

a { color: var(--yellow); }

:focus-visible { outline: 2px solid var(--yellow); outline-offset: 2px; }

.skip-link {
  position: absolute;
  top: -100px;
  left: 16px;
  z-index: 40;
  padding: 12px 16px;
  border-radius: var(--r);
  background: var(--white);
  color: var(--black);
}
.skip-link:focus { top: 8px; }

.sr-only {
  position: absolute;
  background: var(--bg);
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- Smoke: one small image repeated sideways in three layers, behind everything, on every page.
   Each layer is one tile wider than the screen, so moving it by a whole tile cannot be seen.
   100vh, not 100%: it must not resize as a phone's address bar comes and goes. ---------- */

.smoke {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 0;
  width: 100%;
  height: 100vh;
  overflow: hidden;
  pointer-events: none;
  contain: strict;
}
.smoke__layer {
  --tile: 150vw;
  position: absolute;
  left: 0;
  width: calc(100vw + var(--tile));
  background: url("smoke.webp") 0 0 / var(--tile) 100% repeat-x;
  will-change: transform; /* smoke.js moves these, by transform alone. No CSS animation, so nothing runs before it takes over. */
}
.smoke__layer--a { top: -10%; height: 120%; opacity: 0.6; }
.smoke__layer--b { --tile: 120vw; top: 15%; height: 108%; opacity: 0.45; }
.smoke__layer--c { --tile: 180vw; top: -25%; height: 132%; opacity: 0.32; }
/* The warm light behind the smoke. Painted once, and it never moves. */
.glow {
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(44% 26% at 30% 18%, rgba(140, 105, 35, 0.3), transparent 72%),
    radial-gradient(40% 24% at 72% 40%, rgba(165, 125, 45, 0.3), transparent 72%),
    radial-gradient(46% 26% at 16% 74%, rgba(95, 76, 32, 0.28), transparent 72%),
    radial-gradient(36% 22% at 86% 88%, rgba(120, 92, 36, 0.26), transparent 72%);
}
/* Embers rise over the smoke. Each layer is one tile taller than the screen, so moving it by a whole tile cannot be seen. smoke.js moves them. */
.embers {
  --tile-h: 900px;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: calc(100vh + var(--tile-h));
  background: url("embers.svg") 0 0 / 700px var(--tile-h) repeat;
  will-change: transform;
}
.embers--b { --tile-h: 640px; background-size: 500px var(--tile-h); opacity: 0.7; }
/* Each moving layer costs tens of megabytes on an iPhone, so phones draw fewer, a little stronger. */
@media (max-width: 719px), (max-height: 500px) {
  .smoke__layer--a { opacity: 0.66; }
  .smoke__layer--b { opacity: 0.54; }
  .smoke__layer--c, .embers--b { display: none; }
}

main, .site-footer { position: relative; z-index: 1; }
.under-bar { padding-top: var(--header-h); }

/* ---------- Buttons. Filled yellow is for the main action and play buttons only. ---------- */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 10px;
  border: 2px solid transparent;
  border-radius: var(--r);
  background: var(--yellow);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.2);
  color: var(--black);
  font: 600 0.9375rem/1 var(--label);
  letter-spacing: 0.03em;
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
  white-space: nowrap;
}
/* The glow lives on its own layer and only its opacity moves, so a press costs no repaint. */
.btn::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 0 18px 2px rgba(255, 208, 0, 0.65);
  opacity: 0;
  pointer-events: none;
  transition: opacity 90ms ease-out;
}

.btn--big {
  width: 100%;
  font: 400 1rem/1.1 var(--display);
  letter-spacing: 0.03em;
}
.btn--big::after { opacity: 0.5; } /* The one button that glows at rest, so the eye lands on it. */

/* The red "!" in line with the words. Drawn, so it adds no words to the link. */
.alert-mark { display: inline-block; margin-left: 0.3em; pointer-events: none; }
.alert-mark::after { content: "!"; color: var(--red); font: 400 1.15em/1 var(--display); }

html[data-motion="on"] .redline::after { animation: redline-sweep 6s ease-in-out infinite; }
@keyframes redline-sweep { 0%, 55% { transform: translateX(-100%); } 100% { transform: translateX(460%); } }

/* Quieter actions. */
.ghost, .outline {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--panel);
  color: var(--white);
  font: 600 1rem/1.15 var(--label);
  letter-spacing: 0.05em;
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
  cursor: pointer;
}
.ghost[hidden] { display: none; }
.outline { display: flex; min-height: 48px; border-color: var(--white); white-space: nowrap; }
.outline--yellow { border-color: var(--yellow); background: var(--black); color: var(--yellow); font: 400 1.125rem/1 var(--display); letter-spacing: 0.04em; }

.icon-btn {
  flex: none;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--panel);
  color: var(--white);
  cursor: pointer;
}
.icon-btn[hidden] { display: none; }
.icon-btn svg { display: block; width: 20px; height: 20px; }

/* ---------- Top bar. Solid, with no blur: blurring moving smoke repaints every frame. ---------- */

.site-header {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: var(--header-h);
  padding: var(--safe-top) var(--gutter-r) 0 var(--gutter-l);
  border-bottom: 1px solid var(--red);
  background: var(--black);
}
/* The thin red line, with a brighter sweep along it now and then. */
.redline {
  position: absolute;
  right: 0;
  bottom: -1px;
  left: 0;
  height: 2px;
  overflow: hidden;
  background: var(--red);
  pointer-events: none;
}
.redline::after { content: ""; position: absolute; inset: 0 auto 0 0; width: 22%; background: rgba(255, 255, 255, 0.75); transform: translateX(-100%); }

/* Plain inline text, so the name stays one word for screen readers and copying. */
.wordmark {
  display: block;
  margin-right: auto;
  color: var(--white);
  font: 400 1.25rem/44px var(--display);
  white-space: nowrap;
  letter-spacing: 0.02em;
  text-decoration: none;
}
/* How far down the page you are: a thin yellow line along the header, sized by transform alone. Needs reveal.js, so hidden without it. */
.scrollbar { position: absolute; right: 0; bottom: 1px; left: 0; height: 2px; background: var(--yellow); transform: scaleX(0); transform-origin: left; pointer-events: none; }
.wordmark::before { content: ""; display: inline-block; vertical-align: -7px; width: 28px; height: 28px; margin-right: 6px; background: url("brand/mark-dh.svg") center / contain no-repeat; }
@media (max-width: 340px) { .wordmark::before { display: none; } } /* The smallest phones: the name alone, so the header stays one line. */
.wordmark span { color: var(--yellow); }

.site-nav { display: flex; }
.site-nav a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 6px;
  color: var(--white);
  font: 600 0.9375rem/1 var(--label);
  letter-spacing: 0.04em;
  text-decoration: none;
  text-transform: uppercase;
}
.site-nav a[aria-current="page"] { box-shadow: inset 0 -3px 0 var(--yellow); }

/* ---------- Hero: one full screen. These base rules are already the complete flat version.
   hero.js adds the pin and the 3D only where it can. svh, so a phone's address bar cannot make it jump. ---------- */

.hero__stage {
  position: relative;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  height: 100svh;
  padding: var(--header-h) var(--gutter-r) 14px var(--gutter-l); /* No safe-area here: svh already stops above the home bar, and the inset changes as the toolbar moves. */
  overflow: hidden;
}
.hero[data-hero-pinned] { height: 150svh; } /* hero3d.js sets this only once 3D has really started. */
.hero[data-hero-pinned] .hero__stage { position: sticky; top: 0; }

.hero__canvas { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; touch-action: pan-y; transition: opacity 400ms ease; }
.hero__flat { display: block; width: 100%; height: 100%; min-height: 0; padding-block: 12px; object-fit: contain; pointer-events: none; transition: opacity 300ms ease; }
.hero[data-hero-live] .hero__canvas { opacity: 1; }
.hero[data-hero-live] .hero__flat { opacity: 0; }

.hero__copy { position: relative; z-index: 1; display: grid; justify-items: center; gap: 10px; text-align: center; }
.hero__rule { display: block; width: 64px; height: 3px; margin: 0 auto 8px; border-radius: 2px; background: var(--red); }
.hero__words { width: 100vw; margin-inline: calc(-1 * var(--gutter-l)) calc(-1 * var(--gutter-r)); }
h1 { text-transform: uppercase; line-height: 0.98; }
h1 span { display: block; }
h1 span:first-child { font-size: min(12vw, 6.4svh, 84px); }
h1 span:last-child { font-size: min(29vw, 14.5svh, 190px); letter-spacing: 0.01em; }
.hero__who { margin-top: 6px; color: var(--text); font-size: 0.9375rem; line-height: 1.25; }
.hero__actions { display: grid; gap: 8px; width: min(66.7%, 280px); } /* 44px is the smallest a tap target may be, so the height goes no lower. */
.hero__actions .btn--big, .hero__actions .outline { min-height: 44px; font-size: clamp(0.8125rem, 3.75vw, 0.9375rem); }

/* One calm area for headings on the smoke: edge to edge, with faded edges so no box shows. The words sit inside the fade, where it is at full strength. */
.hero__words, .section-title {
  padding-block: var(--fade);
  background-color: var(--scrim);
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 var(--fade), #000 calc(100% - var(--fade)), transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 var(--fade), #000 calc(100% - var(--fade)), transparent);
}

/* Low screens: the line about who this is gives way first, so the button never does. */
@media (max-height: 600px) {
  .hero__who { display: none; }
  .hero__words { --fade: 6px; }
}

/* ---------- Thin yellow lines between sections, and what slides in. reveal.js is the only thing that adds these classes. ---------- */

.rule { display: block; height: 1px; background: var(--yellow); transform-origin: left; }
.is-pre, .video-list > .is-pre { opacity: 0; transform: translateY(24px); transition: none; } /* Waiting must not itself animate. */
.rule.is-pre { opacity: 1; transform: scaleX(0); }
.is-in, .video-list > .is-in { transition: opacity 500ms var(--ease), transform 500ms var(--ease); }

/* ---------- Sections ---------- */

.section { --pad-l: var(--gutter-l); --pad-r: var(--gutter-r); padding: 14px var(--pad-r) 8px var(--pad-l); }
.section > * + * { margin-top: 12px; }
.section--list { padding-top: 6px; }

.section-title, .page-title { font-size: 1.75rem; text-transform: uppercase; }
.section-title { margin-inline: calc(-1 * var(--pad-l)) calc(-1 * var(--pad-r)); padding-inline: var(--pad-l) var(--pad-r); }
.page-title { font-size: 3.25rem; }
.quiet { color: var(--muted); font-size: 0.9rem; line-height: 1.35; }
.quiet:empty { display: none; }
.section > .quiet, noscript > .quiet, noscript > p, .plain-list { padding: 4px 8px; border-radius: var(--r); background: var(--bg); }

.section.prose {
  max-width: 680px;
  margin: 16px var(--gutter-r) 0 var(--gutter-l);
  padding: 18px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: rgba(0, 0, 0, 0.74); /* See-through, so the same background runs behind the words. */
}
.prose > * + * { margin-top: 14px; }
.prose h2 { margin-top: 34px; font-size: 1.625rem; text-transform: uppercase; }
.prose ul { padding-left: 20px; list-style: disc; }
.prose li + li { margin-top: 6px; }

/* An inline link keeps its line height, but its padding gives a tap area of at least 44px. Nothing sideways, or a gap shows before a full stop. */
.prose a, .quiet a, .video-error a {
  padding: calc((46px - 1.2em) / 2) 0;
  color: var(--yellow);
}

.sample-label {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 6px;
  background: var(--raised);
  color: var(--white);
  font: 600 0.9375rem/1.3 var(--label);
  letter-spacing: 0.03em;
}

.panel { padding: 16px; border-radius: var(--r-card); background: var(--panel); }

/* ---------- Videos: the controls are one solid block. ---------- */

/* One surface, so it reads over the smoke, and no boxes inside it. Each label is a 44px target, and what shows inside it can be slimmer, so that spare height is the spacing between rows. */
.controls {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  margin-top: 4px;
  padding: 0 6px 2px;
  border-radius: var(--r-card);
  background: var(--panel);
}
.controls[hidden] { display: none; }
.controls fieldset { min-width: 0; margin: 0; padding: 0; border: 0; }
.controls fieldset[hidden] { display: none; }
.controls legend { display: block; padding: 0; color: var(--muted); font: 600 0.8125rem/1.2 var(--label); letter-spacing: 0.03em; }
.controls__row { display: flex; align-items: center; padding-top: 2px; }
.controls__row fieldset { flex: 0 1 auto; margin-right: auto; }
.controls .icon-btn { border: 0; background: none; color: var(--text); }
.controls .icon-btn[aria-expanded="true"] { background: var(--raised); color: var(--white); }

/* Three words on one hairline, which runs edge to edge. */
.choices--tabs { display: grid; grid-template-columns: repeat(3, minmax(max-content, 1fr)); margin-inline: -6px; border-bottom: 1px solid var(--line); }
.choices--tabs input:checked + span { box-shadow: inset 0 -3px 0 var(--yellow); }
/* One outline around both parts, which touch. Only the chosen part is filled. */
.choices--seg { display: grid; grid-template-columns: repeat(2, 1fr); }
.choices--seg span { margin-block: 3px; padding-inline: 14px; border: 1px solid var(--line); }
.choices--seg .choice:first-child span { border-right: 0; border-radius: var(--r) 0 0 var(--r); }
.choices--seg .choice:last-child span { border-left: 0; border-radius: 0 var(--r) var(--r) 0; }
.choices--seg input:checked + span { background: var(--raised); }
/* Sideways by itself, so the page never scrolls sideways. */
.choices--chips {
  display: flex;
  gap: 6px;
  margin-top: -3px;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.choices--chips::-webkit-scrollbar { display: none; }
.choices--chips .choice { flex: none; scroll-snap-align: start; }
.choices--chips span { margin-block: 5px; padding-inline: 10px; border: 1px solid var(--line); border-radius: var(--r); }
.choices--chips input:checked + span { border-color: var(--yellow); }

.choice { position: relative; display: flex; min-width: 44px; min-height: 44px; }
.choice input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }
/* A grid, not a flex row, because only a grid can both centre the line and sit the words and the smaller count on one baseline. */
.choice span {
  flex: 1;
  display: grid;
  grid-auto-flow: column;
  justify-content: center;
  align-content: center;
  align-items: baseline;
  column-gap: 4px;
  color: var(--muted);
  font: 600 0.875rem/1.1 var(--label);
  letter-spacing: 0.03em;
  white-space: nowrap;
  text-transform: uppercase;
  cursor: pointer;
}
.choice b { color: var(--muted); font-size: 0.75rem; }
.choice input:checked + span { color: var(--white); }
/* Drawn inside, because the chips' row clips anything outside it and the tabs touch the block's edge. */
.choice input:focus-visible + span { outline: 2px solid var(--yellow); outline-offset: -2px; }
@media (hover: hover) { .choice:hover span { color: var(--white); } }

.search { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 6px; padding-block: 3px 4px; }
.search[hidden], .search .icon-btn[hidden] { display: none; }
.search__box { display: block; grid-column: 1; }
.search__box:has(+ .icon-btn[hidden]) { grid-column: 1 / -1; }
.search__count { grid-column: 1 / -1; color: var(--text); font: 600 0.875rem/1.2 var(--label); letter-spacing: 0.02em; }
.search__count:empty { display: none; }
.search input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.search input {
  display: block;
  width: 100%;
  min-height: 46px;
  padding: 8px 12px;
  border: 1px solid var(--muted);
  border-radius: var(--r);
  background: var(--panel);
  color: var(--white);
  font: 400 1rem/1.4 var(--body); /* 16px or more stops iOS zooming in on focus */
  -webkit-appearance: none;
  appearance: none;
}
.search input:focus { border-color: var(--yellow); outline-offset: -2px; }

/* The source and the one cookie notice (D-50), on solid ground straight above the list. */
.video-flag { padding: 0 10px; border-radius: var(--r); background: var(--bg); }
.video-flag:empty, .video-status:empty { display: none; }
.video-flag:has(.youtube-mark) { display: flex; align-items: center; gap: 8px; padding-block: 6px; padding-left: 2px; }
.video-flag .sample-label { margin-bottom: 2px; }
.video-status { padding: 0 10px; border-radius: var(--r); background: var(--bg); color: var(--white); font: 600 0.9375rem/1.3 var(--label); letter-spacing: 0.02em; }
.section--list .video-flag { margin-top: 4px; }

/* Two columns, in reading order. Rows line up: every card stretches, and its action sits at the bottom.
   A list holding any Short shows every card at 3:4 (D-51). A list of only wider videos shows them whole, at 16:9, and bigger. */
.video-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  align-items: stretch;
}
.video-list--wide { grid-template-columns: minmax(0, 1fr); }
.section--list .video-list { margin-top: 6px; }
.video-list:empty { display: none; }

/* Room kept while the data is on its way, so the cards arrive without pushing what has already been painted. */
@media (scripting: enabled) {
  [data-video-library]:not([data-loaded]) .video-flag { display: block; min-height: 44px; }
  .library:not([data-loaded]) [data-shelf] { display: block; min-height: calc((100vw - 44px) * 4 / 3 + 200px); }
  .section--list:not([data-loaded]) { min-height: 100vh; }
}

.video { position: relative; display: flex; flex-direction: column; min-width: 0; overflow: hidden; border-radius: var(--r-card); background: var(--panel); transition: transform 120ms ease-out; }
/* The edge is drawn over the card, not as a border, because a border narrows the words and makes cards taller. */
.video::before { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; box-shadow: inset 0 0 0 1px var(--line); pointer-events: none; }
/* A press lifts the card and lights its edge. The light is its own layer and only its opacity moves. */
.video::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; box-shadow: inset 0 0 0 2px var(--yellow), inset 0 0 26px rgba(255, 208, 0, 0.3); opacity: 0; pointer-events: none; transition: opacity 120ms ease-out; }
.video:has(.facade:active) { transform: translateY(-3px); } /* The picture only, so a finger starting a scroll on the words lifts nothing. */
.video:has(.facade:active)::after { opacity: 1; }

.player { position: relative; flex: none; width: 100%; aspect-ratio: 3 / 4; overflow: hidden; background: var(--raised); }
.video-list--wide .player { aspect-ratio: 16 / 9; }

.facade {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: var(--raised);
  color: var(--white);
  cursor: pointer;
}
.facade img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.facade__word {
  position: absolute;
  top: 8px;
  left: 8px;
  padding: 2px 8px;
  border-radius: 6px;
  background: var(--panel);
  color: var(--white);
  font: 600 0.875rem var(--label);
}
.facade__play {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 48px;
  height: 48px;
  margin: -24px 0 0 -24px;
  border-radius: 50%;
  background: var(--yellow);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35);
}
.facade__play::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 0 18px 2px rgba(255, 208, 0, 0.65);
  opacity: 0;
  transition: opacity 90ms ease-out;
}
.facade__play::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -8px 0 0 -5px;
  border-style: solid;
  border-width: 8px 0 8px 13px;
  border-color: transparent transparent transparent var(--black);
}

/* The one player: fixed under the header, so nothing below it moves. 200px is YouTube's minimum player size.
   svh is the small viewport, so the address bar coming and going cannot change what fits. */
.dock { position: fixed; top: var(--header-h); right: 0; left: 0; z-index: 25; border-bottom: 1px solid var(--line); background: var(--black); }
.dock[hidden] { display: none; }
.dock__bar { display: flex; justify-content: flex-end; padding: 4px var(--gutter-r) 4px var(--gutter-l); }
.dock__stage { position: relative; height: min(56.25vw, calc(100svh - var(--header-h) - 53px)); min-height: 200px; }
.dock--short .dock__stage { height: min(100vw, calc(100svh - var(--header-h) - 176px)); }
.dock__stage iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

.sample-player {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
  background: var(--raised);
  color: var(--white);
  font-size: 0.875rem;
  text-align: center;
}

.video__meta { flex: 1; display: flex; flex-direction: column; min-width: 0; padding: 8px 10px 6px; background: var(--panel); }
.video__meta h3 { color: var(--white); font: 600 1rem/1.2 var(--label); letter-spacing: 0.01em; overflow-wrap: anywhere; text-wrap: balance; }
.video__tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 2px; }
.tag { color: var(--muted); font: 600 0.75rem/1.2 var(--label); letter-spacing: 0.08em; text-transform: uppercase; }
.tag--sample { padding: 0 6px; border-radius: 4px; background: var(--raised); color: var(--white); }
.video__foot { display: flex; align-items: flex-end; gap: 2px; margin-top: auto; padding-top: 4px; }
.video__stats { flex: 1; min-width: 0; color: var(--muted); font-size: 0.75rem; line-height: 1.3; }

.video-error { margin-top: 18px; }
.video-empty { display: grid; gap: 12px; justify-items: start; margin-top: 8px; color: var(--white); }
.video-empty[hidden] { display: none; }
/* The empty state says it on screen; the status line still tells screen readers. */
.video-empty:not([hidden]) ~ .video-status { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip-path: inset(50%); }
[data-show-more] { display: flex; width: 100%; margin-top: 16px; }

/* The clickable YouTube mark. Drawn here, so nothing loads from YouTube before a tap. */
.youtube-mark {
  display: inline-grid;
  place-items: center;
  width: 44px;
  height: 44px;
  flex: none;
}
.youtube-mark::before {
  content: "";
  width: 28px;
  height: 20px;
  border-radius: 6px;
  background: #ff0000 url("youtube-mark.svg") center / contain no-repeat;
}
.video__foot .youtube-mark { margin: -6px -8px -4px 0; }

noscript > p, noscript > ul { margin-top: 14px; }
.plain-list li + li { margin-top: 4px; }
.plain-list a { display: block; padding: 12px 0; }
.video-status.is-loading { position: absolute; }

/* ---------- Press and hover. A press shows at once. ---------- */

.btn:active { scale: 0.97; }
.btn:active::after, .facade:active .facade__play::after { opacity: 1; }
.facade:active .facade__play { scale: 0.92; }
.ghost:active, .outline:active, .icon-btn:active { background: var(--raised); scale: 0.98; }
.choice:active span { scale: 0.98; }
.youtube-mark:active::before { scale: 0.88; }
.wordmark:active, .site-nav a:active, .prose a:active, .quiet a:active, .video-error a:active { opacity: 0.7; }
@media (hover: hover) {
  .btn:hover::after, .facade:hover .facade__play::after, .video:hover::after { opacity: 1; }
  .ghost:hover, .outline:hover, .icon-btn:hover { background: var(--raised); }
  .wordmark:hover, .site-nav a:hover { color: var(--yellow); }
}

/* The footer, the header's LIVE link and the moving DH marks are in chrome.css. */

/* ---------- Phones held sideways: the logo on one side, the words and button on the other. ---------- */

@media (min-width: 560px) and (max-height: 500px) {
  .hero__stage { grid-template-rows: minmax(0, 1fr); grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 16px; align-items: center; }
  .hero__flat { grid-row: 1; grid-column: 1; }
  .hero__copy { grid-row: 1; grid-column: 2; gap: 6px; }
  .hero__words { width: auto; margin-inline: 0; background-color: transparent; -webkit-mask-image: none; mask-image: none; text-shadow: 0 2px 14px rgba(0, 0, 0, 0.85); }
  .hero__rule { margin-bottom: 4px; }
}

/* ---------- Roomier screens. ---------- */

@media (min-width: 720px) {
  .video-list { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .video-list--wide { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .library:not([data-loaded]) [data-shelf] { min-height: 460px; }
  .site-header { gap: 14px; }
  .btn { padding: 0 14px; font-size: 1rem; }
  .site-nav { gap: 10px; margin-right: 8px; }
  .site-nav a { font-size: 1.125rem; }
}

@media (min-width: 1040px) {
  .section, .site-footer {
    --pad-l: max(var(--gutter-l), calc((100vw - 1040px) / 2));
    --pad-r: max(var(--gutter-r), calc((100vw - 1040px) / 2));
    padding-left: var(--pad-l);
    padding-right: var(--pad-r);
  }
  .section.prose { margin-inline: auto; padding: 18px 24px; }
  .video-list--wide { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .dock__stage, .dock--short .dock__stage { max-height: 540px; }
}
