/* BARLUNGO STUDIO.
 *
 * One stylesheet. It holds NO COLOUR OF ITS OWN: every value here is a custom
 * property from tokens.css, or one of those properties mixed with transparent.
 * A test fails the build if a raw hex, rgb() or hsl() literal appears in this
 * file, so a new colour has to be a token — which is what keeps four project
 * worlds from leaking into each other.
 *
 * The structure follows the page: reset, type, chrome, hero, then one block per
 * component in lib/sections.js, then the world-specific overrides, then motion
 * and the reduced-motion rule, then the breakpoints.
 */

/* ----------------------------------------------------------------- reset */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body,
h1,
h2,
h3,
p,
figure,
figcaption,
dl,
dd,
ul {
  margin: 0;
  padding: 0;
}

ul {
  list-style: none;
}

img,
video {
  display: block;
  max-width: 100%;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

a {
  color: inherit;
  text-decoration: none;
}

/* ------------------------------------------------------------------ base */

body {
  background: var(--ground);
  color: var(--fg);
  font-family: var(--font-display);
  font-size: var(--size-body);
  font-weight: 400;
  line-height: 1.55;
  /* Nothing on this site scrolls sideways. Any component that would is wrong,
     and this keeps a wrong one from reaching the visitor as a jitter. */
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* The one interactive affordance, applied once so no component forgets it.
   Keyboard focus is visible everywhere; a mouse click does not draw it. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 0.75rem 1rem;
  background: var(--ink);
  color: var(--bone);
  font-family: var(--font-mono);
  font-size: var(--size-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.skip:focus {
  left: 0.5rem;
  top: 0.5rem;
}

/* ------------------------------------------------------------------ type */

.label {
  font-family: var(--font-mono);
  font-size: var(--size-label);
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg-soft);
}

.line {
  display: block;
}

/* In the document, not on the screen. Used where artwork already carries the
   words: the heading keeps the page outline and the section's accessible name,
   and the picture does the showing. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.lede {
  font-size: var(--size-sm);
  line-height: 1.5;
  max-width: var(--measure);
}

/* THE MUSIC BIOS READ A TENTH SMALLER. --size-sm is a display size as much as
   a reading one -- it sets eyebrows, captions and status lines as well as this
   -- and at the top of its range it carried the artist bios larger than they
   want to be read. Taken off the token rather than restated as a number, so it
   still tracks --size-sm through both the base scale and the large-display
   tier, where the ceiling is more than twice as high.
   SCOPED TO .artist-page: the character pages set their copy in .lede too, and
   this was a judgement about the music bios. */
.artist-page .lede {
  font-size: calc(var(--size-sm) * 0.9);
}

p + p {
  margin-top: 1.1em;
}

strong {
  font-weight: 500;
}

/* ---------------------------------------------------------------- chrome */

/* The header is type over the page, not a bar on top of it.
 *
 * It always carries a veil — a short gradient from the studio near-black — so
 * the wordmark reads over anything beneath it, including the cream film world.
 * Scrolling deepens it into a blurred ground; that is the whole of the
 * "slightly more solid" behaviour, and it never becomes a navbar.
 */
.site-header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 50;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.5rem;
  padding: clamp(1rem, 2.5vw, 1.75rem) var(--gutter);
  color: var(--bone);
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--ink) 62%, transparent),
    color-mix(in srgb, var(--ink) 0%, transparent)
  );
  transition: background var(--t-base) var(--ease), backdrop-filter var(--t-base) var(--ease);
}

.site-header[data-scrolled] {
  background: color-mix(in srgb, var(--ink) 82%, transparent);
  backdrop-filter: blur(14px) saturate(120%);
  box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--bone) 12%, transparent);
}

.wordmark {
  display: block;
  font-size: clamp(0.8125rem, 1.1vw, 0.9375rem);
  font-weight: 500;
  line-height: 1.08;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.wordmark-studio {
  color: color-mix(in srgb, var(--bone) 62%, transparent);
}

/* The home page renders no wordmark, so nothing pushes the navigation right.
   This holds it there on every page, with or without one. */
.nav-toggle,
.site-nav {
  margin-left: auto;
}

.site-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(0.9rem, 2vw, 1.9rem);
  justify-content: flex-end;
}

.nav-link {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--size-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--bone) 78%, transparent);
  padding-block: 0.25rem;
  border-bottom: 1px solid transparent;
  transition: color var(--t-quick) var(--ease), border-color var(--t-quick) var(--ease);
}

.nav-link:hover,
.nav-link:focus-visible {
  color: var(--bone);
}

.nav-link.is-current {
  color: var(--bone);
  border-bottom-color: var(--accent);
}

/* The toggle exists only on small screens. Progressive by design: the panel is
   collapsed by the stylesheet ONLY once studio.js has marked the document
   ready, so with the script blocked the links render as a plain list and the
   navigation still works. */
.nav-toggle {
  display: none;
  color: var(--bone);
  letter-spacing: 0.2em;
}

/* ------------------------------------------------------------------ hero */

/* The copy sits on the left, optically centred in the frame rather than
   anchored to the floor: the hero image puts its subject in the lower right,
   and bottom-left type crowds it. The extra top padding is what makes centred
   read as centred once the header is accounted for. */
.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  /* STACKED BY DEFAULT. A phone crops the frame so hard that the bird fills the
     width and there is nothing to sit beside, so the copy drops to the foot of
     the frame and clears it vertically instead. */
  align-content: end;
  justify-items: start;
  padding: clamp(6rem, 15vh, 9rem) var(--gutter) clamp(4rem, 11vh, 7rem);
  background: var(--ground-deep);
  isolation: isolate;
}


/* Full width by default — on a phone the frame is cropped so hard that there is
   no room beside the bird, and the copy goes under it instead (see the stacked
   case below). The right-hand column is a wide-viewport arrangement only. */
.hero-copy {
  max-width: 100%;
}
/* SIDE BY SIDE once there is room. The guardabarranco occupies the left ~40% of
   the frame — wingtip to beak — and the open water to its right is where the
   type goes. The cap is what keeps the wordmark off the bird; the type scale is
   set to fit inside it, so the two move together. */
@media (min-width: 64rem) {
  .hero {
    align-content: center;
    justify-items: end;
  }

  .hero-copy {
    /* 56%, not 58%: the tightest case is a 4:3 laptop, where cover crops the
       sides of a 16:9 frame and the bird lands further right than it does on a
       wide screen. Measured at 1024 — the narrowest width that still goes side
       by side — the beak is the thing that decides this number. */
    max-width: 56%;
    /* ONE RIGHT-HAND AXIS. The navigation above and the SCROLL cue below are
       already set to the gutter; setting the copy to it as well makes those
       three a single edge rather than three near-misses. It also turns the
       ragged edge toward the bird, which is where an irregular contour belongs
       — left-aligned, only BARLUNGO reached the axis and STUDIO fell 180px
       short of it, which read as an accident rather than a decision. */
    text-align: right;
  }

  /* A capped measure inside a right-aligned block still has to be pushed to the
     axis: left to itself the box sits at the block's left edge and breaks the
     one alignment the composition is built on. */
  .hero-descriptor {
    margin-left: auto;
  }
}

.hero-media {
  position: absolute;
  inset: 0;
  z-index: -2;
  overflow: hidden;
}

.hero-media .plate,
.hero-media .plate img {
  width: 100%;
  height: 100%;
}

.hero-video {
  /* Layered over the still, which stays underneath as the portrait-phone hero,
     the reduced-motion hero, and what shows while the clip buffers. `cover`
     keeps the frame's own proportions — it is cropped, never stretched. The
     bird lives on the right of this frame, so the crop is anchored there.

     85.5%, AND THE ROAD TO IT RAN THROUGH THREE WRONG ANSWERS. Scanning 24
     frames for the bird's COLOUR puts it at x 54.5–85.3%, but colour is not
     the bird: the beak, the leading wingtip and the two thread-thin tail
     streamers are near-black and carry none of it. Reading a gridded frame by
     eye corrected that to 51–86% and was still short at the beak. What
     settled it was differencing the frames — the bird is the only thing in
     the shot that moves much, so the spread between each pixel's brightest
     and darkest moment finds it whatever colour it is. THE BIRD IS x 51–88.5%,
     37.5% of the frame's width.

     THE THIRD WRONG ANSWER WAS FORGETTING THE DRIFT. The hero's slow Ken
     Burns move scales this element from 1.04 to 1.12 and slides it, and
     `.hero-media` clips the overflow — so the window on to the frame is 1/s
     of what `cover` alone gives. A 0.75 screen looks through 28.7% of the
     frame at the far end of the drift, not 32.1%, and an anchor computed
     without that cut the beak for part of every cycle.

     85.5% is the lowest value whose right edge clears 88.5% at EVERY MOMENT
     of the drift, on every shape the gate admits. Where the frame is too
     narrow to hold the whole bird the crop then takes the trailing wingtip
     and never the face; lower would show exactly as much bird and cut the
     beak instead, which is why the arithmetic optimum is not the right
     answer. On a full-bleed landscape screen the whole bird is on view and
     this number stops mattering — and on an upright screen the clip is not
     full-bleed at all, but a band, which is the only arrangement where the
     whole bird survives there. See the band below. */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 85.5% 50%;
  /* Not shown at all until the script attaches a source: below the breakpoint
     there is nothing to reveal, and an empty video box would paint black. */
  display: none;
}

.hero-video[data-hero-attached] {
  display: block;
}

/* The hero's empty-state label clears the header, which sits over the same
   corner. Only the empty state carries a label, so a delivered file is
   unaffected by this. */
.hero-plate.plate-empty {
  padding-top: clamp(4.5rem, 11vh, 6rem);
}

/* Anchored to the corner the copy sits in rather than spread over the frame:
   a band across the whole image dims the picture to lift the type. */
/* Weighted to the side the copy is on rather than spread over the frame: a band
   across the whole image dims the picture to lift the type.

   Tuned against the real photograph, not a placeholder. The guardabarranco
   frame is bright turquoise water exactly where the copy sits, and the first
   version of this scrim — built while the slot was still an empty dark plate —
   left the descriptor washed out. The left side now carries most of the weight
   and holds it further across, and a soft pool sits under the copy block
   itself, which is centred rather than on the floor. */
.hero-scrim {
  position: absolute;
  inset: 0;
  /* ABOVE THE PLATE, not below it. `.hero-media` carries a z-index and so opens
     a stacking context; -1 in here is behind the photograph, which is where
     this gradient sat, invisible, until it was painted solid to find out. The
     copy is a sibling of `.hero-media` and still draws over both. */
  z-index: 1;
  background:
    /* Seated under the copy block. The right of this frame is the sun's
       reflection — the brightest water in the picture — and sampling the pixels
       behind the descriptor gave 1.05:1 against bone before any scrim. This is
       what buys that back, so it holds the plateau further out rather than
       falling away at half radius. */
    radial-gradient(
      ellipse 68% 58% at 76% 56%,
      color-mix(in srgb, var(--ink) 62%, transparent) 0%,
      color-mix(in srgb, var(--ink) 46%, transparent) 46%,
      color-mix(in srgb, var(--ink) 16%, transparent) 76%,
      color-mix(in srgb, var(--ink) 0%, transparent) 100%
    ),
    linear-gradient(
      to left,
      color-mix(in srgb, var(--ink) 52%, transparent) 0%,
      color-mix(in srgb, var(--ink) 38%, transparent) 34%,
      color-mix(in srgb, var(--ink) 14%, transparent) 62%,
      color-mix(in srgb, var(--ink) 0%, transparent) 86%
    ),
    linear-gradient(
      to top,
      color-mix(in srgb, var(--ink) 58%, transparent) 0%,
      color-mix(in srgb, var(--ink) 0%, transparent) 38%
    );
}

/* The copy carries its own contrast, from a shadow that hugs the letterforms.
   The alternative is a scrim heavy enough to survive bright surf behind the
   descriptor, and that dims the photograph to protect three lines of type —
   which is the wrong trade when the photograph is the point. */
.hero-copy {
  text-shadow:
    0 1px 2px color-mix(in srgb, var(--ink) 55%, transparent),
    0 2px 18px color-mix(in srgb, var(--ink) 65%, transparent);
}

.hero-title {
  font-size: var(--size-hero);
  font-weight: 500;
  line-height: 0.86;
  letter-spacing: -0.035em;
  text-transform: uppercase;
}

.hero-disciplines {
  margin-top: clamp(1.25rem, 3vh, 2rem);
  /* Full bone rather than the muted tint the other detail type uses: this line
     sits on a photograph, where the muting that reads as restraint on a flat
     ground reads as faint. Measured against the pixels actually behind it, bone
     gives 6.1:1 before the scrim — the weight stays as designed. */
  color: var(--bone);
  letter-spacing: 0.22em;
  /* A tight dense halo and a wide soft one. The tight pass is what survives the
     specular highlights on the water, which are small and very bright; the wide
     pass seats the line on the photograph rather than floating it. */
  text-shadow:
    0 0 2px color-mix(in srgb, var(--ink) 92%, transparent),
    0 1px 4px color-mix(in srgb, var(--ink) 88%, transparent),
    0 0 18px color-mix(in srgb, var(--ink) 82%, transparent);
}

/* When the discipline line is set, the descriptor follows it closely — they are
   one block. With the line removed the descriptor becomes the first thing under
   the wordmark and takes the space the line used to provide, so the fold does
   not read as two lines jammed together. */
.hero-title + .hero-descriptor {
  margin-top: clamp(1.25rem, 3vh, 2rem);
}

.hero-descriptor {
  margin-top: 0.5rem;
  max-width: 34rem;
  font-size: var(--size-sm);
  text-shadow:
    0 0 2px color-mix(in srgb, var(--ink) 92%, transparent),
    0 1px 4px color-mix(in srgb, var(--ink) 88%, transparent),
    0 0 18px color-mix(in srgb, var(--ink) 82%, transparent);
  /* Near-bone rather than the muted grey: this line sits on a photograph, and
     a mid grey that reads on a flat dark ground does not survive water. */
  color: color-mix(in srgb, var(--bone) 90%, transparent);
}

.hero-cue {
  position: absolute;
  right: var(--gutter);
  bottom: clamp(3rem, 9vh, 7rem);
  writing-mode: vertical-rl;
  letter-spacing: 0.4em;
  color: color-mix(in srgb, var(--bone) 45%, transparent);
}

/* ----------------------------------------------------------------- world */

/* A world is a room: it sets the ground and the ink, and everything inside
   inherits. The cut between two of them is deliberate and hard — no fade,
   because a fade would blend palettes the brief asks to keep apart. */
.world {
  background: var(--ground);
  color: var(--fg);
  padding-block: var(--section);
}

/* A section whose own media runs to the edges supplies its own rhythm. */
.section-flush {
  padding-block: 0;
}

.page-head {
  /* Clears the fixed header on an inner page, where there is no hero to sit
     under it. */
  padding-top: clamp(7rem, 16vh, 11rem);
}

/* A HEAD THAT IS ONLY A TITLE OWNS THE FIRST SCREEN. On /work/ the opener sat
   in a tall section with the index beginning right under it, so on a large
   desktop the page opened with ONE BODY OF WORK, a field of empty black, and
   then the top two inches of the next section's lettering cut off by the fold
   — which reads as a mistake rather than as space.

   MARKED BY A CLASS, NOT INFERRED. This was `:has(> .opener:only-child)`,
   which was clever and immediately wrong: adding the SCROLL cue inside the
   section gave the opener a sibling, the selector stopped matching, and the
   head silently reverted to being short. A page either opens on its title or
   it does not — that is a decision the template should state, not something
   the stylesheet guesses from the shape of the markup. The plain .page-head
   class still wraps the whole of the shop and the music profiles, where a
   full-height centred box would push the content a screen down. */
.page-head-full {
  /* FOUR FIFTHS, NOT THE WHOLE SCREEN. At 100svh the head owned the first
     screen exactly, which meant the page that exists to show the work opened
     showing none of it -- the first entry began one pixel below the fold on
     every laptop. 80svh keeps the composition and the air that goes with it,
     and lifts the top of the index into the bottom of the screen, so the page
     says what it is before you touch the scroll wheel. */
  min-height: 80svh;
  display: grid;
  align-content: center;
  position: relative;
  /* MOST OF THE AIR BELOW GOES. This matched the padding above so the title
     sat on the optical centre, which cost 144px at the bottom of the screen
     -- and that, plus the index section's own 108px, is what kept the first
     work entry off a laptop entirely. At 1440x900 the head comes down from
     900px to 720px and 72px of the index comes into view, of which 40px is
     the top edge of the first plate.

     NOT a change to the bottom alone, despite how it reads: the head is
     align-content:center, so taking 90px off the bottom hands about half of
     it back to the top and the eyebrow moves from 24% of the screen to 19%.
     Worth knowing before reaching for padding-top to tune the air above --
     these two are coupled, and changing either moves the title. */
  padding-bottom: clamp(2.5rem, 6vh, 4rem);
}

/* WHEN THE HEAD IS THE WHOLE SCREEN, THE TITLE FILLS IT. Sized by measuring
   rather than by feel: the lettering was measured against the viewport at a
   range of sizes, and the answer is almost exactly linear —

       8vw  -> 40% of the width
      10vw  -> 50%
      12vw  -> 60%
      14vw  -> 70%

   The section-opener size put it at 20%, and the hero size at 35%, both of
   which read as a caption on a screen with nothing else on it. 13vw holds it
   at about 65% at every width, which is a page opening on its own title.

   NOT var(--size-hero), which this briefly was: the home hero shares its
   screen with a bird and has to leave room for it, so it is deliberately
   smaller than a title that has the screen to itself. Two different jobs.
   The cap is high on purpose — it exists to stop the line colliding with the
   gutters on an enormous display, not to stop it growing. */
.page-head-full .opener-title {
  font-size: clamp(2.75rem, 13vw, 30rem);
}

/* And the same vertical SCROLL mark the hero carries, for the same reason: a
   screen holding nothing but a title gives no sign that there is more below
   it. Right-hand side, matching the hero's. */
.head-cue {
  position: absolute;
  right: var(--gutter);
  bottom: clamp(3rem, 9vh, 7rem);
  writing-mode: vertical-rl;
  letter-spacing: 0.4em;
  color: color-mix(in srgb, var(--bone) 45%, transparent);
}

.band {
  padding-inline: var(--gutter);
  margin-top: clamp(2rem, 5vh, 3.5rem);
}

/* The RELEASES band can carry a catalogue link — an artist channel that covers
   the whole body of work rather than one record. It sits on the heading's
   baseline, after a gap, so it reads as an aside to the section rather than a
   second heading. It wraps under on a narrow screen. */
.band-releases {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.75rem clamp(1rem, 3vw, 2rem);
}

.band-releases .links {
  margin: 0;
}

.band-measure {
  max-width: calc(var(--measure) + var(--gutter) * 2);
}

.band-tail {
  margin-top: clamp(2.5rem, 6vh, 4rem);
}

.empty-note {
  padding-inline: var(--gutter);
  color: var(--fg-soft);
}

/* ---------------------------------------------------------------- opener */

.opener {
  padding-inline: var(--gutter);
}

.opener-eyebrow {
  color: var(--accent-soft);
  margin-bottom: clamp(1rem, 2.5vh, 1.75rem);
}

/* NO EYEBROW: THE TITLE CLEARS THE HEADER ITSELF.
 *
 * Dropping the eyebrow takes away two different things — the line of type it
 * occupied, and the gap the design put beneath it. Only the SECOND is worth
 * keeping. Restoring both would leave exactly the empty slot the eyebrow used
 * to fill; restoring neither drops a 102px heading to 59px under a fixed header
 * and reads as crowding, not as a decision.
 *
 * So this gives back the gap and not the line box. The value is the eyebrow's
 * own margin-bottom, reused rather than reinvented, so the two cases stay in
 * step if that rhythm is ever retuned.
 *
 * Below the title, the dek opens up a little: with only two elements left the
 * pair has to carry the whole composition, and the tighter gap that read
 * correctly as the third item in a stack reads as crowding as the second.
 */
.opener-bare {
  padding-top: clamp(1rem, 2.5vh, 1.75rem);
}

.opener-bare .opener-dek {
  margin-top: clamp(1.5rem, 3.5vh, 2.25rem);
}

.opener-title {
  font-size: var(--size-xl);
  font-weight: 500;
  line-height: 0.9;
  letter-spacing: -0.03em;
  text-transform: uppercase;
}

.opener-sub .opener-title {
  font-size: var(--size-lg);
}

/* The roster: names under the section title, in the detail face. It is a list
   of who, not a sentence about them. */
.opener-roster {
  margin-top: clamp(1rem, 2.5vh, 1.5rem);
  letter-spacing: 0.22em;
  color: color-mix(in srgb, var(--fg) 72%, transparent);
}

.opener-dek {
  margin-top: clamp(1rem, 2.5vh, 1.75rem);
  max-width: var(--measure);
  font-size: var(--size-sm);
  color: var(--fg-soft);
}

.section-title {
  font-size: var(--size-md);
  font-weight: 500;
  letter-spacing: -0.01em;
  text-transform: uppercase;
}

.section-label {
  color: var(--accent-soft);
}

/* The one piece of pure typography on the site: the line that carries the
   visitor from the songs into the world. */
.transition {
  padding-inline: var(--gutter);
  margin-top: clamp(3rem, 8vh, 6rem);
  font-size: var(--size-lg);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--fg) 58%, transparent);
}

/* ----------------------------------------------------------------- plate */

/* Every image on the site sits in a plate. The plate owns the frame; the file
   is cropped to it. */
.plate {
  position: relative;
  overflow: hidden;
  background: color-mix(in srgb, var(--fg) 5%, transparent);
}

.plate img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* THE DESIGNED EMPTY STATE. A slot with no file yet is a framed, labelled
   plate — intentional while the art direction is outstanding, and never a
   broken image or a collapsed box. */
.plate-empty {
  display: grid;
  /* The slot name sits in the corner, as an annotation would. Centred, it
     collides with the copy that bottom-anchored frames set over the plate. */
  place-items: start;
  align-content: start;
  padding: 1rem;
  text-align: left;
  background:
    repeating-linear-gradient(
      135deg,
      color-mix(in srgb, var(--fg) 4%, transparent) 0 1px,
      transparent 1px 9px
    ),
    color-mix(in srgb, var(--fg) 3%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--fg) 14%, transparent);
}

.plate-slot {
  font-family: var(--font-mono);
  font-size: var(--size-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--fg) 46%, transparent);
}

.figure figcaption {
  margin-top: 0.75rem;
  display: grid;
  gap: 0.35rem;
}

.figure-caption {
  font-size: var(--size-label);
  color: var(--fg-soft);
  letter-spacing: 0;
  text-transform: none;
  font-family: var(--font-display);
}

/* ------------------------------------------------------------------- cta */

/* Type with a rule under it. Not a pill, not a button, and the rule draws in
   on hover rather than the whole shape changing. */
.cta {
  position: relative;
  display: inline-block;
  padding-block: 0.4rem;
  color: var(--fg);
  letter-spacing: 0.2em;
}

.cta-rule {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--accent);
  transform-origin: left;
  transform: scaleX(0.35);
  transition: transform var(--t-base) var(--ease);
}

.cta:hover .cta-rule,
.cta:focus-visible .cta-rule {
  transform: scaleX(1);
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1.25rem, 3vw, 2.5rem);
  margin-top: clamp(1.5rem, 4vh, 2.5rem);
}

/* A destination that has not been supplied says so, rather than being a link
   that goes nowhere. */
.cta-pending {
  color: var(--fg-soft);
  border-bottom: 1px dashed color-mix(in srgb, var(--fg) 24%, transparent);
}

.cta-note {
  letter-spacing: 0.08em;
  text-transform: none;
}

.links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  margin-top: 1rem;
}

.links a {
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  padding-bottom: 2px;
  transition: color var(--t-quick) var(--ease), border-color var(--t-quick) var(--ease);
}

.links a:hover,
.links a:focus-visible {
  color: var(--fg);
  border-bottom-color: var(--accent);
}

/* A release that is finished but not yet distributed. Deliberately NOT styled
   like the link list above it — no underline, no hover, no amber — because it
   is a statement about the record rather than a way to reach it. Sits in the
   same muted register the site uses elsewhere for a pending state. */
.links-note {
  margin-top: 1rem;
  color: color-mix(in srgb, var(--fg) 38%, transparent);
}

/* --------------------------------------------------------------- credits */

.credits {
  display: grid;
  gap: 0.9rem;
  margin-top: 1.5rem;
}

/* A BARLUNGO STUDIO FILM. The authorship line, above the list and in the same
   mono register as the section labels, so it reads as the statement the credits
   hang under rather than as a first credit row. */
.credits-head {
  display: block;
  margin-top: 1.5rem;
  color: var(--fg-soft);
}

/* With the head line present the list no longer needs its own top margin: the
   head supplies it, and two stacked margins opened a gap the band did not want. */
.credits-head + .credits {
  margin-top: 1rem;
}

/* THE TOOLS, SET APART. Same quiet register as .figure-caption, which is this
   site's way of annotating rather than crediting. Keeping them out of the
   credit list is the point: a tool is not an author, and a ROLE / NAME row
   would read as one. */
.credits-note {
  margin-top: 1.5rem;
  font-size: var(--size-label);
  font-family: var(--font-display);
  line-height: 1.7;
  color: var(--fg-soft);
}

.credits-row {
  display: grid;
  gap: 0.15rem;
}

.credits dd {
  font-size: var(--size-sm);
}

/* ------------------------------------------------------------------ film */

/* Full bleed and immersive. The film is never reduced to a card. */
.film-feature {
  position: relative;
  min-height: clamp(34rem, 92svh, 60rem);
  display: grid;
  align-content: end;
  padding: clamp(5rem, 14vh, 9rem) var(--gutter) clamp(3rem, 9vh, 6rem);
  background: var(--ground-deep);
  isolation: isolate;
  overflow: hidden;
}

.film-feature-media {
  position: absolute;
  inset: 0;
  z-index: -2;
}

.film-feature-media .plate,
.film-feature-media .plate img {
  width: 100%;
  height: 100%;
}

/* The film world is cream, so its scrim lifts from its own ground rather than
   from the studio black: a dark band under cream type would read as a different
   site. */
.film-scrim {
  position: absolute;
  inset: 0;
  /* Same stacking trap as the hero: inside a wrapper that opens a context, so
     it has to be above the plate rather than behind it. */
  z-index: 1;
  background: linear-gradient(
    to top,
    color-mix(in srgb, var(--ground) 92%, transparent) 0%,
    color-mix(in srgb, var(--ground) 58%, transparent) 38%,
    color-mix(in srgb, var(--ground) 0%, transparent) 78%
  );
}

.film-title {
  margin-top: 0.75rem;
  font-size: var(--size-xl);
  font-weight: 500;
  line-height: 0.9;
  letter-spacing: -0.03em;
  text-transform: uppercase;
}

.film-subtitle {
  margin-top: clamp(0.75rem, 2vh, 1.25rem);
  font-size: var(--size-md);
  font-weight: 400;
  font-style: italic;
  letter-spacing: -0.01em;
}

.film-standfirst {
  margin-top: 0.75rem;
  max-width: var(--measure);
  color: var(--fg-soft);
}

.film-meta {
  margin-top: clamp(1.25rem, 3vh, 2rem);
}

/* FINISHED KEY ART. The artwork carries its own title and production credit, so
   it is shown whole at its own ratio — no fixed height, no cover crop, no scrim
   over it — and the copy sits beneath rather than on top. This is the one place
   on the site where an image sizes the box instead of filling one. */
.film-feature-art {
  display: block;
  min-height: 0;
  padding: 0 0 clamp(2.5rem, 7vh, 4.5rem);
  overflow: visible;
}

.film-feature-art .film-feature-media {
  position: static;
  inset: auto;
}

.film-feature-art .film-plate {
  width: 100%;
  height: auto;
}

/* ------------------------------------------------------------ film player */

/* The key art is the play control. It keeps the artwork's own box exactly —
   the glyph is drawn over it, nothing is scaled or cropped — so turning the
   image into a button changes no layout. */
.film-play,
.media-launch {
  position: relative;
  display: block;
  cursor: pointer;
}

.film-play-glyph,
.media-launch-glyph {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
}

.film-play-glyph svg,
.media-launch-glyph svg {
  width: clamp(3.75rem, 8vw, 5.5rem);
  height: auto;
  /* Over finished key art the glyph is drawn in the artwork's own light rather
     than in an accent: a coloured disc would compete with the title baked into
     the frame. */
  fill: none;
  filter: drop-shadow(0 2px 14px color-mix(in srgb, var(--shade) 45%, transparent));
  transition: transform 320ms cubic-bezier(0.2, 0.7, 0.3, 1),
    opacity 320ms cubic-bezier(0.2, 0.7, 0.3, 1);
}

.film-play-glyph circle,
.media-launch-glyph circle {
  stroke: color-mix(in srgb, var(--glare) 88%, transparent);
  stroke-width: 2;
  fill: color-mix(in srgb, var(--shade) 28%, transparent);
}

.film-play-glyph path,
.media-launch-glyph path {
  fill: color-mix(in srgb, var(--glare) 94%, transparent);
}

/* The launch arrow is drawn, not filled — a play triangle is a solid shape and
   an arrow is a line, and giving them the same treatment made the arrow read as
   a blob at small sizes. */
.media-launch-glyph path {
  fill: none;
  stroke: color-mix(in srgb, var(--glare) 94%, transparent);
  stroke-width: 3.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* AND IT SITS IN THE CORNER, not the middle. The film's play control is centred
   because the centre of that key art is open water; the centre of a product
   screen is its headline, and the arrow landed straight on WRITE TO THE BEAT.
   The corner is also where an outward link is conventionally offered. */
.media-launch-glyph {
  place-items: end;
  padding: clamp(0.85rem, 2vw, 1.4rem);
}

.media-launch-glyph svg {
  width: clamp(2.25rem, 3.4vw, 3rem);
}

.film-play:hover .film-play-glyph svg,
.film-play:focus-visible .film-play-glyph svg,
.media-launch:hover .media-launch-glyph svg,
.media-launch:focus-visible .media-launch-glyph svg {
  transform: scale(1.08);
}

.film-play:focus-visible,
.media-launch:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
}

/* The fallback box only. The script overrides this with the measured ratio of
   the artwork it replaced, which is what actually keeps the page still. */
.film-player {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--shade);
}

.film-embed {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

.film-feature-art .film-plate img {
  width: 100%;
  height: auto;
  /* Belt and braces: the plate already carries the artwork's own ratio, so
     there is nothing to crop, and contain guarantees it even if a replacement
     of a different size is dropped in before the ratio is updated. */
  object-fit: contain;
}

.film-feature-art .film-feature-copy {
  padding-inline: var(--gutter);
  padding-top: clamp(1.75rem, 5vh, 2.75rem);
}

.film-feature-art .film-standfirst {
  margin-top: clamp(0.5rem, 2vh, 1rem);
  max-width: 44rem;
  font-size: var(--size-sm);
  color: var(--fg);
}

.film-rows {
  margin-top: clamp(2.5rem, 6vh, 4rem);
  padding-inline: var(--gutter);
  display: grid;
  gap: clamp(2.5rem, 6vh, 4.5rem);
}

/* The row is the grid. It used to be the link, but the artwork now plays the
   film while the copy goes to the project, which is two destinations and so
   cannot be one anchor wrapping both. */
.film-row {
  display: grid;
  gap: clamp(1rem, 3vw, 2rem);
  grid-template-columns: auto minmax(0, 18rem) minmax(0, 1fr);
  align-items: start;
}

.film-row-index {
  color: var(--accent-soft);
}

.film-row-copy {
  display: grid;
  gap: 0.4rem;
}

.film-row-title {
  display: block;
  font-size: var(--size-md);
  font-weight: 500;
  letter-spacing: -0.01em;
  text-transform: uppercase;
}

.film-row-subtitle {
  display: block;
  font-style: italic;
  color: var(--fg-soft);
}

.film-row-plate {
  transition: opacity var(--t-base) var(--ease);
}

/* The plate dims for its own control now, not for the title's. */
.film-row .film-play:hover .film-row-plate,
.film-row .film-play:focus-visible .film-row-plate {
  opacity: 0.82;
}

/* At index scale the glyph is smaller than it is over the full-bleed feature —
   the control should read without covering the key art's own title. */
.film-row .film-play-glyph svg {
  width: clamp(2.5rem, 4vw, 3.25rem);
}

/* ------------------------------------------------------------- soundtrack */

/* A list of songs, set as rows with a hairline between them — the same editorial
   device the front door uses for its destinations. A title with a release links
   to its artist; one without is simply named, which is how a song can belong to
   the film before it has artwork. */
.soundtrack {
  margin-top: clamp(1rem, 3vh, 1.75rem);
  display: grid;
  gap: 0;
  max-width: 46rem;
}

.soundtrack-row {
  border-top: 1px solid color-mix(in srgb, var(--fg) 16%, transparent);
}

.soundtrack-row:last-child {
  border-bottom: 1px solid color-mix(in srgb, var(--fg) 16%, transparent);
}

.soundtrack-row,
.soundtrack-link {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 1.25rem;
}

.soundtrack-link {
  width: 100%;
  position: relative;
}

.soundtrack-row > .soundtrack-title,
.soundtrack-link {
  padding-block: clamp(0.75rem, 2vh, 1.1rem);
}

.soundtrack-title {
  font-size: var(--size-md);
  font-weight: 500;
  letter-spacing: -0.01em;
  text-transform: uppercase;
}

.soundtrack-artist {
  color: var(--fg-soft);
}

/* The rule draws in on hover, the same gesture every other call to action uses. */
.soundtrack-link::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -1px;
  height: 1px;
  width: 100%;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t-base) var(--ease);
}

.soundtrack-link:hover::after,
.soundtrack-link:focus-visible::after {
  transform: scaleX(1);
}

/* Three across on a wide screen: the stills are 16:9 and sequential, so a row
   of them reads as a strip from the film. A two-column grid would leave the
   third one orphaned on its own line. */
.gallery {
  margin-top: clamp(2rem, 5vh, 3.5rem);
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(0.75rem, 2vw, 1.5rem);
}

.cast {
  display: flex;
  flex-wrap: wrap;
  gap: 2rem;
  margin-top: 1rem;
}

/* ----------------------------------------------------------------- music */

.artist-row {
  margin-top: clamp(2.5rem, 7vh, 5rem);
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  /* ALIGNED ON THE TOP EDGE. This used to align on the BOTTOM, because the
     tiles carried different native ratios — a square cover beside standing
     portraits — and bottom alignment was what put the four names on one line.
     Every plate is 2:3 now, so that reason is gone, and bottom alignment had
     become the bug: below about 1520px the two longer role lines wrap to two
     lines, and anchoring the bottom pushed those two tiles 20px higher than
     the other two. Aligning the tops holds the photographs level, which is the
     thing the eye actually reads across. */
  align-items: start;
  gap: clamp(1rem, 2.5vw, 2rem);
}

/* The names then sit on one line because the plates are the same height, and
   the role lines take whatever room they need beneath without moving them. */
.artist-meta {
  align-content: start;
}

.artist-plate {
  transition: opacity var(--t-base) var(--ease);
}

.artist-link:hover .artist-plate,
.artist-link:focus-visible .artist-plate {
  opacity: 0.85;
}

.artist-meta {
  display: grid;
  gap: 0.3rem;
  margin-top: 1rem;
}

.artist-index {
  color: var(--accent-soft);
}

.artist-name {
  font-size: var(--size-md);
  font-weight: 500;
  letter-spacing: -0.01em;
  text-transform: uppercase;
}

.release-grid {
  margin-top: clamp(2rem, 5vh, 3.5rem);
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.5rem, 4vw, 3rem);
}

.release-copy {
  margin-top: 1.1rem;
  display: grid;
  gap: 0.3rem;
}

.release-title {
  font-size: var(--size-sm);
  font-weight: 500;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

.release-artist {
  color: var(--fg-soft);
  font-size: var(--size-label);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-family: var(--font-mono);
}

.release .credits {
  margin-top: 0.75rem;
  gap: 0.4rem;
}

.release .credits dd {
  font-size: var(--size-label);
  font-family: var(--font-mono);
  letter-spacing: 0.08em;
}

/* A placeholder record is visibly one. It cannot be mistaken for a release. */
.release.is-pending .release-title {
  color: var(--fg-soft);
}

.release-flag {
  color: color-mix(in srgb, var(--accent) 80%, transparent);
  letter-spacing: 0.1em;
}

.artist-page,
.character-page {
  margin-top: clamp(2.5rem, 6vh, 4rem);
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: clamp(1.5rem, 5vw, 4rem);
  align-items: start;
}

/* The artist page carried a figure wrapper and the artists row a footnote,
   both of them holding a caption saying the founder portraits were made with
   AI. That caption is gone from these surfaces — it put the word "Founder" on
   pages billing PRODUCER · ARTIST · CREATIVE DIRECTOR, where the term is never
   established. The fact is in the notices now, and the caption survives on the
   Studio page where the founders are presented as founders. */

/* ------------------------------------------------------------ characters */

.character-cards {
  margin-top: clamp(2.5rem, 7vh, 5rem);
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.25rem, 3vw, 2.5rem);
}

/* The character plates sit on the warm taupe ground the 3D artwork was
   rendered against, so the frame continues the photograph rather than cutting
   it out. */
.character-plate,
.view-plate,
.edition-plate {
  background: color-mix(in srgb, var(--plate, var(--taupe)) 24%, var(--ground));
}

.character-copy {
  display: grid;
  gap: 0.5rem;
  margin-top: 1.25rem;
}

.character-name {
  font-size: var(--size-lg);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.025em;
  text-transform: uppercase;
}

.character-line {
  color: var(--fg-soft);
  max-width: 24rem;
}

.character-more {
  position: relative;
  display: inline-block;
  padding-block: 0.35rem;
  width: fit-content;
  letter-spacing: 0.2em;
}

.character-link:hover .cta-rule,
.character-link:focus-visible .cta-rule {
  transform: scaleX(1);
}

/* The turnaround strip. A study, laid out as an archive sheet. */
.views {
  margin-top: clamp(1.5rem, 4vh, 2.5rem);
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(0.5rem, 1.5vw, 1.25rem);
}

.view-name {
  display: block;
  margin-top: 0.6rem;
  color: var(--fg-soft);
}

.appearances {
  margin-top: clamp(1.75rem, 4vh, 2.5rem);
}

/* ---------------------------------------------------------- collectibles */

.editions-module {
  margin-top: clamp(4rem, 11vh, 8rem);
  padding-top: clamp(3rem, 8vh, 5rem);
  border-top: 1px solid color-mix(in srgb, var(--fg) 12%, transparent);
}

.editions-module > .cta {
  margin-left: var(--gutter);
  margin-top: clamp(1.5rem, 4vh, 2.5rem);
}

.editions {
  margin-top: clamp(2rem, 5vh, 3.5rem);
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.5rem, 4vw, 3rem);
}

.edition-copy {
  margin-top: 1.25rem;
  display: grid;
  gap: 0.5rem;
}

.edition-title {
  font-size: var(--size-sm);
  font-weight: 500;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

.edition-status {
  color: var(--accent-soft);
  letter-spacing: 0.16em;
}

.edition-facts {
  margin-top: 0.75rem;
  display: grid;
  gap: 0.5rem;
}

/* -------------------------------------------------------------- software */

/* The technical room. Monospace, oversized, one restrained glow — the same
   studio, a different discipline. */
.software {
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
  position: relative;
  isolation: isolate;
}

/* WHEN THE SCREEN CARRIES THE COPY, the left column is only a label, a way in
   and the separation line — a short block against a tall image. Centring that
   leaves it floating in the middle of a void, so the arrangement changes with
   the content: the artwork takes more of the width and becomes the subject, and
   the copy is set to its top edge, where the alignment is visible and reads as
   a decision rather than as a column that ran out of things to say. */
@media (min-width: 60rem) {
  .software-art {
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    align-items: start;
  }

  .software-art .software-copy {
    /* Optical, not mathematical: the artwork's frame starts a hair below its
       box, and the eyebrow's cap height sits above its own. */
    padding-top: 0.35rem;
  }
}

.software::before {
  content: '';
  position: absolute;
  z-index: -1;
  inset: -20% -10% auto -10%;
  height: 70%;
  background: radial-gradient(
    ellipse 60% 70% at 25% 40%,
    color-mix(in srgb, var(--accent) 16%, transparent) 0%,
    color-mix(in srgb, var(--violet) 10%, transparent) 42%,
    color-mix(in srgb, var(--accent) 0%, transparent) 72%
  );
  pointer-events: none;
}

.software-eyebrow {
  color: var(--accent);
  letter-spacing: 0.34em;
}

/* A special mention, so it is set as a line of detail type rather than a badge.
   A box around it would claim more than it is. */
.software-award {
  margin-top: 0.75rem;
  color: color-mix(in srgb, var(--fg) 62%, transparent);
  letter-spacing: 0.16em;
}

.software-title {
  margin-top: clamp(1rem, 2.5vh, 1.75rem);
  font-family: var(--font-mono);
  font-size: var(--size-xl);
  font-weight: 500;
  line-height: 0.95;
  letter-spacing: -0.045em;
  text-transform: uppercase;
  text-shadow: 0 0 44px color-mix(in srgb, var(--accent) 28%, transparent);
}

.software-standfirst {
  margin-top: clamp(1.25rem, 3vh, 2rem);
  max-width: var(--measure);
  font-family: var(--font-mono);
  font-size: var(--size-sm);
  line-height: 1.5;
  color: var(--fg-soft);
}

/* The separation line. Load-bearing: Barlungo the software does not make the
   music published elsewhere on this site, and that stays on the page. */
.software-separation {
  margin-top: clamp(2rem, 5vh, 3rem);
  max-width: 32rem;
  letter-spacing: 0.06em;
  text-transform: none;
  color: color-mix(in srgb, var(--fg) 44%, transparent);
  border-left: 1px solid color-mix(in srgb, var(--cyan) 50%, transparent);
  padding-left: 1rem;
}

.software-plate {
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--fg) 12%, transparent),
    0 40px 90px -40px color-mix(in srgb, var(--accent) 36%, transparent);
}

.software-page .software {
  padding-top: clamp(1rem, 4vh, 3rem);
}

/* ---------------------------------------------------------------- studio */

.studio-note {
  margin-top: clamp(2.5rem, 6vh, 4rem);
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: start;
}

.studio-copy {
  max-width: var(--measure);
  font-size: var(--size-sm);
}

/* THE ABOUT PAGE READS AS A MAGAZINE COLUMN, NOT A MANIFESTO. Scoped to
   .page-head so it reaches the Studio page only: the home page carries the same
   .studio-copy block in a section that is one of several, and that one keeps the
   larger setting it was approved at.

   SET AT THE MIDPOINT of the two settings this column has carried. The first
   pass took --size-sm down about 6.5% to clamp(1.0625rem, 1.68vw, 1.2625rem) at
   1.45, which read small beside 312px portraits and left the left column ending
   well short of the right one. The original clamp(1.1rem, 1.8vw, 1.35rem) at
   1.55 was the manifesto setting we were moving away from. Every stop below is
   the average of the two, computed rather than eyeballed:

     floor  (1.1    + 1.0625 ) / 2 = 1.08125rem → shipped 1.08rem   (17.28px)
     pref   (1.8    + 1.68   ) / 2 = 1.74vw     → shipped 1.74vw
     cap    (1.35   + 1.2625 ) / 2 = 1.30625rem → shipped 1.305rem  (20.88px)
     lead   (1.55   + 1.45   ) / 2 = 1.5

   The job of the extra size and leading is to give the column enough weight to
   stand against the portraits, so the white space between the two reads as
   composition rather than shortfall. It is bought with type, NOT with layout:
   the measure stays 34rem, the 7fr/5fr grid and its gutter are untouched, and
   the founders block has not moved.

   1.5 also happens to be what the narrow viewport was already using, so the
   media-query override this rule used to need is gone rather than restated. */
.page-head .studio-copy {
  font-size: clamp(1.08rem, 1.74vw, 1.305rem);
  line-height: 1.5;
}

/* THE COMPOSITION STOPS GROWING. The two columns were pure fr, so every pixel
   of extra viewport was split 7:5 and handed to a text column already capped at
   34rem — all of it landing as dead air between the copy and the portraits. The
   channel measured 160px at 1280 and 889px at 2560, and the portrait plates
   inflated from 208px wide to 467px along with it. Neither is a composition; it
   is a composition being stretched.

   Capping the box freezes both at the proportions the 1280 view was approved
   at. The cap is 76rem of content plus the page gutter, which is wider than the
   content box at every viewport up to about 1344px — so nothing at or below the
   width this page was designed at moves by a pixel, and everything above it
   holds still instead of spreading:

     viewport   channel before → after     one plate before → after
     1280       160px   →  160px (unchanged)    208px → 208px
     1680       376px   →  199px                284px → 220px
     1920       516px   →  199px                334px → 220px
     2560       889px   →  199px                467px → 220px

   The opener carries the same cap so the headline and the copy keep one left
   edge: capping only the lower block would have left BARLUNGO STUDIO hanging
   out past the column it introduces. */
.studio-page .opener,
.studio-page .studio-note {
  max-width: calc(76rem + var(--gutter) * 2);
  margin-inline: auto;
}

/* The paragraph gap is set in em, so a smaller size would have quietly closed it
   up. Multiplying the FORMER size holds the rhythm exactly where it was approved
   — at every viewport width, since --size-sm is the clamp the gap used to be
   measured against. */
.page-head .studio-copy p + p {
  margin-top: calc(1.1 * var(--size-sm));
}

.creators-heading {
  margin-bottom: 1.25rem;
  color: var(--accent-soft);
}

/* The two founder portraits arrived at different ratios and keep them. They are
   paired by a shared column width and a shared top edge rather than by one
   frame: forcing identical framing would crop a standing full-length figure,
   which has nothing spare to lose.

   They align on their bottom edge rather than their top. Both are standing
   figures photographed on a floor, so the bottom edge is the ground plane —
   aligning there reads as one room rather than two cut-outs, and it puts the
   two names on the same line, which aligning the tops does not. */
.creators {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: end;
  gap: clamp(1rem, 3vw, 2rem);
}

.creator {
  display: grid;
  gap: 0.35rem;
}

/* A quiet caption, not a badge. Same register as .figure-caption, which is this
   site's existing way of annotating an image: detail size, the muted secondary
   ink, no tracking, no uppercase, no rule, no box. It sits below BOTH portraits
   and is left-aligned to the founders block, so it reads as a note about the
   pair rather than a label stuck on either person. The space above it is what
   makes it look deliberate instead of like a stray line of bio. */
.creators-disclosure {
  margin-top: clamp(1.5rem, 4vh, 2.5rem);
  max-width: 34rem;
  font-family: var(--font-display);
  font-size: var(--size-label);
  line-height: 1.5;
  letter-spacing: 0;
  text-transform: none;
  color: var(--fg-soft);
}

.creator-name {
  margin-top: 0.9rem;
  font-size: var(--size-sm);
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

/* The colophon reads as four movements rather than a list of notes, so each
   carries an index and a heading on the same line — the same furniture the work
   index and the shop categories use. */
/* The Studio page carries About, Founders and the Colophon in one column. The
   section titles sit between the opener and the detail headings inside each. */
.studio-section {
  margin-top: clamp(4rem, 11vh, 8rem);
  padding-top: clamp(2.75rem, 7vh, 4.5rem);
  padding-inline: var(--gutter);
  border-top: 1px solid color-mix(in srgb, var(--fg) 12%, transparent);
  max-width: calc(var(--measure) + var(--gutter) * 2);
}

.studio-section-title {
  font-size: var(--size-md);
  font-weight: 500;
  letter-spacing: -0.01em;
  text-transform: uppercase;
}

.studio-section-dek {
  margin-top: 0.5rem;
  color: var(--fg-soft);
  font-size: var(--size-sm);
}

.studio-section .colophon {
  margin-top: clamp(1.75rem, 5vh, 2.75rem);
}

.colophon-section + .colophon-section {
  margin-top: clamp(2.75rem, 7vh, 4.5rem);
  padding-top: clamp(2.75rem, 7vh, 4.5rem);
  border-top: 1px solid color-mix(in srgb, var(--fg) 12%, transparent);
}

.colophon-heading {
  display: flex;
  align-items: baseline;
  gap: clamp(0.9rem, 3vw, 1.75rem);
  margin-bottom: clamp(1rem, 3vh, 1.75rem);
}

.colophon-index {
  color: color-mix(in srgb, var(--fg) 40%, transparent);
}

.colophon-name {
  font-size: var(--size-md);
  font-weight: 500;
  letter-spacing: -0.01em;
  text-transform: uppercase;
}

.colophon-body {
  font-size: var(--size-sm);
}

/* Discipline on the left, the tools on the right. A short list on purpose:
   a tool earns a line here only if removing it would change the work. */
.stack {
  display: grid;
  gap: 0.75rem;
  margin-top: clamp(1.25rem, 3vh, 1.75rem);
}

/* The notices sit in the same two-column shape as the stack — a label and its
   content — but carry sentences rather than lists, so the second column takes a
   reading measure and the rows are separated rather than packed. */
/* What ran inside a tool, set under it: a quiet label and a plain list,
   indented so it reads as belonging to the line above rather than as another
   discipline. */
.stack-nested {
  margin: 0.4rem 0 0;
  padding-left: 1rem;
  border-left: 1px solid color-mix(in srgb, var(--fg) 16%, transparent);
  color: var(--fg-soft);
  font-size: var(--size-sm);
}

.stack-nested .label {
  display: block;
  color: color-mix(in srgb, var(--fg) 42%, transparent);
}

.notices {
  margin-top: clamp(1rem, 3vh, 1.5rem);
  display: grid;
  gap: clamp(1rem, 2.5vh, 1.5rem);
}

.notice-row {
  display: grid;
  grid-template-columns: minmax(0, 9rem) minmax(0, 1fr);
  gap: 0.5rem 1.5rem;
  align-items: baseline;
}

.notice-row dt {
  color: var(--accent-soft);
}

.notice-row dd {
  margin: 0;
  max-width: 44rem;
  color: var(--fg-soft);
}

@media (max-width: 48rem) {
  .notice-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.25rem;
  }
}

.stack-row {
  display: grid;
  grid-template-columns: 9rem minmax(0, 1fr);
  gap: 1rem;
  align-items: baseline;
}

.stack-row dd {
  font-size: var(--size-sm);
}

.stack-note,
.stack-stackaible {
  margin-top: clamp(1.25rem, 3vh, 1.75rem);
  color: var(--fg-soft);
}

.stack-stackaible a {
  color: var(--fg);
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  padding-bottom: 2px;
  transition: border-color var(--t-quick) var(--ease);
}

.stack-stackaible a:hover,
.stack-stackaible a:focus-visible {
  border-bottom-color: var(--accent);
}

.colophon-updated {
  display: block;
  margin-top: clamp(3rem, 8vh, 5rem);
  color: color-mix(in srgb, var(--fg) 38%, transparent);
}

/* A quiet way through, above the copyright and apart from the platform links.
   The contact address is one of these: an address set apart in its own
   treatment would read as a call to action, and this is a way to reach the
   studio rather than an invitation to. It is the ONLY thing in this group that
   is not a page, so it keeps the group's type and spacing and nothing more. */
.footer-contact,
.footer-notices,
.footer-colophon {
  margin-top: clamp(1.5rem, 4vh, 2.5rem);
  color: color-mix(in srgb, var(--bone) 60%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--bone) 22%, transparent);
  padding-bottom: 2px;
  transition: color var(--t-quick) var(--ease), border-color var(--t-quick) var(--ease);
}

.footer-contact:hover,
.footer-contact:focus-visible,
.footer-notices:hover,
.footer-notices:focus-visible,
.footer-colophon:hover,
.footer-colophon:focus-visible {
  color: var(--bone);
  border-bottom-color: var(--amber);
}

.footer-notices + .footer-copy,
.footer-colophon + .footer-copy {
  margin-top: clamp(1rem, 3vh, 1.5rem);
}

/* Two of the group in a row read as a list, not as two separate arrivals. */
.footer-contact + .footer-notices,
.footer-notices + .footer-colophon {
  margin-top: clamp(0.5rem, 1.5vh, 0.75rem);
}

/* ------------------------------------------------------------------ pager */

/* PREVIOUS · INDEX · NEXT at the foot of a detail page. Three columns with the
   section link centred, so the row reads as a position in a set rather than as
   a pair of buttons. The outer two are opposed, which is what makes the
   direction legible without drawing an arrow.

   The middle column is the one fixed point: both neighbours are optional, and
   an absent one leaves an empty cell rather than collapsing the grid and
   shifting the index link off centre. */
.pager {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: clamp(1rem, 4vw, 3rem);
  margin-top: clamp(4rem, 10vh, 7rem);
  padding: clamp(1.75rem, 4vh, 2.5rem) var(--gutter) 0;
  border-top: 1px solid color-mix(in srgb, var(--fg) 14%, transparent);
}

/* THE ARRIVING FORM. Set under the role line and above the portrait, where it
   costs one line of height and is visible without scrolling. No top rule, no
   big margin, and no neighbour names — it is a control, not a section ending,
   and the full version at the foot of the page still does that job.

   Laid out to the left rather than across three columns: at the top of the page
   it reads as a small navigation cluster, not as a divider. */
.pager-compact {
  display: flex;
  justify-content: flex-start;
  align-items: baseline;
  gap: clamp(1rem, 3vw, 1.75rem);
  margin-top: clamp(1rem, 3vh, 1.5rem);
  margin-bottom: clamp(1.5rem, 4vh, 2.5rem);
  padding-top: 0;
  border-top: 0;
}

.pager-compact .pager-step {
  display: inline-block;
}

/* An absent neighbour leaves nothing at all here — the row is a cluster, not a
   grid, so there is no column to hold open. */
.pager-compact .pager-step:empty {
  display: none;
}

.pager-compact .pager-dir,
.pager-compact .pager-index {
  font-size: var(--size-label);
}

.pager-compact .pager-dir {
  color: color-mix(in srgb, var(--fg) 52%, transparent);
  border-bottom: 1px solid transparent;
  padding-bottom: 2px;
  transition: color var(--t-quick) var(--ease), border-color var(--t-quick) var(--ease);
}

.pager-compact .pager-step:hover .pager-dir,
.pager-compact .pager-step:focus-visible .pager-dir {
  color: var(--fg);
  border-bottom-color: var(--accent);
}

.pager-step {
  display: grid;
  gap: 0.3rem;
  min-width: 0;
}

.pager-next {
  justify-items: end;
  text-align: right;
}

.pager-dir {
  color: var(--accent-soft);
}

.pager-name {
  font-size: var(--size-sm);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--fg-soft);
  transition: color var(--t-quick) var(--ease);
}

.pager-step:hover .pager-name,
.pager-step:focus-visible .pager-name {
  color: var(--fg);
}

/* The way back out, in the quiet register the rest of the site uses for a
   destination rather than a title. */
.pager-index {
  color: color-mix(in srgb, var(--fg) 60%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--fg) 22%, transparent);
  padding-bottom: 2px;
  transition: color var(--t-quick) var(--ease), border-color var(--t-quick) var(--ease);
}

.pager-index:hover,
.pager-index:focus-visible {
  color: var(--fg);
  border-bottom-color: var(--accent);
}

/* On a phone the three columns would set each name on four lines. The section
   link leads instead, and the two neighbours sit under it as a pair. */
@media (max-width: 40rem) {
  .pager {
    grid-template-columns: 1fr 1fr;
    gap: 1.5rem 1rem;
  }

  .pager-index {
    grid-column: 1 / -1;
    grid-row: 1;
    justify-self: start;
  }

  .pager-step {
    grid-row: 2;
  }
}

/* --------------------------------------------------- the hero, by device */

/* THE WORDMARK WAS SIZED FOR ONE SHAPE AND WORN ON ALL OF THEM. --size-hero is
   clamp(2.5rem, 8.75vw, 9rem), and that 8.75vw exists for a specific reason:
   on a wide screen the guardabarranco occupies the left of the frame and the
   type sits in the open water beside it, so the wordmark must not grow back
   across the bird.
   
   Below that shape the bird is not beside the type at all — the clip does not
   attach, the crop is different, and the copy sits at the foot of the frame
   across the full width. The constraint does not apply, and the clamp's FLOOR
   was carrying phones at 40px.
   
   Measured rather than guessed: BARLUNGO is about 5.6em wide in this face, so
   the largest that fits inside the gutters is 50px at 320, 64px at 393, 70px
   at 430 and 144px at an 820 iPad. Every number below sits under its limit at
   the narrowest viewport it applies to. */

/* PHONES. 15.5vw lands at 49.6px on a 320 SE — just inside its 50px limit,
   which is the tightest case and therefore the one that sets the coefficient.
   The 4.5rem cap stops it overrunning as a phone approaches tablet width. */
@media (max-width: 47.99rem) {
  .hero-title {
    font-size: clamp(2.75rem, 15.5vw, 4.5rem);
  }

  /* The descriptor holds its own measure rather than running the full width of
     a phone, where a 40-character line is easier to read than a 60. */
  .hero-descriptor {
    max-width: 24rem;
  }
}

/* TABLETS HELD UPRIGHT. Wide enough for the desktop rules to have taken over,
   but the frame is still taller than 4:3 — so the clip has not attached, the
   copy is at the foot, and the bird is above it rather than beside it. 11vw is
   90px on an 820 iPad against a 144px limit. */
@media (min-width: 48rem) and (max-aspect-ratio: 4 / 3) {
  .hero-title {
    font-size: clamp(4.5rem, 11vw, 7rem);
  }

  .hero-descriptor {
    max-width: 32rem;
  }
}

/* ---------------------------------------------------------------- consent */

/* The same interface cumiche.com carries, in this site's own palette and type.
   It ships HIDDEN and the script reveals it, so a browser with no scripting
   shows nothing — correct rather than degraded, since nothing that needs
   consent can run there either.

   The banner is a bar at the foot, not a modal: it never covers the work and
   never steals focus. The panel IS modal, because it is a decision the visitor
   went looking for. */
.consent[hidden],
.consent-banner[hidden],
.consent-panel[hidden] {
  display: none;
}

.consent-banner {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  background: color-mix(in srgb, var(--ink-deep) 96%, transparent);
  border-top: 1px solid color-mix(in srgb, var(--bone) 16%, transparent);
  backdrop-filter: blur(8px);
}

.consent-banner-inner {
  display: grid;
  gap: clamp(1rem, 3vw, 2rem);
  align-items: center;
  max-width: calc(76rem + var(--gutter) * 2);
  margin-inline: auto;
  padding: clamp(1.25rem, 3vh, 1.75rem) var(--gutter);
}

.consent-banner-title {
  color: var(--amber);
  margin-bottom: 0.5rem;
}

.consent-banner-text {
  max-width: 46rem;
  font-size: var(--size-sm);
  line-height: 1.55;
  color: color-mix(in srgb, var(--bone) 78%, transparent);
}

.consent-banner-actions,
.consent-sheet-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
}

/* ACCEPT AND REJECT ARE THE SAME CONTROL. A reject that is quieter than an
   accept is not a choice, so they share every property including weight. */
.consent-btn {
  font-family: var(--font-mono);
  font-size: var(--size-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--bone);
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--bone) 34%, transparent);
  padding: 0.7rem 1.1rem;
  cursor: pointer;
  transition: border-color var(--t-quick) var(--ease), background var(--t-quick) var(--ease);
}

.consent-btn:hover,
.consent-btn:focus-visible {
  border-color: var(--amber);
  background: color-mix(in srgb, var(--amber) 12%, transparent);
}

.consent-btn-save {
  border-color: var(--amber);
}

.consent-plain {
  font-family: var(--font-mono);
  font-size: var(--size-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--bone) 62%, transparent);
  background: none;
  border: 0;
  border-bottom: 1px solid color-mix(in srgb, var(--bone) 28%, transparent);
  padding: 0 0 2px;
  cursor: pointer;
  transition: color var(--t-quick) var(--ease), border-color var(--t-quick) var(--ease);
}

.consent-plain:hover,
.consent-plain:focus-visible {
  color: var(--bone);
  border-bottom-color: var(--amber);
}

/* ------------------------------------------------------------ the panel */

.consent-panel {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: grid;
  place-items: center;
  padding: var(--gutter);
  background: color-mix(in srgb, var(--shade) 72%, transparent);
}

.consent-sheet {
  width: min(44rem, 100%);
  max-height: 86vh;
  overflow-y: auto;
  padding: clamp(1.5rem, 4vh, 2.5rem);
  background: var(--ink);
  border: 1px solid color-mix(in srgb, var(--bone) 16%, transparent);
}

.consent-sheet-head {
  display: flex;
  justify-content: space-between;
  align-items: start;
  gap: 1rem;
}

.consent-panel-title {
  font-size: var(--size-md);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--bone);
}

.consent-close {
  font-size: 1.5rem;
  line-height: 1;
  color: color-mix(in srgb, var(--bone) 62%, transparent);
  background: none;
  border: 0;
  padding: 0.25rem 0.5rem;
  cursor: pointer;
  transition: color var(--t-quick) var(--ease);
}

.consent-close:hover,
.consent-close:focus-visible {
  color: var(--bone);
}

.consent-sheet-text {
  margin-top: 0.75rem;
  font-size: var(--size-sm);
  line-height: 1.55;
  color: color-mix(in srgb, var(--bone) 74%, transparent);
}

.consent-categories {
  display: grid;
  gap: clamp(1.25rem, 3vh, 1.75rem);
  margin: clamp(1.5rem, 4vh, 2.25rem) 0;
  padding: 0;
  list-style: none;
}

.consent-category {
  padding-bottom: clamp(1.25rem, 3vh, 1.75rem);
  border-bottom: 1px solid color-mix(in srgb, var(--bone) 12%, transparent);
}

.consent-category:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.consent-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.consent-check {
  width: 1rem;
  height: 1rem;
  accent-color: var(--amber);
  cursor: pointer;
}

.consent-check:disabled {
  cursor: default;
}

.consent-name {
  color: var(--bone);
  cursor: pointer;
}

.consent-always {
  margin-left: auto;
}

.consent-summary {
  margin-top: 0.5rem;
  font-size: var(--size-sm);
  line-height: 1.55;
  color: color-mix(in srgb, var(--bone) 70%, transparent);
}

/* What the category ACTUALLY holds on this site. The dim variant is the
   honest empty state: a category listed with nothing in it. */
.consent-used {
  margin-top: 0.5rem;
  font-family: var(--font-mono);
  font-size: var(--size-label);
  letter-spacing: 0.1em;
  color: color-mix(in srgb, var(--bone) 52%, transparent);
}

.consent-used.dim,
.consent .dim {
  color: color-mix(in srgb, var(--bone) 34%, transparent);
}

.consent-more {
  margin-top: 1.25rem;
}

.consent-more-link {
  color: color-mix(in srgb, var(--bone) 62%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--bone) 24%, transparent);
  padding-bottom: 2px;
  transition: color var(--t-quick) var(--ease), border-color var(--t-quick) var(--ease);
}

.consent-more-link:hover,
.consent-more-link:focus-visible {
  color: var(--bone);
  border-bottom-color: var(--amber);
}

/* Under the way through to the notices, in the same register. A privacy panel
   that explains what is stored and offers to change it is where a question
   about any of it occurs to someone, so the route out is given there rather
   than left to be hunted for. Quieter than the link above it: this is an
   answer to "and if I want to ask", not a second call to action. */
.consent-contact {
  margin-top: 0.6rem;
  font-size: var(--size-sm);
  color: color-mix(in srgb, var(--bone) 58%, transparent);
}

.consent-contact-link {
  color: color-mix(in srgb, var(--bone) 72%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--bone) 22%, transparent);
  padding-bottom: 1px;
  transition: color var(--t-quick) var(--ease), border-color var(--t-quick) var(--ease);
}

.consent-contact-link:hover,
.consent-contact-link:focus-visible {
  color: var(--bone);
  border-bottom-color: var(--amber);
}

/* The footer's way back to a choice already made. */
.consent-banner-inner,
.footer-privacy {
  margin-top: 0;
}

.footer-privacy {
  margin-top: clamp(1rem, 3vh, 1.5rem);
}

.footer-choices {
  font-family: var(--font-mono);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--bone) 60%, transparent);
  background: none;
  border: 0;
  border-bottom: 1px solid color-mix(in srgb, var(--bone) 22%, transparent);
  padding: 0 0 2px;
  cursor: pointer;
  transition: color var(--t-quick) var(--ease), border-color var(--t-quick) var(--ease);
}

.footer-choices:hover,
.footer-choices:focus-visible {
  color: var(--bone);
  border-bottom-color: var(--amber);
}

/* Side by side once there is room for the copy and the controls to share a
   line; stacked below that, where three buttons would otherwise crush.
   THE COPY COLUMN HAS A FLOOR, and it needs one: the controls are `auto`, so
   they take whatever their own text needs, and when the label type grew on
   large displays they took 895px of a 1184px row and left the sentence 289px
   — forty lines of one word each. `minmax(0, 1fr)` let the copy shrink to
   nothing because the controls asked first. A sentence is not a scrap. */
@media (min-width: 52rem) {
  .consent-banner-inner {
    grid-template-columns: minmax(26rem, 1fr) auto;
  }
}

/* ON A PHONE THE BANNER WAS A THIRD OF THE SCREEN. 300px of 893 at 412 wide,
   355 of 812 on an SE — for a bar that is meant to sit under the work, not
   stand in front of it. Measured, the body copy was most of it: 17.6px set at
   1.55 ran to five lines and 136px on its own.
   
   The copy itself is not touched. It discloses three things — no cookies, no
   analytics, and that the one optional item stays off until it is asked for —
   and a phone-sized version that dropped any of them would be a smaller
   disclosure rather than a smaller banner. What changed is the setting: 14px
   at 1.5 holds the same 225 characters in FOUR lines instead of five, which is
   where the line count falls over. The rest is padding and leading.

   Result, measured at every phone width: 355 to 261 at 320, 327 to 240 at 375
   and 390, 300 to 219 at 412 and 430. About 27% off, consistently.

   The buttons keep their natural width on purpose. Making them share the row
   with flex: 1 squeezed each to 103px, which wrapped "ACCEPT ALL" onto two
   lines and made them TALLER than leaving them alone. */
@media (max-width: 47.99rem) {
  .consent-banner-inner {
    gap: 0.75rem;
    padding: 1rem var(--gutter);
  }

  .consent-banner-title {
    margin-bottom: 0.35rem;
  }

  .consent-banner-text {
    font-size: 0.875rem;
    line-height: 1.5;
  }

  .consent-banner-actions {
    gap: 0.5rem 0.75rem;
  }

  /* MANAGE PREFERENCES is a 20px line of type and was a 20px tap target. The
     hit area is widened with a pseudo-element rather than padding, because the
     underline here is a border-bottom: pad the element and the rule detaches
     from the word. Real hit-testing puts it at 40px.

     It reaches further DOWN than up, into the banner's own bottom padding
     where nothing else lives. Extended evenly it reached back up past the row
     gap and stole the bottom edge of ACCEPT ALL and REJECT ALL — a mis-tap
     that opens a panel instead of accepting. */
  .consent-plain {
    position: relative;
  }

  .consent-plain::after {
    content: "";
    position: absolute;
    inset: -0.3rem 0 -1rem;
  }
}

/* ---------------------------------------------------------------- notices */

/* Set as a definition list, the same shape as .credits and .stack: a mono label
   and the statement under it. Legal copy wants to be scannable by heading, and
   wants the measure of a reading column rather than the page. Nothing here is a
   box, a panel or a warning — a notice is type. */
.notices {
  display: grid;
  gap: clamp(2rem, 5vh, 3rem);
  margin-top: clamp(1.5rem, 4vh, 2.5rem);
}

.notices-row {
  display: grid;
  gap: 0.6rem;
}

.notices-label {
  color: var(--accent-soft);
}

.notices-body {
  margin: 0;
  max-width: var(--measure);
  font-size: var(--size-sm);
  line-height: 1.6;
  color: var(--fg-soft);
}

.notices-updated {
  display: block;
  margin-top: clamp(2.5rem, 6vh, 4rem);
  color: color-mix(in srgb, var(--fg) 38%, transparent);
}

/* ------------------------------------------------------------------ shop */

/* Architecture, not a storefront. The categories are set as an index — rule,
   number, name — so the page reads as a contents page for something being
   built rather than as an empty grid waiting for stock. */
.shop-status {
  color: var(--accent-soft);
  letter-spacing: 0.24em;
}

.shop-note {
  margin-top: 0.75rem;
  max-width: var(--measure);
  color: var(--fg-soft);
}

.shop-categories {
  margin-top: clamp(3rem, 8vh, 5rem);
  padding-inline: var(--gutter);
  display: grid;
}

.shop-category {
  padding-block: clamp(2rem, 5vh, 3rem);
  border-top: 1px solid color-mix(in srgb, var(--fg) 12%, transparent);
}

.shop-category:last-child {
  border-bottom: 1px solid color-mix(in srgb, var(--fg) 12%, transparent);
}

.shop-category-head {
  display: grid;
  grid-template-columns: 4rem minmax(0, 1fr) auto;
  gap: clamp(1rem, 3vw, 2rem);
  align-items: baseline;
}

.shop-category-index {
  color: color-mix(in srgb, var(--fg) 40%, transparent);
}

.shop-category-name {
  font-size: var(--size-md);
  font-weight: 500;
  letter-spacing: -0.01em;
  text-transform: uppercase;
}

.shop-category-line {
  grid-column: 2;
  color: var(--fg-soft);
  font-size: var(--size-label);
  line-height: 1.6;
}

.shop-category-status {
  grid-column: 3;
  grid-row: 1;
  color: var(--accent-soft);
  justify-self: end;
}

.shop-category-head .cta {
  grid-column: 3;
  grid-row: 1;
  justify-self: end;
}

.product-grid {
  margin-top: clamp(1.5rem, 4vh, 2.5rem);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.5rem, 4vw, 3rem);
}

.product-copy {
  margin-top: 1.1rem;
  display: grid;
  gap: 0.4rem;
}

.product-collection {
  color: var(--accent-soft);
}

.product-title {
  font-size: var(--size-sm);
  font-weight: 500;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

.product-description {
  color: var(--fg-soft);
  font-size: var(--size-label);
  line-height: 1.6;
}

.product-status {
  color: color-mix(in srgb, var(--fg) 52%, transparent);
}

.variants {
  display: grid;
  gap: 0.35rem;
  margin-top: 0.35rem;
}

.variant dd {
  font-size: var(--size-label);
  font-family: var(--font-mono);
  letter-spacing: 0.08em;
  color: var(--fg-soft);
}

/* ------------------------------------------------------------------ work */

/* One shape for a film, a release, a character, an edition, a project —
   because the index's job is to show they are one body of work. Each entry
   carries its own world, so the index is a contact sheet of the four rooms. */
.work-index-list {
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.5rem, 4vw, 3rem);
}

.work-entry {
  background: var(--ground);
  color: var(--fg);
}

/* THE LANDSCAPE ENTRY TAKES THE WHOLE ROW. A wide frame in a portrait column
   had to be letterboxed, which left a dead band above it and pushed the film
   onto a row of its own. Spanning the grid lets it be shown at its own ratio
   and closes the row underneath. */
.work-entry-wide {
  grid-column: 1 / -1;
}

@media (min-width: 60rem) {
  /* The copy sits beside the frame at this width rather than under it: a
     full-width band with its title stacked below would read as a section
     heading rather than as one entry among four. */
  .work-entry-wide .work-link {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    align-items: center;
    column-gap: clamp(1.5rem, 4vw, 3rem);
  }

  .work-entry-wide .work-index {
    grid-column: 1 / -1;
  }
}

.work-link {
  display: grid;
  gap: 0.9rem;
}

.work-plate {
  transition: opacity var(--t-base) var(--ease);
}

.work-link:hover .work-plate,
.work-link:focus-visible .work-plate {
  opacity: 0.84;
}

.work-copy {
  display: grid;
  gap: 0.35rem;
}

.work-kind {
  color: var(--accent-soft);
}

.work-title {
  font-size: var(--size-sm);
  font-weight: 500;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

.work-line {
  color: var(--fg-soft);
  font-size: var(--size-label);
  line-height: 1.5;
}

.work-index {
  color: color-mix(in srgb, var(--fg) 40%, transparent);
}

/* ---------------------------------------------------------------- footer */

.site-footer {
  padding: clamp(3.5rem, 9vh, 6rem) var(--gutter) clamp(2.5rem, 6vh, 4rem);
  background: var(--ink-deep);
  color: var(--bone);
  display: grid;
  gap: 1rem;
  justify-items: start;
}

.footer-wordmark {
  font-size: var(--size-md);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.footer-disciplines {
  color: color-mix(in srgb, var(--bone) 58%, transparent);
  letter-spacing: 0.22em;
}

/* A discipline that has somewhere to go gets the same underline-on-hover the
   rest of the footer uses. One that does not stays exactly as it reads now —
   same colour, same tracking, no affordance — so the line still reads as one
   sign-off rather than as a row of buttons with two of them broken. */
.footer-disciplines a {
  color: inherit;
  border-bottom: 1px solid transparent;
  padding-bottom: 2px;
  transition: color var(--t-quick) var(--ease), border-color var(--t-quick) var(--ease);
}

.footer-disciplines a:hover,
.footer-disciplines a:focus-visible {
  color: var(--bone);
  border-bottom-color: var(--amber);
}

/* The separator is not part of either neighbour's target. */
.footer-disciplines-dot {
  color: color-mix(in srgb, var(--bone) 38%, transparent);
}

.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  margin-top: 0.75rem;
}

.footer-links a {
  color: color-mix(in srgb, var(--bone) 72%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--bone) 24%, transparent);
  padding-bottom: 2px;
  transition: color var(--t-quick) var(--ease), border-color var(--t-quick) var(--ease);
}

.footer-links a:hover,
.footer-links a:focus-visible {
  color: var(--bone);
  border-bottom-color: var(--amber);
}

.footer-copy {
  margin-top: clamp(1.5rem, 4vh, 2.5rem);
  color: color-mix(in srgb, var(--bone) 40%, transparent);
  letter-spacing: 0.1em;
}

.not-found {
  min-height: 70svh;
}

/* ---------------------------------------------------------------- motion */

/* Restrained by instruction. Two effects on the whole site: the hero drifts,
   slowly enough to be felt rather than watched, and a section's type settles
   as it arrives. Nothing enters from off-screen, nothing bounces. */
@keyframes drift {
  from {
    transform: scale(1.04) translate3d(0, 0, 0);
  }
  to {
    transform: scale(1.12) translate3d(-1.5%, -1.5%, 0);
  }
}

[data-drift] .plate img,
[data-drift] .hero-video {
  animation: drift var(--t-drift) var(--ease) infinite alternate;
  will-change: transform;
}

[data-reveal] {
  opacity: 0;
  transform: translate3d(0, 14px, 0);
  transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
}

[data-reveal].is-in {
  opacity: 1;
  transform: none;
}

/* One rule, so a transition added later cannot forget to respect the setting. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  [data-reveal] {
    opacity: 1;
    transform: none;
  }

  .hero-video {
    /* A looping video is motion whatever the stylesheet does to it, so the
       poster frame is what plays. studio.js pauses it for the same reason. */
    animation: none;
  }
}


/* ------------------------------------------------ the moving composition */

/* WHERE THE CLIP PLAYS, THE COPY SWAPS SIDES. The still has the bird on the
   left and the copy to its right; this frame has the bird on the RIGHT, so the
   copy moves to the open sunset and coastline on the left. Same query the
   script uses to attach the clip, so the layout and the video can never
   disagree about which composition is on screen. */
/* ONCE THE SCREEN IS WIDER THAN IT IS TALL BY A TENTH. The script attaches
   the clip from an aspect of 2/5, but up to 11/10 it is laid out as a band
   (below) and the stacked arrangement — copy under the picture — is the
   right one, the same as it is on a phone. These rules are for the full-bleed
   case only, and 11/10 rather than 1/1 because that is where full-bleed first
   holds the whole bird through the drift.
   The query followed the script from width to shape: a portrait tablet is 768
   wide and never met the old 64rem floor, so the clip never played there and
   this block never applied. */
@media (min-aspect-ratio: 11/10) {
  .hero:has(.hero-video[data-hero-attached]) {
    justify-items: start;
  }

  .hero:has(.hero-video[data-hero-attached]) .hero-copy {
    text-align: left;
  }

  /* The measure is pushed to the left axis rather than left where a
     right-aligned block had put it. */
  .hero:has(.hero-video[data-hero-attached]) .hero-descriptor {
    margin-left: 0;
    margin-right: auto;
  }

  /* And the scrim pools under the copy's new side. Without this the type sits
     on open sky at the left while the gradient darkens empty water on the
     right — the protection and the words in different places. */
  .hero:has(.hero-video[data-hero-attached]) .hero-scrim {
    background:
      radial-gradient(
        ellipse 68% 58% at 26% 54%,
        color-mix(in srgb, var(--ink) 66%, transparent) 0%,
        color-mix(in srgb, var(--ink) 48%, transparent) 46%,
        color-mix(in srgb, var(--ink) 16%, transparent) 76%,
        color-mix(in srgb, var(--ink) 0%, transparent) 100%
      ),
      linear-gradient(
        to right,
        color-mix(in srgb, var(--ink) 54%, transparent) 0%,
        color-mix(in srgb, var(--ink) 38%, transparent) 34%,
        color-mix(in srgb, var(--ink) 12%, transparent) 62%,
        color-mix(in srgb, var(--ink) 0%, transparent) 86%
      ),
      linear-gradient(
        to top,
        color-mix(in srgb, var(--ink) 58%, transparent) 0%,
        color-mix(in srgb, var(--ink) 0%, transparent) 38%
      );
  }

}


/* ------------------------------------------------ the upright composition */

/* THE CLIP BECOMES A BAND RATHER THAN A WALLPAPER. A 2.33:1 frame stretched
   over an upright screen under `cover` keeps only (aspect x 42.86)% of its
   width, and the drift takes another twelfth of that: a tablet held upright
   is looking through 28.7% of the frame at a bird that spans 37.5% of it. No
   anchor fixes that. A QUARTER OF THE BIRD IS GONE WHATEVER THE ANCHOR IS,
   and the quarter that remains is magnified 1.6x, so what the hero shows is
   a cropped wing rather than a bird in flight.

   Giving the clip its own box solves it instead of trading one end of the
   bird against the other. At an aspect of 1/1 the box is wide enough that
   `cover` keeps 42.9% of the frame's width — more than the bird needs — so
   the WHOLE bird is on view, at close to its natural size, moving. The copy
   then sits under the picture on the hero's own ground, which is the stacked
   arrangement this page already uses on a phone.

   BOUNDED AT THE TOP ONLY, and that is deliberate. From 11/10 upward the
   full-bleed composition above takes over — not 1/1, though that is where it
   looks like it should sit: full-bleed on a square screen the drift still
   leaves the window a shade too narrow and 2% of the bird goes. 11/10 is the
   first ratio where full-bleed holds the whole bird through the entire drift.
   There is NO FLOOR, because the band's box is a fixed square whatever the
   screen is, so it holds the whole bird at any shape however narrow — a
   folded phone's cover screen, a browser window dragged to a sliver. An
   earlier floor of 2/5 left those showing 55–61% of the bird for no reason
   other than that the number had been carried over from the full-bleed
   arrangement, where a floor genuinely was needed. */
@media (max-aspect-ratio: 11/10) {
  .hero-video[data-hero-attached] {
    /* Anchored to the top edge and sized by ratio, so one rule serves every
       upright screen: 768 wide gives a 768 band, 393 wide gives a 393 band,
       each leaving the rest of the hero for the type. */
    inset: 0 0 auto;
    height: auto;
    aspect-ratio: 1 / 1;
    /* CAPPED, because near the top of this range the screen is almost square
       and a band as tall as it is wide would fill the hero and leave the words
       nowhere to go. A capped band is WIDER than 1:1, which only ever helps:
       the window on to the frame widens with the box. */
    max-height: 80%;
    /* AND IT DOES NOT DRIFT. The drift is a scale, and a scale on a band
       pushes its edges past the box they were measured for — the seam would
       wander, and the window on to the frame would narrow by a twelfth just
       when it is tightest. The clip is already moving: the bird is flying. */
    animation: none;
    /* AND ITS LOWER EDGE DISSOLVES rather than ending in a line. The band
       stops partway down the hero and the ground carries the rest, so without
       this there is a hard horizontal rule across the page where ocean meets
       black — and the wordmark sits astride it, half on a photograph and half
       on a flat field. The fade starts below the bird and is clear of it at
       every point of the clip. */
    -webkit-mask-image: linear-gradient(to bottom, var(--ink) 68%, transparent 100%);
    mask-image: linear-gradient(to bottom, var(--ink) 68%, transparent 100%);
  }

  /* AND THE STILL TAKES THE SAME SHAPE. It is what reduced motion gets, what a
     data-saving connection gets, and what shows if autoplay is refused — so
     it has to survive an upright screen too, and full-bleed it does not: at
     0.46 the drift leaves a window 23% of the frame wide against a bird that
     needs 30.5%, and whichever end is saved the other one goes. In a band it
     is simply whole. The ratio is set on the image rather than the plate
     because the plate carries an inline height from the slot renderer. */
  .hero-media .hero-plate img {
    /* Matched through .hero-media so this outweighs `.hero-media .plate img`,
       which sets the full height a few hundred lines above. */
    height: auto;
    aspect-ratio: 1 / 1;
    max-height: 80%;
    -webkit-mask-image: linear-gradient(to bottom, var(--ink) 68%, transparent 100%);
    mask-image: linear-gradient(to bottom, var(--ink) 68%, transparent 100%);
  }

  /* ONE PICTURE, NOT TWO. The still is a different crop of the same coast,
     mirrored, with the bird on the other side; left showing below the band it
     reads as a seam between two photographs rather than one composition. It
     goes only once a frame has actually been painted — see data-hero-playing
     in studio.js — so the hero never flashes to bare ground while the mp4
     loads. */
  .hero:has(.hero-video[data-hero-playing]) .hero-plate {
    visibility: hidden;
  }

  /* The stacked arrangement, restated because a 1024-wide tablet held upright
     is past the 64rem floor that centres the copy and sends it right. Here
     the picture is above and the words are below it. Unconditional, unlike
     the rule above it: inside this range the hero is a band whether the clip
     attached or the still is carrying it, so the layout cannot depend on
     which one is there. */
  .hero {
    align-content: end;
    justify-items: start;
  }

  .hero-copy {
    max-width: 100%;
    text-align: left;
  }

  .hero-descriptor {
    margin-left: 0;
    margin-right: auto;
  }
}

/* A TALL PHONE LEAVES A HOLE, and the hole is not a choice — it is what is
   left over. The band can only be as tall as it is wide, because any taller
   and the box narrows, the crop tightens and the bird starts going again. On
   a 0.46 screen that is 46% of the hero, and with the copy pinned to the
   bottom edge the remaining half reads as an unfinished page rather than as
   room. So on those screens only, the copy centres in the space BELOW the
   picture instead of sitting at the foot of the whole hero. Tablets are left
   alone: there the band already fills three quarters of the frame and the
   bottom edge is the right place for the words. */
@media (max-aspect-ratio: 3/5) {
  .hero {
    align-content: center;
    /* The band's height IS 100vw — full width at a 1:1 ratio — so this is the
       same number, not an approximation of it. */
    padding-top: 100vw;
  }
}

/* ------------------------------------------------------------------- shop */

/* ONE PICTURE AND ONE DOOR. The page is a heading, the storefront collage at
   its own proportions, and a single link out. No grid, no banner, no card. */

/* RESTRAINED ON PURPOSE, and smaller than this site's other page titles. The
   collage already carries BARLUNGO STUDIO / SUPPLY set large across its middle
   panel; a display-sized heading directly above it would be the same words
   twice, competing. --size-lg reads as a page heading without arguing with the
   artwork. */
.shop-head .opener-title {
  font-size: var(--size-lg);
}

/* FULL WIDTH OF THE CONTENT CONTAINER, at its own ratio. No crop beyond the
   one already baked into the file, no overlay, no rounded corner, no shadow —
   the plate's own ground shows only while the image loads. */
/* NEVER DRAWN LARGER THAN THE FILE, AND CENTRED. The master is 1536px across.
   Left to fill the container it was drawn at 3096px on a 3440 screen — a 2x
   upscale, which is what reads as distortion: there are no more pixels, so
   the browser invents them and every edge in the artwork goes soft. 96rem IS
   1536px, so at and above that width the picture is shown at exactly one
   image pixel per CSS pixel and stops growing; below it nothing changes.
   Centred rather than left-aligned, by instruction: a picture that has
   stopped short of both gutters reads as a plate, and hanging it on the left
   would leave all of the leftover room on one side. */
.shop-collage {
  margin: clamp(2rem, 5vh, 3.5rem) auto 0;
  padding-inline: var(--gutter);
  max-width: calc(96rem + var(--gutter) * 2);
}

.shop-collage-plate {
  background: var(--shade);
}

.shop-cta-row {
  margin-top: clamp(1.75rem, 4vh, 2.75rem);
  padding-inline: var(--gutter);
}

/* THE ONE BUTTON ON THE PAGE, so it is sized to be hit and read rather than
   to match the monospace detail type around it. At the label size it came out
   11px in a 29px-tall target on a phone — under what a thumb reliably finds,
   and under what anyone wants to read. The padding is what makes the target;
   the border is the line the rest of the site's links carry. */
.shop-cta {
  display: inline-block;
  font-size: clamp(0.9rem, 1.1vw, 1.1rem);
  padding-block: 0.85rem;
}

.shop-footnote {
  margin-top: clamp(2rem, 5vh, 3rem);
  padding-inline: var(--gutter);
  color: color-mix(in srgb, var(--fg) 56%, transparent);
}

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

/* ------------------------------------------------------- large displays */

/* EVERY CLAMP IN tokens.js STOPS GROWING AT ABOUT 1650px, and nothing did
   until a hero was looked at on a 3440-wide desktop. The wordmark caps at
   144px and the gutter at 80px, while the photograph behind them goes on
   filling the screen — so at 3440 the type is 22% of the width and the gutter
   is 2%, and the composition reads as a small caption jammed into a corner of
   a very large picture. It is not a bug in any one rule; it is a ceiling that
   was set for laptops.

   This tier lifts those ceilings and nothing else. THE FLOORS ARE THE OLD
   CEILINGS, so at 103rem each value is exactly what it was a pixel earlier and
   there is no jump — below this width the site is untouched. The vw terms are
   the same ones tokens.js already uses, so the growth rate does not change
   either; only where it stops.

   Section headings are deliberately NOT included. They cap at 6.5rem and
   raising them changes every page rather than the hero; worth doing as its own
   decision rather than smuggled into this one. */
@media (min-width: 103rem) {
  :root {
    /* THE CAPS ARE SET SO THEY DO NOT BIND UNTIL ABOUT 4000px. Three passes
       were spent nudging rem ceilings upward — 9rem to 15rem, 1rem to 1.3rem —
       and each one looked right at 1650px and microscopic again at 3440,
       because a rem ceiling is a FIXED SIZE and the screen is not. The vw
       terms below are the ones tokens.js already chose; all this tier does is
       get out of their way. Past 4000px they settle, which is a deliberate
       stop rather than an oversight. */
    --size-hero: clamp(9rem, 8.75vw, 22rem);
    --size-xl: clamp(6.5rem, 6.31vw, 16rem);
    --size-lg: clamp(3.75rem, 3.64vw, 9rem);
    /* THESE TWO ARE DELIBERATELY NOT LET RUN. The display sizes above can
       scale with the screen because they are seen, not read; running copy is
       read, and there is a size past which a line stops being comfortable
       however big the monitor is. Left uncapped, --size-body reached 40px at
       3440 and broke the consent banner into one word per line, because the
       banner's columns are sized for a sentence rather than for a headline. */
    --size-sm: clamp(1.35rem, 1.8vw, 3rem);
    --size-body: clamp(1.1875rem, 1.15vw, 1.5rem);
    /* The monospace detail type: wordmark, navigation, eyebrows, SCROLL. This
       is the one that kept reading as microscopic, because it is the smallest
       thing on the page and so the first to look wrong when it stops growing. */
    --size-label: clamp(0.8125rem, 0.8vw, 2.25rem);
    --gutter: clamp(5rem, 5vw, 14rem);
  }

  /* THE MEASURE GROWS WITH THE TYPE IT HOLDS. --measure is 34rem, which is a
     comfortable line at 21px and a cramped one at 60px — the descriptor broke
     every three words under a 447px headline, in a column narrower than the
     word above it. A measure is a count of characters, not a width. */
  .hero-descriptor {
    max-width: 48rem;
  }

  .opener-dek {
    max-width: 60rem;
  }

  /* The consent banner is centred inside a 76rem measure, which was room for a
     sentence and three controls at laptop sizes. The controls are `auto` and
     grew with the label type, so on a 3440 screen they took two thirds of that
     measure and the sentence got the rest. Giving the band more room is the
     honest fix — the alternative is holding the controls at a size the rest of
     the chrome has outgrown. */
  .consent-banner-inner {
    max-width: calc(112rem + var(--gutter) * 2);
  }

  /* THE KEY ART IS THE ENTRY, so it stops being a thumbnail. The row's middle
     column is a flat 18rem, which is a sensible index size on a laptop and
     288px — eight percent of the width — on a 3440 display, under a headline
     running at 217px. That reads as a contact sheet for a list of many films;
     the studio has one, and its own artwork is the thing worth looking at.
     The column scales with the screen instead, from the same 18rem it has
     always been at the tier's start, so nothing below 1648px moves. */
  .film-row {
    grid-template-columns:
      auto
      minmax(0, clamp(18rem, 26vw, 48rem))
      minmax(0, 1fr);
  }

  /* A GARMENT IS NOT A BILLBOARD. The grid is three columns of 1fr at every
     width, so each plate simply grows with the screen -- about 440px on a
     laptop and 1300px on a wide display, where a t-shirt is drawn taller than
     the viewport. The count of columns grows instead of the size of each one: auto-fill adds
     a column every time the row has 26rem spare, so a plate stays between
     about 420 and 580px from 1650px to 4000px and the row still fills the
     width. Capping the plate instead was tried and left more gap than
     garment -- 416px images adrift in 864px cells. Below 1648px nothing
     moves: at the tier's own start this still measures three columns. */
  .product-grid {
    grid-template-columns: repeat(auto-fill, minmax(26rem, 1fr));
  }
}

/* ----------------------------------------------------------- breakpoints */

/* Mobile is not a shrunken desktop: the compositions restack, the type stays
   large, and the vertically strong assets — character boards, posters — get
   the full width they are drawn for. */

@media (max-width: 64rem) {
  .work-index-list,
  .release-grid,
  .artist-row,
  .product-grid,
  .shop-hero {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .film-row-link {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .film-row-copy {
    grid-column: 2;
  }

  .artist-page,
  .character-page,
  .software,
  .studio-note {
    grid-template-columns: minmax(0, 1fr);
  }

  .views {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 48rem) {
  .site-header {
    align-items: center;
  }

  /* Discipline above its tools: a 9rem label column leaves nothing for the
     tools on a narrow screen. */
  .stack-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.25rem;
  }

  /* The panel only collapses once the script is ready; without it the links
     stay on the page as a list. */
  [data-nav='ready'] .nav-toggle {
    display: block;
  }

  [data-nav='ready'] .site-nav {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: grid;
    align-content: center;
    padding: var(--gutter);
    background: color-mix(in srgb, var(--ink) 97%, transparent);
    backdrop-filter: blur(20px);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--t-base) var(--ease), visibility var(--t-base) var(--ease);
  }

  [data-nav='ready'] .site-nav[data-open] {
    opacity: 1;
    visibility: visible;
  }

  /* Stacked, and only once the script is ready — without it these links stay a
     plain list in the header rather than a column with nothing to open it. */
  [data-nav='ready'] .site-nav ul {
    display: grid;
    gap: clamp(1rem, 4vh, 2rem);
    justify-content: start;
  }

  [data-nav='ready'] .nav-link {
    font-size: var(--size-md);
    font-family: var(--font-display);
    letter-spacing: 0.02em;
    border-bottom: 0;
  }

  [data-nav='ready'] .nav-link.is-current {
    color: var(--amber);
  }

  /* The toggle and the wordmark sit above the open panel: the way out and the
     way home both stay on screen. */
  .nav-toggle,
  .wordmark {
    position: relative;
    z-index: 70;
  }

  .release-grid,
  .artist-row,
  .work-index-list,
  .character-cards,
  .editions,
  .gallery,
  .product-grid,
  .shop-hero,
  .creators {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Two across on a phone rather than one: four full-width frames stacked
     would be four screens of hero before the first product. At half a phone's
     width 16/9 is small enough that the ratio still shows hair to hem. */
  .shop-hero {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* The category index stacks: number and name on one line, then the line of
     copy, then the status. The three-column baseline grid is a desktop idea. */
  .shop-category-head {
    grid-template-columns: 3rem minmax(0, 1fr);
  }

  .shop-category-status,
  .shop-category-head .cta {
    grid-column: 2;
    grid-row: auto;
    justify-self: start;
  }

  .gallery {
    gap: clamp(1rem, 4vw, 1.5rem);
  }

  /* Both cues go on a phone: a vertical word pinned to the right edge crowds
     a narrow column, and on a touch screen nobody needs telling that a page
     scrolls. */
  .hero-cue,
  .head-cue {
    display: none;
  }

  /* A side-weighted scrim is a wide-screen idea. On a phone the copy runs the
     full width of the frame, so the weight has to come from the floor instead —
     otherwise the descriptor sits on whatever the crop happens to leave behind
     it, which here is bright surf. */
  .hero-scrim {
    background: linear-gradient(
      to top,
      color-mix(in srgb, var(--ink) 82%, transparent) 0%,
      color-mix(in srgb, var(--ink) 60%, transparent) 30%,
      color-mix(in srgb, var(--ink) 28%, transparent) 62%,
      color-mix(in srgb, var(--ink) 0%, transparent) 100%
    );
  }


  .film-row-link {
    grid-template-columns: minmax(0, 1fr);
  }

  .film-row-copy,
  .film-row-index {
    grid-column: 1;
  }
}

/* The turnaround strip stays two-up even on the narrowest screens: a
   turnaround read one view at a time is not a turnaround. */
@media (max-width: 30rem) {
  .views {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
