/* ===========================================================================
   Films, second version (/films/): Danny Gevirtz's films page
   (dannygevirtz.com/dannysprojects) as Graeme asked, his grid in the site's
   own look. His page is a near-black wall of looping clips, three across,
   nearly edge to edge with hairline seams and no words until a clip is
   hovered; each opens a page with a centred title and credits, the film
   full width, then stills. Here it is on V4's paper, in V4's type, with the
   hover titles in the pixel face (Graeme's call). One stylesheet for the
   index and every film page, as work.css is for the case studies.

   V5: Graeme picked this version for his films (over /film/), and it took
   V5's look: Inter at -6% in place of Geist, his G logo and V5's top bar,
   and the films' page titles in Inter like V5's headings (the hover titles
   and "Next film" stay in the pixel face, his call for this page). Its
   links go back to V5. It keeps this address until launch, when it
   becomes /film/ (V4 still links the template there).

   V6: merged into V6 (Graeme asked): the logo, "projects" and "contact" go
   back to V6 now, which links here from its nav and its film section. V5's
   "films" still opens it.
   =========================================================================== */
@font-face { font-family: "GL OffBit 101 Bold"; src: url("/fonts/OffBitTrial-101Bold.otf") format("opentype"); font-display: block; }
/* V5: Inter, one variable file for every weight, as on V5. */
@font-face { font-family: "GL Inter"; src: url("/fonts/InterVariable.woff2") format("woff2"); font-weight: 100 900; font-display: swap; }

/* V4's tokens, repeated: the prototype has no build step to share them (V5's where they differ). */
:root {
  --u: calc(min(100vw, 2315px) / 2315);
  --margin: calc(200 * var(--u));
  --gutter: calc(40 * var(--u));
  --s-1: calc(24 * var(--u));
  --s-2: calc(40 * var(--u));
  --s-3: calc(64 * var(--u));
  --s-4: calc(96 * var(--u));
  --s-5: calc(160 * var(--u));
  --t-title: calc(88 * var(--u));
  --t-sub: calc(64 * var(--u));
  --t-lead: max(18px, calc(44 * var(--u)));
  --t-body: max(15px, calc(32 * var(--u)));
  --t-small: max(13px, calc(24 * var(--u)));
  --t-micro: max(11px, calc(18 * var(--u)));
  --f-pixel: "GL OffBit 101 Bold", "GL Inter", "Helvetica Neue", Arial, sans-serif;
  --f-text: "GL Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
  /* V5's hero size, for a film page's title. */
  --t-head: calc(83.101 * var(--u));
  --ink: #000000;
  --ink-soft: rgb(0 0 0 / 0.62);
  --paper: #faf6f5;
  --card: #ffffff;
  --orange: #ff5c39;
  --blue: #0e1adf; /* Graeme's blue, as V4's (it was #0690fb) */
  --line: max(1.5px, calc(3 * var(--u)));
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --dur-s: 200ms;
  --dur-m: 450ms;

  /* Danny's grid: 29px from the window's edges and 7px seams at 1440 wide,
     here in design pixels so it scales like the rest of the site. */
  --edge: calc(46 * var(--u));
  /*
    Then rounded, in one grid (Graeme asked, after a grid of rounded film
    stills he sent): the homepage cards' corner, not rounder, and seams
    wider than Danny's hairlines, which rounded corners crowded (about 1% of
    the width, as in his picture: 15px at 1440).
  */
  /*
    Then tighter (Graeme asked, after a second picture: "very tight tiles,
    very tight rounded corners"): in it the seams are about 1.7% of a
    tile's width and the corners a few pixels, so here 8px and 4px at 1440.
  */
  --radius: max(3px, calc(6.5 * var(--u)));
  --seam: max(4px, calc(13 * var(--u)));

  /* A clip under its title, dimmed so the white title reads on any frame. */
  --dim: rgb(0 0 0 / 0.5);

  /* The placeholder stills' colours: the site's orange and blue, the
     resume band's sky, peach and rose, and three darks for dusk and night. */
  --sky-1: #8fc6f2;
  --sky-2: #b9d8f6;
  --peach: #ffb38a;
  --rose: #f6a8c6;
  --night: #0b1a2e;
  --plum: #4a2645;
  --stone: #cfc6be;
  --slate: #57514d;
  --noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1.4 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

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

html, body { margin: 0; }

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--f-text);
  font-size: var(--t-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
  /* Inter's text cut at every size, as on V5 (the display cut was much narrower than Figma's). */
  font-optical-sizing: none;
}

/*
  The Films pages are white (Graeme: "make it white"), not the site's
  paper. A mildly moving pastel gradient was tried behind them and taken
  off at his ask; it is parked in design/parked/film-sky.html.
*/
body { background: var(--card); }

/*
  Inter at -6% (Graeme's setting), on every element, as on V5: an em letter
  spacing is handed down as a fixed length. The pixel face keeps its own.
*/
body, body * { letter-spacing: -0.06em; }

h1, h2, p, ol, ul, figure { margin: 0; }
h1, h2 { font-weight: 400; text-wrap: balance; }
p { text-wrap: pretty; }
ol, ul { padding: 0; list-style: none; }
a { color: inherit; }
::selection { background: var(--orange); color: var(--ink); }
:focus-visible { outline: 3px solid var(--blue); outline-offset: 4px; }

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

.wrap {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  padding-inline: var(--margin);
}

.pill {
  display: inline-grid;
  place-items: center;
  height: calc(64 * var(--u));
  min-height: 40px;
  padding: 0 calc(28 * var(--u));
  border: var(--line) solid var(--ink);
  border-radius: 999px;
  background: var(--card);
  font-family: var(--f-pixel);
  font-size: var(--t-body);
  line-height: 1;
  /* OffBit's capitals sit 0.1em above the middle of their line (measured), as on V4. */
  padding-top: 0.2em;
  letter-spacing: -0.02em;
  white-space: nowrap;
  text-decoration: none;
  transition: background var(--dur-s) var(--ease), color var(--dur-s) var(--ease);
}

.pill:hover, .pill:focus-visible { background: var(--ink); color: var(--card); }

/* ---------------------------------------------------------------------------
   The top bar, as on V4 (it keeps the site's margins, so it sits inside the
   wider grid, as Danny's header does)
   ------------------------------------------------------------------------- */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: calc(60 * var(--u)) var(--margin) 0;
}

.logo {
  font-family: var(--f-pixel);
  font-size: var(--t-lead);
  line-height: 1.1;
  letter-spacing: -0.02em;
  text-decoration: none;
  white-space: nowrap;
}

.topbar ul { display: flex; gap: var(--s-3); }

.topbar ul a {
  display: flex;
  align-items: center;
  gap: 0.4em;
  font-size: var(--t-small);
  font-weight: 500;
  text-decoration: none;
}

.topbar img { width: 0.62em; height: 0.62em; image-rendering: pixelated; }

/*
  The way into the Dream Space (Graeme, with a mockup of the menu): its
  wizard, last, 2.42 times the words' size, his hat an em above their
  line and his feet just under it, as in the mockup; his margins leave
  him the words' line height (1lh), so the bar doesn't grow. He has no
  words, so his picture names the link, and focus rings him. Not turned
  white with the icons: he keeps his colours on the black. (His link is
  .dreamspace: .dream is the Dreamscape's own layer, on these pages.)
*/
.topbar .dreamspace img { width: auto; height: 2.42em; margin: -1em 0 calc(1lh - 1.42em); image-rendering: auto; filter: none; }
.topbar .dreamspace:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; border-radius: 4px; }

/*
  V5's top bar: Graeme's grainy G with its ® (the SVG from Figma), its box
  where his frame "V8" has it, and the nav's baseline 183 design pixels down.
*/
.topbar { align-items: flex-start; padding-top: 0; }

.mark {
  container-type: inline-size;
  position: relative;
  display: block;
  width: calc(98.667 * var(--u));
  margin: calc(102.4 * var(--u)) 0 0 calc(-3.56 * var(--u));
  color: var(--ink);
  text-decoration: none;
}

/* Through .topbar, or the nav icons' size takes it. */
.topbar .mark img { display: block; width: 100%; height: auto; image-rendering: auto; }

.mark .reg {
  position: absolute;
  left: 82.8cqi;
  top: 4.56cqi;
  font-size: 24.93cqi;
  font-weight: 700;
  line-height: 1;
}

.topbar nav { margin-top: calc(183 * var(--u) - 0.969 * var(--t-small)); }

/*
  Then the studio's logo in place of the G (Graeme asked): peace and love
  studios, white type with its own ®, shown in ink as on /film/. 480 design
  pixels wide (298px at 1440), its baseline on the nav's (the type sits on
  row 72 of the image's 113, 49 design pixels down at this width), its
  first letter on the margin (19 of 706 columns are empty on the left).
  It still goes to V6.
  Then the G back (Graeme asked), as on V5 and V6; the studio's logo moved
  into the head of the index, over his sentence on what it is for (below).
*/

.topbar ul a:hover span,
.topbar ul a:focus-visible span,
.topbar ul a[aria-current] span {
  text-decoration: underline;
  text-decoration-thickness: var(--line);
  text-underline-offset: 0.2em;
}

/* ---------------------------------------------------------------------------
   A still: a film's clip, its frame, or (until there is one) a placeholder
   ------------------------------------------------------------------------- */
.still {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--slate);
  object-fit: cover;
}

/* A real still: its height attribute (720) is also a CSS height, which beat the 16:9 shape and made the grid's tiles tall; auto lets the shape set it (the play screen sets its own 100%). */
img.still { height: auto; }

/* The placeholders: grainy washes in the site's colours, like the resume's band. */
.ph::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--noise);
  mix-blend-mode: overlay;
  opacity: 0.55;
}

.ph-1 { background: linear-gradient(180deg, var(--night) 0%, var(--plum) 40%, var(--orange) 78%, var(--peach) 100%); }
.ph-2 { background: radial-gradient(70% 90% at 30% 20%, var(--sky-1), rgb(143 198 242 / 0) 70%), linear-gradient(160deg, var(--blue), var(--night)); }
.ph-3 {
  background:
    radial-gradient(45% 120% at 48% 0%, var(--peach), rgb(255 179 138 / 0) 70%),
    radial-gradient(35% 110% at 72% 10%, var(--rose), rgb(246 168 198 / 0) 70%),
    linear-gradient(90deg, var(--sky-1), var(--sky-2) 40%, var(--sky-1));
}
.ph-4 { background: radial-gradient(40% 55% at 60% 65%, var(--orange), rgb(255 92 57 / 0) 75%), var(--night); }
.ph-5 { background: linear-gradient(200deg, var(--rose), var(--sky-2) 70%); }
.ph-6 { background: linear-gradient(180deg, var(--stone), var(--slate)); }

/* ---------------------------------------------------------------------------
   The index: Danny's wall of clips, three across. Nothing is written on a
   clip until it is hovered (or focused): then it dims and its title rises
   into the middle, in the pixel face.
   ------------------------------------------------------------------------- */
.reel {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--seam);
  padding: var(--s-4) var(--edge) var(--s-5);
}

/*
  The films were three groups (Graeme's pick), each an Inter heading over
  its own rows. Then one grid again with a filter above it (Graeme asked):
  All, Documentaries, Brand films, Personal films, as pills in Inter on the
  clips' left edge. The pressed one is filled. It is only shown with script
  (film.js), since without it it would do nothing.
*/
/*
  Then a row of words, after a second picture Graeme sent: "FILTER WORK:"
  and the kinds in blue capitals, spread across the row. It runs between
  the page's margins, the logo's left edge and the nav's right one (Graeme:
  the logo is its boundary), not the wider grid's. The capitals are spaced
  out as in the picture (+4%), the one place on the page off Inter's -6%:
  at -6% small capitals ran together. The chosen kind is underlined, as the
  nav's current page is.
  Then much quieter (Graeme asked, with the studio's head above it): no
  label (screen readers still hear "Filter films by kind"), the words in
  ordinary case at the nav's size, grey, grouped and centred under the
  sentence rather than spread across the page; the chosen one in ink and
  underlined, the others turning ink under the pointer. Back on Inter's
  -6%, which only the capitals needed to leave.
*/
.filter {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px max(20px, calc(40 * var(--u)));
  padding: var(--s-3) var(--margin);
}

.filter[hidden] { display: none; }
.filter:not([hidden]) + .reel { padding-top: 0; }

.filter button {
  padding: 4px 0;
  border: 0;
  background: none;
  color: var(--ink-soft);
  font-family: var(--f-text);
  font-size: var(--t-small);
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  text-decoration: underline transparent;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 0.35em;
  transition: color var(--dur-s) var(--ease), text-decoration-color var(--dur-s) var(--ease);
}

.filter button:hover { color: var(--ink); }
.filter button[aria-pressed="true"] { color: var(--ink); text-decoration-color: currentColor; }

/*
  The studio's head (Graeme asked): its logo, in ink (the image is white
  type, as on /film/), over his sentence on what the studio is for, both
  centred under the top bar, the sentence in the home page's film-section
  text (Inter Regular at 36 design pixels) and balanced over two lines.
  Then a hero, the page's first screen (Graeme asked: "like an above the
  fold … the films just peeking"): the logo and the line, bigger, centred
  in the room the top bar leaves, so that under them the filter and then
  the first row of films start just above the screen's foot, --peek of
  them showing, at any window height. The room is the screen less the top
  bar (--bar: 210 design pixels, 131px at 1440; 110px on phones), the
  filter's row and the peek. On a short window the hero is just its
  padding and the films come up sooner.
*/
:root {
  --bar: calc(210 * var(--u));
  --peek: clamp(64px, 11svh, 140px);
  --filter-h: calc(2 * var(--s-3) + 1.2 * var(--t-small) + 8px);
}

.studio-intro {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: var(--s-3);
  min-height: calc(100svh - var(--bar) - var(--filter-h) - var(--peek));
  padding: var(--s-4) var(--margin);
  text-align: center;
}

.studio-logo {
  display: block;
  /* 860 design pixels, 535px at 1440; a step past 760, which still read as a heading rather than a hero. On phones, three quarters of the screen. */
  width: calc(860 * var(--u));
  min-width: 260px;
  max-width: 100%;
  height: auto;
  filter: brightness(0);
}

.studio-intro p {
  max-width: 30em;
  font-size: var(--t-lead);
  line-height: 1.4;
  text-wrap: balance;
}

/* Then a weight up (Graeme asked, so it reads more easily): Medium, as the page's headings are. */
.studio-intro > p { font-weight: 500; }

/*
  Two quotes under the line (Graeme's picks, Orson Welles and Nia
  DaCosta): small epigraphs, a pair side by side, each centred in its half,
  in grey at the nav's size with the name under it in ink, a step bolder.
  The em dash before each name is drawn here, not typed, so screen readers
  read the name alone after the quote. On phones they stack.
*/
.epigraphs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-4);
  width: min(100%, calc(1300 * var(--u)));
  margin-top: var(--s-2);
}

.epigraphs figure { margin: 0; }

.epigraphs blockquote { margin: 0; }

.epigraphs blockquote p {
  max-width: none;
  color: var(--ink-soft);
  font-size: var(--t-small);
  font-weight: 400;
  line-height: 1.5;
  text-wrap: balance;
}

.epigraphs figcaption {
  margin-top: 0.6em;
  font-size: var(--t-small);
  font-weight: 500;
}

.epigraphs figcaption::before { content: "— "; }

/*
  Then the tagline leads (Graeme found the head hard to read: the logo was
  the biggest thing on the screen, the line one long 70-character run
  through the middle, the quotes far apart). It is the studio's own front
  door now, a page of its own at the top of this one:
  - the tagline is the hero, at V5's hero size (--t-head, 52px at 1440),
    Inter Medium, on two lines broken at "and" (on phones each half wraps);
  - the logo signs it, above, 240px wide at 1440 (from 535);
  - the quotes stay small and grey but sit closer, a pair about 760px
    across under the tagline rather than spread across the page.
*/
.studio-logo { width: calc(386 * var(--u)); min-width: 180px; }

.studio-intro > p {
  max-width: none;
  margin-top: calc(-0.2 * var(--s-3));
  font-size: var(--t-head);
  line-height: 1.12;
}

.epigraphs {
  width: min(100%, calc(1220 * var(--u)));
  gap: var(--s-3) var(--s-4);
  margin-top: var(--s-3);
}

/*
  Then less busy, more professional (Graeme: "a bit busy"; he took all
  three of Claude's ideas): the head is the studio's name and one line, as
  film studios' sites are, and the work comes sooner.
  1. The quotes left the head for the end of the page, a quiet sign-off
     after the films (.sign-off), same size and grey.
  2. The head is shorter: --peek is now most of the first row (clamp
     120px, 22svh, 260px: about 200px of a 256px tile at 1440x900).
  3. It is left-aligned, editorial: the logo (its first letter on the
     margin) and the tagline on the left, the filter on the right of the
     tagline's last line, both inside the page's margins; the logo is the
     filter's boundary as before, now on the left, the nav's edge on the
     right. Centred, the stack had read a little like a template.
*/
:root { --peek: clamp(120px, 22svh, 260px); }

/* Seated at the foot of its room, on the films: centred, it left about 200px between the filter and the grid it works, at 1440. */
.studio-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  align-content: end;
  column-gap: var(--s-4);
  min-height: calc(100svh - var(--bar) - var(--peek));
  padding: var(--s-4) var(--margin);
}

.studio-head .studio-intro {
  justify-items: start;
  gap: var(--s-2);
  min-height: 0;
  padding: 0;
  text-align: left;
}

.studio-head .studio-logo { margin-left: calc(-386 * var(--u) * 19 / 706); }

/* On the tagline's last line: the buttons' text sits on its baseline (measured), so it reads as the row's controls. */
.studio-head .filter {
  justify-content: flex-end;
  padding: 0 0 0.08em;
}

.studio-head + .reel { padding-top: 0; }

.sign-off {
  display: grid;
  justify-items: center;
  padding: 0 var(--margin) var(--s-5);
  text-align: center;
}

.sign-off .epigraphs { margin-top: 0; }

/* The films a filter brings back fade in, so the change reads. */
@media (prefers-reduced-motion: no-preference) {
  .reel li.arrive { animation: arrive var(--dur-m) var(--ease) both; }
}

@keyframes arrive { from { opacity: 0; } }

.tile {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--radius);
  color: var(--card);
  text-decoration: none;
}

.tile::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--dim);
  opacity: 0;
  transition: opacity var(--dur-m) var(--ease);
}

.cap {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: calc(10 * var(--u));
  padding: var(--s-2);
  text-align: center;
  opacity: 0;
  translate: 0 calc(12 * var(--u));
  transition: opacity var(--dur-m) var(--ease), translate var(--dur-m) var(--ease);
}

/* Inter Medium (Graeme asked; it was the pixel face, which the page's headings left). */
.cap .t {
  font-size: var(--t-sub);
  font-weight: 500;
  line-height: 1.1;
  text-wrap: balance;
}

.cap .m {
  font-size: var(--t-small);
  font-weight: 500;
  opacity: 0.85;
}

.tile:is(:focus-visible, .tapped)::before { opacity: 1; }
.tile:is(:focus-visible, .tapped) .cap { opacity: 1; translate: 0 0; }
.tile:focus-visible { outline-offset: 2px; }

/* Hovering only where a pointer can hover: a phone holds a tapped tile as
   "hovered", which would have kept its title up beside the tapped one. */
@media (hover: hover) {
  .tile:hover::before { opacity: 1; }
  .tile:hover .cap { opacity: 1; translate: 0 0; }
}

/* Touch screens can't hover. With script, the clip crossing the middle of
   the screen shows its title (film.js); without it, every title shows.
   Then a first tap shows it, and a second goes to the film (Graeme found
   titles coming up as the page scrolled distracting; film.js). */
@media (hover: none) {
  .reel:not(.watch) .tile::before { opacity: 1; }
  .reel:not(.watch) .cap { opacity: 1; translate: 0 0; }
}

@media (prefers-reduced-motion: reduce) {
  .cap { translate: 0 0; }
}

/* ---------------------------------------------------------------------------
   A film's page: centred title and credits, the film full width, then stills
   ------------------------------------------------------------------------- */
.film-head {
  display: grid;
  justify-items: center;
  gap: var(--s-1);
  padding: var(--s-5) var(--margin) var(--s-4);
  text-align: center;
}

.film-head h1 {
  font-family: var(--f-pixel);
  font-size: var(--t-title);
  line-height: 1.05;
  letter-spacing: -0.02em;
}

/* V5: in Inter Medium at V5's hero size, as V5's headings are Inter. */
.film-head h1 { font-family: var(--f-text); font-size: var(--t-head); font-weight: 500; line-height: 1.1; letter-spacing: -0.06em; }

.film-head .meta { display: flex; flex-wrap: wrap; justify-content: center; gap: calc(8 * var(--u)); }

.film-head .meta li {
  padding: calc(6 * var(--u)) calc(14 * var(--u));
  border: var(--line) solid var(--ink);
  border-radius: 999px;
  font-size: var(--t-micro);
  font-weight: 500;
}

.film-head .logline {
  max-width: 34ch;
  margin-top: var(--s-1);
  font-size: var(--t-lead);
  font-weight: 500;
  line-height: 1.3;
}

/* Danny's credits: a few grey lines under the title. */
.film-head .credits {
  color: var(--ink-soft);
  font-size: var(--t-body);
  line-height: 1.5;
}

.frames {
  display: grid;
  /* Danny's hairline, as before the grid's seams widened: a film page's stills stay square, so they keep it. */
  gap: max(4px, calc(11 * var(--u)));
  padding-inline: var(--edge);
}

.player {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--ink);
}

.player .poster,
.player iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.poster { display: block; color: var(--card); text-decoration: none; }
.poster .still { height: 100%; }

/* The play button: a white disc with the pixel triangle from the nav, as on /film/. */
.play {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: calc(160 * var(--u));
  height: calc(160 * var(--u));
  min-width: 56px;
  min-height: 56px;
  border-radius: 50%;
  background: var(--card);
  translate: -50% -50%;
  transition: scale var(--dur-s) var(--ease);
}

.play img { width: 36%; height: 36%; margin-left: 8%; image-rendering: pixelated; }
.poster:hover .play, .poster:focus-visible .play { scale: 1.08; }

/* A note shown only in the template, when a film has no ID yet. */
.player .missing {
  position: absolute;
  inset: auto auto var(--s-2) 50%;
  z-index: 3;
  max-width: 80%;
  padding: calc(12 * var(--u)) calc(20 * var(--u));
  border-radius: 999px;
  background: var(--orange);
  color: var(--ink);
  font-size: var(--t-small);
  font-weight: 500;
  translate: -50% 0;
}

/* The way on: back to every film, or on to the next. */
.film-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  padding: var(--s-5) var(--margin);
}

.film-nav .next {
  display: grid;
  justify-items: end;
  gap: calc(6 * var(--u));
  text-align: right;
  text-decoration: none;
}

.film-nav .next small { color: var(--ink-soft); font-size: var(--t-small); font-weight: 500; }

.film-nav .next span {
  font-family: var(--f-pixel);
  font-size: var(--t-sub);
  line-height: 1.1;
  letter-spacing: -0.02em;
  transition: color var(--dur-s) var(--ease);
}

.film-nav .next:hover span, .film-nav .next:focus-visible span { color: var(--orange); }

/* ---------------------------------------------------------------------------
   The footer, as on /film/
   ------------------------------------------------------------------------- */
.site-foot {
  align-items: center;
  padding-block: var(--s-3);
  border-top: var(--line) solid var(--ink);
  font-size: var(--t-small);
}

.site-foot .logo { grid-column: 1 / 4; font-size: var(--t-body); }
.site-foot ul { grid-column: 4 / 10; display: flex; gap: var(--s-3); font-weight: 500; }
.site-foot a { text-decoration: none; }
.site-foot a[href]:hover { text-decoration: underline; text-decoration-thickness: var(--line); text-underline-offset: 0.2em; }
.site-foot .copy { grid-column: 10 / 12; color: var(--ink-soft); }
/* Then the G, with its ®, in place of "Graeme Lindsay" in the pixel face (Graeme, before launch: the new logo in every footer), smaller than the top bar's: 40px wide at 1440. */
.site-foot .mark { width: max(36px, calc(64 * var(--u))); margin: 0; }
.site-foot .mark img { display: block; width: 100%; height: auto; }

.up {
  grid-column: 12;
  justify-self: end;
  position: relative;
  width: max(52px, calc(120 * var(--u)));
  aspect-ratio: 150.748 / 153.771;
  text-decoration: none;
}

.up img { display: block; width: 100%; height: 100%; }

.up span {
  position: absolute;
  left: 51.74%;
  top: 59.83%;
  translate: -50% -50%;
  font-family: var(--f-pixel);
  font-size: max(26px, calc(62 * var(--u)));
  line-height: 1.1;
  /* As before V5's -6%: the key's two letters were set at the font's own spacing. */
  letter-spacing: normal;
}

.up:active { translate: 0 calc(4 * var(--u)); }
/* Then much smaller (Graeme, before launch): 36px across, from 75 at 1440 and 52 on phones, about the footer G's size; its letters in proportion, as 62 to its 120. */
.up { --key: max(36px, calc(58 * var(--u))); width: var(--key); }
.up span { font-size: calc(var(--key) * 62 / 120); }

/* ---------------------------------------------------------------------------
   Tablets: two across, as Danny's goes below 768px
   ------------------------------------------------------------------------- */
@media (max-width: 900px) {
  :root {
    --margin: 20px;
    --gutter: 16px;
    --s-1: 12px;
    --s-2: 20px;
    --s-3: 28px;
    --s-4: 40px;
    --s-5: 56px;
    --t-title: 36px;
    --t-sub: 24px;
    --t-lead: 20px;
    --t-body: 17px;
    --t-small: 14px;
    --t-micro: 11px;
    --line: 1.5px;
    --edge: 20px;
    --radius: 3px;
    --seam: 6px;
  }

  .wrap { grid-template-columns: minmax(0, 1fr); }
  .wrap > * { grid-column: 1 / -1 !important; }

  .topbar { flex-direction: column; align-items: flex-start; gap: 14px; padding-top: 20px; }
  .mark { width: 52px; margin: 0 0 0 -2px; }
  /* The top bar here, for the hero's room (measured at 390). */
  :root { --bar: 110px; }
  .studio-logo { width: 46vw; min-width: 0; }
  /* One column here: logo, tagline, then the filter, all on the left margin. */
  .studio-head { grid-template-columns: minmax(0, 1fr); row-gap: var(--s-3); align-items: start; }
  .studio-head .studio-logo { margin-left: calc(-46vw * 19 / 706); }
  .studio-head .filter { justify-content: flex-start; padding: 0; }
  /* The break at "and" stays: each half wraps on its own (without it the line split "…in / the visual world and telling / moving…"). */
  .studio-intro > p { font-size: 30px; }
  .epigraphs { grid-template-columns: minmax(0, 1fr); gap: 20px; margin-top: 4px; }
  .topbar nav { margin-top: 0; }
  .film-head h1 { font-size: 36px; }
  .topbar ul { width: 100%; justify-content: space-between; gap: 8px; }
  .topbar ul a { font-size: 15px; }
  /* Then centred on phones (Graeme, before launch): the G over the menu, the menu gathered in the middle rather than spread edge to edge, free to wrap on the narrowest screens. */
  .topbar { align-items: center; }
  .topbar .mark { margin: 0; }
  .topbar ul { width: auto; flex-wrap: wrap; justify-content: center; gap: 6px clamp(6px, calc(5.6vw - 10px), 20px); } /* One row down to 320, the Resume's Geist included (at 4.6vw it wrapped there). */
  /* Then the G and the menu as one header (Graeme: "balanced"): 14px between their ink, from 23, which matched the 24 above the G and left it floating; the hero line stays 45px under the menu. */
  .topbar { gap: 5px; }
  /* Then the Dream Space's wizard joined the menu, and below 375 it no longer fit one row (at 320 it wrapped, the page moving down 25px; the Resume's Geist the widest): there the words ease down, to 13px at 320, and the gaps close to 6px. */
  @media (max-width: 374px) {
    .topbar ul a { font-size: max(13px, 4.1vw); }
    .topbar ul { column-gap: 6px; }
  }

  .reel { grid-template-columns: repeat(2, minmax(0, 1fr)); padding-top: 28px; }
  .reel-group:first-of-type { padding-top: 28px; }

  /* In design pixels these pills' padding and gaps shrink to 1 or 2px here, and the pills touched. */
  .film-head .meta { gap: 6px; }
  .film-head .meta li { padding: 3px 10px; }

  .film-nav { flex-direction: column-reverse; align-items: flex-start; }
  .film-nav .next { justify-items: start; text-align: left; }

  .site-foot { row-gap: 16px; padding-block: 32px; }
  .site-foot ul { flex-wrap: wrap; gap: 16px; }
  .up { justify-self: start; }
  /* Then one footer on phones (Graeme, before launch): the G and the UP key on one row, the links under them, then the year; stacked, it ran to four loose rows. */
  .site-foot { display: flex; flex-wrap: wrap; align-items: center; column-gap: 16px; }
  .site-foot .mark { order: 1; }
  .site-foot .up { order: 2; margin-left: auto; }
  .site-foot ul { order: 3; flex-basis: 100%; }
  .site-foot .copy { order: 4; flex-basis: 100%; }
}

/* Phones: one clip per row, edge to edge, as Danny's. Rounded, they keep the page's margin. */
@media (max-width: 540px) {
  .reel { grid-template-columns: minmax(0, 1fr); }
  .cap .t { font-size: 28px; }
}

/* ===========================================================================
   Then black (Graeme asked, after white), the head centred again. Every
   Films page: the index and the fifteen films, so they stay one room.
   Black text turns white rule by rule, not by swapping --ink and --card,
   which the tiles' titles and the play button use as white on purpose.
   =========================================================================== */
:root {
  --page: #000000;
  --fg: #ffffff;
  --fg-soft: rgb(255 255 255 / 0.62);
  --fg-line: rgb(255 255 255 / 0.3);
}

body { background: var(--page); color: var(--fg); }

/* The keyboard ring: V5's blue all but vanished on black (about 2:1). */
:focus-visible { outline-color: var(--fg); }

.mark { color: var(--fg); }

/* The nav's pixel icons are drawn in black. */
.topbar ul img { filter: invert(1); }

/* The studio's logo is white type: on black it shows as it is. */
.studio-logo { filter: none; }

.filter button { color: var(--fg-soft); }
.filter button:hover,
.filter button[aria-pressed="true"] { color: var(--fg); }

.epigraphs blockquote p { color: var(--fg-soft); }

.pill { border-color: var(--fg); background: transparent; color: var(--fg); }
.pill:hover, .pill:focus-visible { background: var(--fg); color: var(--page); }

.film-head .meta li { border-color: var(--fg); }
.film-head .credits,
.film-nav .next small,
.site-foot .copy { color: var(--fg-soft); }

/* A hair lighter than the page, so a film loading shows where it will be. */
.player { background: #111111; }

/* The footer's rule, softened: a full white line on black was the loudest thing in it. */
.site-foot { border-top-color: var(--fg-line); }
/* Then no rule above it at all (Graeme, before launch), as on V6 and the Resume. */
.site-foot { border-top: 0; }

/* The UP key is a pale keycap: its letters stay black. */
.up span { color: #000000; }

/*
  The head centred again (Graeme), in the middle of its room: the logo
  over the tagline, both centred, and the filter centred under them at
  the room's foot, just above the films it works. The room and the peek
  of films are as before.
*/
.studio-head {
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: 1fr auto;
  justify-items: center;
  align-content: stretch;
  row-gap: var(--s-4);
  text-align: center;
}

.studio-head .studio-intro {
  align-self: center;
  justify-items: center;
  text-align: center;
}

.studio-head .studio-logo { margin-left: 0; }
.studio-head .filter { justify-content: center; padding: 0; }

@media (max-width: 900px) {
  .studio-head { row-gap: var(--s-4); align-items: stretch; }
  .studio-head .studio-logo { margin-left: 0; }
  .studio-head .filter { justify-content: center; }
}

/*
  A glow behind the head (Graeme, after Gemini's soft blue on black): the
  G's orange, very faint, a wide oval centred on the tagline that fades to
  black well before the screen's edges. Still, and only behind the head,
  so it stays with the first screen rather than following the films down.
  A layer under the head's words, reaching above and below the head so
  its fade never meets an edge.
*/
.studio-head { position: relative; isolation: isolate; }

.studio-head.glow::before {
  content: "";
  position: absolute;
  /* Within the page's width: reaching past its sides (-10%), it widened the page to 1584px at 1440. The oval has faded out long before them. */
  inset: -15% 0 -25%;
  z-index: -1;
  background: radial-gradient(55% 50% at 50% 48%, rgb(255 92 57 / 0.2), rgb(255 92 57 / 0.07) 45%, rgb(255 92 57 / 0) 72%);
  pointer-events: none;
}

/*
  Then (Graeme picked both refinements, and the home page's blue): dim
  orange on black read as brown haze, not light; dim blue stays blue, as
  Gemini's does. So it is V5's blue (#0e1adf, --glow as its channels, so
  the orange is one value away: 255 92 57), with a brighter heart over a
  smaller oval and a quicker fall-off, so the middle reads as light. And
  a fine grain over it, the site's own texture (the resume band's, V5's
  cards'), kept to the glow by the same oval as a mask, so the black
  around stays clean: it smooths the faint bands soft gradients show on
  dark screens, and echoes the grainy G.
*/
:root { --glow: 14 26 223; }

.studio-head.glow::before {
  background:
    radial-gradient(20% 22% at 50% 48%, rgb(var(--glow) / 0.32), rgb(var(--glow) / 0) 100%),
    radial-gradient(44% 44% at 50% 48%, rgb(var(--glow) / 0.42), rgb(var(--glow) / 0.14) 45%, rgb(var(--glow) / 0) 78%);
}

.studio-head.glow::after {
  content: "";
  position: absolute;
  inset: -15% 0 -25%;
  z-index: -1;
  background-image: var(--noise);
  opacity: 0.09;
  -webkit-mask-image: radial-gradient(44% 44% at 50% 48%, #000 30%, transparent 78%);
  mask-image: radial-gradient(44% 44% at 50% 48%, #000 30%, transparent 78%);
  pointer-events: none;
}

/*
  Then the plain black (Graeme: "the black might be nicer"; Claude agreed:
  the glow read as a tech product's, Gemini's, where flat black reads as a
  film studio's and leaves the stills the only light on the page). The
  glow above is kept but off: it shows only with ?glow in the address
  (film.js adds .glow), to compare.
*/

/*
  The eyes cursor (Graeme: it wasn't on these pages), V6's own, drawn by
  eyes.js: the real cursor is hidden only while they run, so without
  script, on touch screens and under reduced motion it stays. Over a
  film's tile there is no cursor at all, as over V6's film tiles: the eyes
  sat on the title the hover brings up. On the black their dark rim
  vanishes and the whites and pupils carry them.
*/
:root {
  --eye-white: #ffffff;
  --eye-ink: #141414;
  --eye-top: #2a2a2a;
  --eye-side: #0b0b0b;
}

.eyes-cursor {
  /* One block of the pixel art. Whole pixels keep the edges crisp. */
  --cell: 3px;
  position: fixed;
  z-index: 2147483647;
  left: 0;
  top: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-s) var(--ease);
}

.eyes-cursor.on { opacity: 1; }

.eyes-cursor svg {
  display: block;
  width: calc(17 * var(--cell));
  height: calc(14 * var(--cell));
  overflow: visible;
  shape-rendering: crispEdges;
}

/* Blinks squash each eye, depth and all, towards its middle. */
.eyes-cursor .eye { transform-box: fill-box; transform-origin: 50% 50%; }

.eyes-cursor .top { fill: var(--eye-top); }
.eyes-cursor .side { fill: var(--eye-side); }
.eyes-cursor .face, .eyes-cursor .pupil { fill: var(--eye-ink); }
.eyes-cursor .white { fill: var(--eye-white); }

html.eyes-on, html.eyes-on * { cursor: none; }

html:has(.tile:hover) .eyes-cursor.on { opacity: 0; }

/*
  The studio's logo a little higher over the tagline (Graeme): 40 design
  pixels more between them (25px at 1440, 16px on phones), the logo moving
  up by all of it and the tagline staying where it was (the extra gap and
  the logo's negative margin cancel out in the centred block). About 32px
  showed between the logo's letters and the tagline's capitals at 1440.
*/
.studio-head .studio-intro { --lift: calc(40 * var(--u)); gap: calc(var(--s-2) + var(--lift)); }
.studio-head .studio-logo { margin-top: calc(-1 * var(--lift)); }

@media (max-width: 900px) {
  .studio-head .studio-intro { --lift: 16px; }
}

/* Then on phones never nearer the menu than the homepage's hero line is (45px; Graeme: "balanced"): on the smallest, with no room to centre in, the logo came 25px under it. */
@media (max-width: 900px) {
  .studio-head { padding-top: calc(var(--s-4) + 20px); }
}

/* ===========================================================================
   Dreamscape (Graeme, after four pictures of soft, grainy, pastel dream
   landscapes: "it takes you away into this epic ethereal dreamscape"),
   built by dream.js on every Films page. The black page stays underneath;
   over it, fixed behind everything, a dusk sky from deep blue to a pink
   horizon with a glow low in it, stars, slow pink and peach clouds, and a
   fine grain so it feels printed rather than digital, as the third
   picture does. The films float over it. Scrolling down, night falls
   (dream.js sets --deep, 0 to 1). Drawn in the pictures' spirit; nothing
   is copied from them.
   Then in the colours of Graeme's second picture, which he asked for, and
   glowier: a steel-blue sky paling to periwinkle and a lilac-pink horizon,
   salmon clouds warming to peach at their feet, each in a soft glow and
   drifting across, a green hill with a yellow-green rim of light turning
   blue at its edges, and the figure on a pale blue pool of light.
   =========================================================================== */
:root {
  --dream-ink: #173371;
  /*
    The tagline sits about two fifths down, on the blue (white on it is
    5.6:1), and the filter about seven tenths, on the lilac: with the pink
    from 74%, as first drawn, the filter was white on pink, about 2.3:1.
    Then the second picture's blues: the tagline's foot is on #4e85c9
    (3.8:1, over the 3:1 type this large needs), and the horizon is paler,
    periwinkle where the filter sits, so the filter is on frosted glass.
  */
  --dream-dusk: linear-gradient(180deg, #1d5aa2 0%, #2a69b3 22%, #3e7bc2 40%, #5f8fd0 54%, #8fa1da 64%, #bfaedd 74%, #e8b6d2 84%, #fcc3c4 93%, #ffd6c2 100%);
  --dream-night: linear-gradient(180deg, #071633 0%, #0c2552 40%, #173a78 72%, #2f4b8f 100%);
  --dream-glow: 255 208 222;
  --dream-cloud-top: #f598ae;
  --dream-cloud-foot: #ffb089;
  --dream-cloud-glow: 255 168 172;
  --dream-hill-far: #5d93d6;
  --dream-hill-rim: 222 244 130;
  --dream-hill: #4fae4d;
  --dream-hill-deep: #2f8b55;
  --dream-hill-edge: #3a78d0;
  --dream-cloud-lit: #ffe9df;
  --dream-shade: 18 44 110;
  --cloud-scale: 1;
  --ground-h: max(220px, calc(560 * var(--u)));
}

@media (max-width: 900px) {
  /* Clouds a share of a narrow screen's width are small puffs: these are as big as on a laptop, near enough. */
  :root { --cloud-scale: 1.7; }
}

.dream {
  --deep: 0;
  position: fixed;
  inset: 0;
  z-index: -1;
  display: none;
  overflow: hidden;
  contain: strict;
  pointer-events: none;
  opacity: 0;
}

.dream.on { display: block; }

/*
  Then no circle: the dream fades in (dream.js) while this bloom grows from
  the button. The circle was a mask redrawn over the whole screen every
  frame, and the drawing work all but filled the opening; opacity and a
  scaled disc are moves the graphics card makes on its own. 400px across,
  scaled up to the screen: soft light, so it needs no sharper.
*/
.dream-bloom {
  position: fixed;
  left: 0;
  top: 0;
  z-index: -1;
  width: 400px;
  height: 400px;
  border-radius: 50%;
  /* Warm at its heart: a paler pink-white read grey over the black as it rose (seen frozen at 0.35s). */
  background: radial-gradient(closest-side, rgb(255 236 244 / 0.95), rgb(255 186 212 / 0.7) 42%, rgb(255 186 212 / 0));
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
}

/* Before dream.js has drawn the scene, a remembered dream is the sky alone, never a flash of black. */
html.dreaming:not(.dream-built) body { background: var(--dream-dusk) fixed; }

.dream > div { position: absolute; }

/* Then a stronger glow along the horizon, behind the hill. */
.dream-sky {
  inset: 0;
  background: radial-gradient(85% 44% at 50% 96%, rgb(var(--dream-glow) / 0.85), rgb(var(--dream-glow) / 0) 72%), var(--dream-dusk);
}

.dream-night { inset: 0; background: var(--dream-night); opacity: var(--deep); }

/*
  Then the grain in the sky and the night themselves, drawn once with them:
  as a layer of its own, blended over the moving clouds, it had to be
  blended again every frame. The night and the stars change only as the
  page scrolls, so they are layers of their own and the sky isn't redrawn.
*/
.dream-sky {
  background: var(--noise) 0 0 / 180px, radial-gradient(85% 44% at 50% 96%, rgb(var(--dream-glow) / 0.85), rgb(var(--dream-glow) / 0) 72%), var(--dream-dusk);
  background-blend-mode: soft-light, normal, normal;
}

.dream-night { background: var(--noise) 0 0 / 180px, var(--dream-night); background-blend-mode: soft-light, normal; will-change: opacity; }

.dream-stars { inset: 0; opacity: calc(0.5 + 0.5 * var(--deep)); will-change: opacity; }
.dream-stars > div { position: absolute; inset: 0; }

.dream-stars i {
  position: absolute;
  width: var(--ss);
  height: var(--ss);
  border-radius: 50%;
  background: #ffffff;
  box-shadow: 0 0 8px 2px rgb(255 255 255 / 0.6);
}

/*
  Then crossing the sky, so placed by translate (dream.js gives each its
  start and its time), and glowing: less blurred, so each keeps the
  picture's puffy outline, inside a wide soft halo of its own pink.
*/
.dream-cloud {
  --cw: calc(var(--w) * var(--cloud-scale));
  left: 0;
  top: var(--y);
  width: var(--cw);
  translate: var(--x) 0;
  opacity: calc(var(--o) - 0.35 * var(--deep));
  will-change: translate, transform;
}

/*
  Then soft again, the first version's blur (Graeme found these harder and
  less glowy), its pale crown back, the halo kept. Then that cloud as one
  picture (scripts/dream-cloud.mjs), blur and glow drawn in, rather than
  each cloud blurred live: the picture has 50 units of room round the 200
  by 110 box for them, so it is 150% of the box's width, set a quarter of
  that width left and up.
*/
.dream-cloud { aspect-ratio: 200 / 110; }
.dream-cloud img { position: absolute; left: -25%; top: 0; width: 150%; height: auto; margin-top: -25%; }


/* The hill, in the Films page's head: it rises behind the filter as the dream settles, its foot dissolving behind the films. */
.dream-ground {
  /* The near dome's top, where the figure stands, as a share of the box from its top. */
  --crest: 20%;
  position: absolute;
  inset: auto 0 calc(-0.5 * var(--ground-h));
  z-index: -1;
  height: var(--ground-h);
  pointer-events: none;
  opacity: 0;
  translate: 0 14%;
  transition: opacity 0.8s var(--ease), translate 0.8s var(--ease);
}

html.dreaming .dream-ground { opacity: 1; translate: 0 0; transition-duration: 1.6s; transition-delay: 0.9s; }

/*
  On phones the filter runs nearly the width of the screen, and the figure
  stood on "Personal films". So there the hill is a far one, floating over
  the filter in the room under the button, its foot lost in mist before
  the filter's words: the box stands on the filter's top edge, the width
  of the screen.
*/
/* Then placed from the head's foot, the filter's top measured by dream.js (--over): the box is in the head again, not the filter. */
/* Then up to 720px wide, not 540: from 541 to about 700 the filter is still most of the width, and the horse and Graeme stood on it. */
@media (max-width: 720px) {
  .dream-ground {
    --crest: 40%;
    bottom: calc(var(--over, 80px) + 2px);
    height: clamp(72px, 12svh, 110px);
  }

  .dream-hills {
    -webkit-mask-image: linear-gradient(#000 58%, transparent 100%);
    mask-image: linear-gradient(#000 58%, transparent 100%);
  }
}

/*
  The domes are ellipses in percent of the ground box, so they stretch with
  the page: the near one's crest 85% across and a fifth down, where the
  figure stands. Grain on both, as on the sky (the sky's grain is under
  them), and the near one's top caught by the pink light of the horizon.
*/
/* Then in a box of their own, which fades their foot and clips them, so the horse and Graeme, beside it, can stand above it. */
.dream-hills {
  position: absolute;
  inset: 0;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(#000 60%, transparent 94%);
  mask-image: linear-gradient(#000 60%, transparent 94%);
}

.dream-hill { position: absolute; border-radius: 50%; background-blend-mode: soft-light, normal; }

/*
  Then as in the second picture, softened a little (blurred 2px at 1440)
  so they glow rather than cut: the near one green, brightest at its top
  and turning blue down its sides, a yellow-green rim of light along its
  edge and a pale haze above it; the far one a distant blue.
*/
.dream-hill.far {
  left: -44%;
  top: calc(var(--crest) + 10%);
  width: 112%;
  height: 174%;
  background: var(--noise) 0 0 / 180px, linear-gradient(var(--dream-hill-far), #3f74c4 40%);
  box-shadow: inset 0 calc(6 * var(--u)) calc(16 * var(--u)) rgb(200 226 255 / 0.5);
  opacity: 0.85;
  filter: blur(max(1px, calc(3 * var(--u))));
}

.dream-hill.near {
  left: 52%;
  top: var(--crest);
  width: 66%;
  height: 180%;
  background: var(--noise) 0 0 / 180px, radial-gradient(48% 34% at 50% 0%, var(--dream-hill) 0%, var(--dream-hill-deep) 62%, var(--dream-hill-edge) 100%);
  box-shadow:
    inset 0 calc(6 * var(--u)) calc(10 * var(--u)) rgb(var(--dream-hill-rim) / 0.9),
    inset 0 calc(18 * var(--u)) calc(40 * var(--u)) rgb(150 220 90 / 0.45),
    0 0 calc(70 * var(--u)) calc(10 * var(--u)) rgb(200 228 255 / 0.35);
  filter: blur(max(1px, calc(2.5 * var(--u))));
}


/* Over the sky the white words take a faint dusk shadow, for when a cloud drifts behind them, and the grey ones a step whiter. */
html.dreaming { --fg-soft: rgb(255 255 255 / 0.84); }

html.dreaming :is(.topbar, .studio-intro > p, .filter, .film-head, .sign-off, .film-nav, .site-foot) { text-shadow: 0 0 0.8em rgb(var(--dream-shade) / 0.4); }
/* Then a little closer and deeper, the clouds now crossing behind the nav and the titles. */
html.dreaming :is(.topbar, .studio-intro > p, .film-head, .sign-off, .film-nav, .site-foot) { text-shadow: 0 0 0.45em rgb(var(--dream-shade) / 0.45), 0 0 1.2em rgb(var(--dream-shade) / 0.3); }
/* The filter is small and lowest on the sky, near the pink: a closer, deeper shadow. */
html.dreaming .filter button { text-shadow: 0 0 0.35em rgb(var(--dream-shade) / 0.4), 0 0 1em rgb(var(--dream-shade) / 0.25); }

/*
  Then on frosted glass, its shadow gone: the second picture's paler
  horizon put the filter on periwinkle (white on it about 2.3:1), and a
  passing cloud or the hill could sit behind it too. A pill of the sky
  behind it, darkened and blurred, the room it takes given back by a
  negative margin, so nothing moves as the dream starts.
*/
html.dreaming .filter button { text-shadow: none; }

.studio-head .filter { transition: background-color 1.2s var(--ease) 0.6s, box-shadow 1.2s var(--ease) 0.6s; }

html.dreaming .studio-head .filter {
  margin: -10px -22px;
  padding: 10px 22px;
  border-radius: 999px;
  background-color: rgb(var(--dream-shade) / 0.32);
  -webkit-backdrop-filter: blur(12px) saturate(1.3);
  backdrop-filter: blur(12px) saturate(1.3);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.2);
}

/* On phones a closer pill: with 22px either side it ran 2px past a 320 screen, which then scrolled sideways. */
@media (max-width: 540px) {
  html.dreaming .studio-head .filter { margin: -8px -12px; padding: 8px 12px; border-radius: 24px; }
}
html.dreaming .studio-logo { filter: drop-shadow(0 0 calc(24 * var(--u)) rgb(var(--dream-shade) / 0.35)); }

/* The films float: a soft dusk shadow under each. */
.tile { transition: box-shadow 1.2s var(--ease); }
html.dreaming .tile { box-shadow: 0 calc(16 * var(--u)) calc(56 * var(--u)) rgb(var(--dream-shade) / 0.3); }

/*
  The button: a small pill of pastel light, pink, peach and periwinkle
  shifting slowly across it, a soft halo, and the site's grain over it.
  It reads "Dreamscape", then "Wake up".
  Then in the second picture's pink, peach and sky blue, asking "Want to
  dream?" (Graeme), its sparkle gone.
*/
.dream-toggle {
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.62em 1.3em 0.66em;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(100deg, #ffb3c4, #ffc9a8 30%, #b9cff7 60%, #ffb3c4 90%) 0 50% / 300% 100%;
  color: var(--dream-ink);
  font: 500 var(--t-small) / 1.2 var(--f-text);
  cursor: pointer;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.6), 0 0 22px 2px rgb(255 176 190 / 0.4), 0 0 64px 12px rgb(150 190 255 / 0.2);
  transition: scale var(--dur-s) var(--ease), box-shadow var(--dur-m) var(--ease);
}

.dream-toggle::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--noise) 0 0 / 120px;
  opacity: 0.5;
  mix-blend-mode: soft-light;
}

/*
  Then the shimmer on a layer of its own, moved by transform: shifting the
  background repainted the pill every frame, awake or dreaming.
  Then back on the pill itself (Graeme saw it broken on the live site):
  Safari doesn't always clip a moving layer to a rounded box, so the layer
  showed as a pink rectangle past the pill's round ends. Repainting a pill
  this small costs next to nothing; the halo stays, which clipping the
  whole button (clip-path or a mask) would have cut off.
*/

.dream-toggle:hover { box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.75), 0 0 28px 4px rgb(255 176 190 / 0.6), 0 0 80px 18px rgb(150 190 255 / 0.3); }
.dream-toggle:focus-visible { outline: 2px solid var(--fg); outline-offset: 4px; }

/* Under the tagline, with the gap the lift added above the logo taken back off. */
.studio-head .dream-toggle { margin-top: calc(var(--s-1) - var(--lift)); }
.film-head .dream-toggle { margin-top: var(--s-1); }

@media (prefers-reduced-motion: no-preference) {
  .dream-toggle { animation: dream-shimmer 9s ease-in-out infinite alternate; }
  .dream-toggle:hover { scale: 1.04; }

  .dream-stars > div { animation: dream-twinkle 3.1s ease-in-out infinite alternate; }
  .dream-stars > div:nth-child(2) { animation-duration: 4.3s; animation-delay: -1.7s; }
  .dream-stars > div:nth-child(3) { animation-duration: 5.7s; animation-delay: -3.2s; }

  .dream-cloud { animation: dream-cross var(--drift) linear var(--phase) infinite, dream-bob var(--bob) ease-in-out calc(var(--i) * -5s) infinite alternate; }
}

@keyframes dream-shimmer { to { background-position: 100% 50%; } }
@keyframes dream-twinkle { from { opacity: 0.25; } }
@keyframes dream-cross { from { translate: calc(-1.2 * var(--cw)) 0; } to { translate: calc(100vw + 0.2 * var(--cw)) 0; } }
@keyframes dream-bob { from { transform: translateY(-0.7vh); } to { transform: translateY(0.7vh); } }

@media (prefers-reduced-motion: reduce) {
  .dream-ground, html.dreaming .dream-ground, .tile, .studio-head .filter { transition: none; }
}

/* ===========================================================================
   Then the one button: the film pages' "All films" (the only .pill here)
   The one button (Graeme, before launch: "make all the buttons the same …
   the Mixed-Methods button style"): V6's Mixed-Methods sticker as a
   button, white with its hairline and soft shadow, in OffBit 101 Bold, in
   black (his call; the sticker's words are blue). Upright, as a button,
   and picked up a little under the pointer, as the stickers are (not
   under reduced motion). The same on V6, the Films pages and the Resume.
   Its top padding is 0.18em more than its foot: OffBit's capitals sit
   0.1em above the middle of their line (measured, on V4's pills).
   White on the black, its words black; no dusk shadow on them in the dream.
   =========================================================================== */
:root { --ease-pop: cubic-bezier(0.34, 1.56, 0.64, 1); }

.pill {
  height: auto;
  min-height: 0;
  padding: 0.6em 1em 0.42em;
  border: 0;
  background: var(--card);
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.07), 0 0.1em 0.4em rgb(0 0 0 / 0.12);
  color: var(--ink);
  text-shadow: none;
  transition: box-shadow var(--dur-s) var(--ease);
}

.pill:hover, .pill:focus-visible { background: var(--card); color: var(--ink); box-shadow: 0 0 0 1px rgb(0 0 0 / 0.1), 0 0.25em 0.8em rgb(0 0 0 / 0.16); }

@media (prefers-reduced-motion: no-preference) {
  .pill { transition: translate var(--dur-m) var(--ease-pop), rotate var(--dur-m) var(--ease-pop), box-shadow var(--dur-s) var(--ease); }
  .pill:hover, .pill:focus-visible { translate: 0 -0.12em; rotate: -2deg; }
}
