/* ============================================================
   ALKABIL.audio — hand-coded static rebuild
   Palette: pure grayscale (black / white / 85% gray accent)
   Type: Academico for everything (stand-in until a proper
   replacement for the original minerva-modern/anziano is chosen);
   headings stay uppercase like the original.
   ============================================================ */

@font-face {
  font-family: 'Academico';
  src: url(../assets/fonts/Academico-Regular.woff2) format('woff2');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'Academico';
  src: url(../assets/fonts/Academico-Bold.woff2) format('woff2');
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: 'Academico';
  src: url(../assets/fonts/Academico-Italic.woff2) format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: 'Academico';
  src: url(../assets/fonts/Academico-BoldItalic.woff2) format('woff2');
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}

:root {
  --white: hsl(0, 0%, 100%);
  --black: hsl(0, 0%, 0%);
  --accent: hsl(0, 0%, 85.1%);      /* light gray — "bright" theme bg   */
  --light-accent: hsl(0, 0%, 96.08%);
  --dark-accent: hsl(0, 0%, 47.45%);
  /* dark red drawn from the index hero image (its strong red ≈ rgb 202,67,64,
     darkened). Stored as RGB components so it can be used with an alpha via
     rgba(var(--hero-red), a) — e.g. the mobile menu overlay. */
  --hero-red: 125, 28, 30;

  --heading-font: "Academico", Georgia, "Times New Roman", serif;
  --body-font: "Academico", Georgia, "Times New Roman", serif;

  --base-font-size: 21px;
  --h1-size: 4.9rem;
  --h2-size: 3.9rem;
  --h3-size: 2.9rem;
  --h4-size: 1.7rem;

  --site-max-width: 1500px;
  --gutter: 4vw;
  --gap: 11px;
  --header-h: 76px;   /* keep in sync with .site-header's padding + brand size */

  /* ALBUM-COVER WINDOW (artist pages) — the 45°-tilted square the release cover
     is shown through. ***Currently OFF.*** Toggle by swapping the value:
       OFF: none
       ON:  polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)
     Any clip-path value works: polygon(), circle(50%), ellipse(), etc.
     NOTE: while it's ON the cover's drop shadow is clipped away (a clip-path
     cuts everything outside the shape). See DOCUMENTATION §1.13. */
  --cover-clip: none;

  /* Release-cover hover grow (artist pages + home newest release). 1 = no grow. */
  --cover-hover-scale: 1.04;

  /* Corner radius for sections marked `rounded-section` (home newest release). */
  --section-radius: 28px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { font-size: var(--base-font-size); }

body {
  font-family: var(--body-font);
  font-size: 1.1rem;
  line-height: 1.6em;
  background: var(--black);
  color: var(--white);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--heading-font);
  font-weight: 400;
  text-transform: uppercase;
  line-height: 1.4em;
  overflow-wrap: break-word;      /* safety net: never spill past the viewport */
}
h1 { font-size: var(--h1-size); }
h2 { font-size: var(--h2-size); }
h3 { font-size: var(--h3-size); }
h4 { font-size: var(--h4-size); }

@media (max-width: 767px) {
  h1 { font-size: calc(var(--h1-size) * 0.62); }
  h2 { font-size: calc(var(--h2-size) * 0.66); }
  h3 { font-size: calc(var(--h3-size) * 0.72); }
}

a { color: inherit; }
img { max-width: 100%; display: block; }

/* ---------------- Section themes ---------------- */

.theme-white  { background: var(--white); color: var(--black); }
.theme-black  { background: var(--black); color: var(--white); }
.theme-bright { background: var(--accent); color: var(--black); }

/* ---------------- Header ----------------
   Fixed to the top and above everything (z-index) so it persists on scroll with
   all content passing underneath. It starts fully TRANSPARENT and the faint red
   bar fades in once the page is scrolled (js/site.js adds .scrolled past a
   threshold, and removes it back at the very top). This happens on EVERY page.

   The catch is nav contrast while the bar is clear, which depends on what the
   page opens on. js/site.js reads the first section's theme and adds .on-light
   for pages that begin on a white/bright section (info, artist pages) so the nav
   flips to dark text there; pages opening on the dark hero or on photos
   (artists grid) keep white text plus a soft shadow. Once .scrolled tints the
   bar, every page is back to white text. Markup is injected by js/site.js into
   the empty <header class="site-header"> shell. */

.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 1000;
  color: var(--white);
  padding: 0.9rem var(--gutter);   /* bar height — keep --header-h in sync */
  background: rgba(var(--hero-red), 0);   /* clear until scrolled */
  -webkit-backdrop-filter: blur(0px);
          backdrop-filter: blur(0px);
  transition: background 0.4s ease, backdrop-filter 0.4s ease,
              -webkit-backdrop-filter 0.4s ease, color 0.4s ease;
}

/* Clear bar on a page that OPENS on a light section: white-on-white would be
   invisible, so the nav goes dark until the red tint fades in. */
.site-header.on-light:not(.scrolled) { color: var(--black); }
/* …unless the mobile menu is open — then the bar sits on the red overlay. */
body.menu-open .site-header.on-light:not(.scrolled) { color: var(--white); }

/* Clear bar over the hero / artist photos: a soft shadow keeps the white text
   and icons legible over bright patches of the image behind. drop-shadow on the
   wrapper covers the text, the SVG icon and the burger bars in one rule. */
.site-header:not(.on-light):not(.scrolled) .header-inner {
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.55));
}
/* DESKTOP HEADER BAR look once scrolled — tweak here (the mobile menu overlay is
   separate, in .mobile-menu): the opacity below (0 = clear … 1 = solid) and the
   two blur() px values (higher = frostier). */
.site-header.scrolled {
  background: rgba(var(--hero-red), 0.22);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
}
@media (prefers-reduced-motion: reduce) { .site-header { transition: none; } }

/* Full-bleed: the bar's contents run the whole page width, inset only by the
   same --gutter padding as the "WE ARE …" section (no max-width cap), so it
   tracks any screen size automatically. */
.site-header .header-inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
}
.site-header nav.nav-left  { justify-self: start; }
.site-header .branding     { justify-self: center; }
.site-header .header-right { justify-self: end; display: flex; align-items: center; gap: 1.2rem; }

/* No text-transform here on purpose: nav labels render exactly as typed in
   NAV_LINKS (js/site.js), so casing is controlled there, not forced to caps. */
.site-header nav a {
  font-family: var(--heading-font);
  text-decoration: none;
  font-size: 0.85rem;
  margin-right: 1.4rem;
  opacity: 1;
  transition: opacity 0.2s;
}
.site-header nav a:last-child { margin-right: 0; }
.site-header nav a:hover { opacity: 0.6; }

/* Also un-forced: the brand renders as typed (currently "ALKABIL" in site.js). */
.branding a {
  font-family: var(--heading-font);
  font-size: 1.5rem;
  text-decoration: none;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.header-right .social-icon svg {
  width: 1.1rem; height: 1.1rem;
  fill: currentColor;
  display: block;
}
.header-right .social-icon:hover { opacity: 0.6; }

/* burger → X (mobile). It lives in the header, which sits ABOVE the menu
   overlay (z-index 1000 > 900) as a white mark on the header's dark frosted
   bar, so the X is always visible when the menu is open. */
.burger {
  display: none;
  background: none; border: 0; cursor: pointer;
  width: 34px; height: 24px;
  position: relative;
}
.burger span {
  position: absolute; left: 0; width: 100%; height: 2px;
  background: currentColor;
  transition: transform 0.25s, opacity 0.25s;
}
.burger span:nth-child(1) { top: 3px; }
.burger span:nth-child(2) { top: 11px; }
.burger span:nth-child(3) { top: 19px; }
body.menu-open .burger span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
body.menu-open .burger span:nth-child(2) { opacity: 0; }
body.menu-open .burger span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }

.mobile-menu {
  display: none;
  position: fixed; inset: 0;
  background: rgba(var(--hero-red), 0.72);  /* dark-red frosted overlay (from the hero).
     High enough that the red reads over the DARK hero behind it — at low alpha a
     red over near-black composites down to ~black. The blur keeps it frosted. */
  -webkit-backdrop-filter: blur(14px);
          backdrop-filter: blur(14px);
  color: var(--white);
  z-index: 900;                  /* below the header so the X shows over it */
  padding: calc(var(--header-h) + 2rem) var(--gutter) 2rem;
  flex-direction: column;
  gap: 1.2rem;
}
.mobile-menu a {
  font-family: var(--heading-font);
  text-transform: uppercase;
  font-size: var(--h3-size);
  line-height: 1.3em;
  text-decoration: none;
}
body.menu-open .mobile-menu { display: flex; }
body.menu-open { overflow: hidden; }

/* Menu opening: the overlay fades in and the links follow in a short stagger
   (~0.25s each, 0.05s apart) instead of appearing instantly. Add more nth-child
   lines if the menu ever grows past six links. */
body.menu-open .mobile-menu { animation: menu-fade 0.25s ease both; }
body.menu-open .mobile-menu a { animation: menu-item-in 0.25s ease both; }
body.menu-open .mobile-menu a:nth-child(1) { animation-delay: 0.06s; }
body.menu-open .mobile-menu a:nth-child(2) { animation-delay: 0.11s; }
body.menu-open .mobile-menu a:nth-child(3) { animation-delay: 0.16s; }
body.menu-open .mobile-menu a:nth-child(4) { animation-delay: 0.21s; }
body.menu-open .mobile-menu a:nth-child(5) { animation-delay: 0.26s; }
body.menu-open .mobile-menu a:nth-child(6) { animation-delay: 0.31s; }
@keyframes menu-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes menu-item-in {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  body.menu-open .mobile-menu,
  body.menu-open .mobile-menu a { animation: none; }
}

/* Narrow screens: the inline nav (Info/Artists/Releases) and the Instagram icon
   give way to the burger + full-screen menu. */
@media (max-width: 880px) {
  .site-header nav.nav-left,
  .site-header .header-right .social-icon { display: none; }
  .site-header .header-inner { grid-template-columns: auto 1fr auto; }
  .site-header .branding { justify-self: start; }
  .burger { display: block; }
}

/* ---------------- Fluid-engine-style grid ---------------- */

.page-section { position: relative; overflow: hidden; }

/* Rounded full-bleed section (the home newest-release block). It still spans the
   full width — only the corners curve, revealing the page background behind
   them. Works because .page-section clips its contents (overflow: hidden), so
   the background photo and the grain follow the rounding. Radius is tunable at
   the top of this file (--section-radius); a smaller one on phones keeps the
   curve in proportion. */
.rounded-section { border-radius: var(--section-radius, 28px); }
@media (max-width: 767px) { .rounded-section { border-radius: calc(var(--section-radius, 28px) * 0.6); } }

.section-bg {
  position: absolute; inset: 0; z-index: 0;
}
.section-bg img {
  width: 100%; height: 100%;
  object-fit: cover;
}
.section-bg::after {           /* subtle darkening like the original */
  content: "";
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, 0.12);
}

.fgrid {
  --cols: 8;
  --row-h: 24px;
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns:
    minmax(var(--gutter), 1fr)
    repeat(var(--cols), minmax(0, calc((var(--site-max-width) - (var(--gap) * (var(--cols) - 1))) / var(--cols))))
    minmax(var(--gutter), 1fr);
  gap: var(--gap);
  grid-auto-rows: minmax(var(--row-h), auto);
  padding: 2.5rem 0;
}
.blk { grid-column: 2 / -2; min-width: 0; }

@media (min-width: 768px) {
  .fgrid {
    --cols: 24;
    --row-h: calc(min(var(--site-max-width), 100vw - var(--gutter) * 2) * 0.0215);
  }
  .blk { grid-column: auto; grid-area: var(--gd); }
}

/* section heights (approximate Squarespace small/medium/large) */
.section-height--large  { min-height: 100vh; display: grid; align-content: end; }
.section-height--large .fgrid,
.section-height--large .hero-inner { align-self: end; }
.section-height--medium .fgrid { padding: 4rem 0; }
.section-height--small  .fgrid { padding: 2rem 0; }

/* ---------------- Buttons ---------------- */

.btn {
  display: inline-block;
  font-family: var(--heading-font);
  text-transform: uppercase;
  font-size: 0.9rem;
  text-decoration: none;
  background: var(--black);
  color: var(--white);
  padding: 1rem 1.9rem;
  transition: opacity 0.2s;
  white-space: nowrap;   /* label stays on ONE line at any width — never "LISTEN/ ⏎ BUY" */
}
.btn:hover { opacity: 0.75; }
.theme-black .btn { background: var(--accent); color: var(--black); }

/* ---------------- Marquee (scrolling text) ---------------- */

/* Seamless ticker: js/site.js duplicates the .track's contents, so the track
   holds the sequence twice. Animating 0 → -50% travels exactly one copy; at
   the end the second copy sits where the first began, so the loop repeats with
   no snap. Edges fade via a mask. */
.marquee {
  overflow: hidden;
  white-space: nowrap;
  display: flex;
  align-items: center;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 9%, #000 91%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 9%, #000 91%, transparent 100%);
}
.marquee .track {
  display: inline-flex;
  flex-shrink: 0;
  width: max-content;
  animation: marquee-scroll var(--speed, 28s) linear infinite;
  will-change: transform;
}
.marquee.reverse .track { animation-direction: reverse; }
.marquee span {
  font-family: var(--heading-font);
  text-transform: uppercase;
  font-size: var(--h2-size);
  line-height: 1.2em;
  padding-right: 2.2rem;
  flex-shrink: 0;
}
@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .marquee .track { animation: none; }
}

/* ---------------- Home ---------------- */

/* Hero concentric-ring parallax. js/site.js builds N ring layers here, each a
   masked copy of the hero image; it shifts each ring with the pointer/touch so
   the rings slide against one another. Masks are set inline per ring; the base
   .section-bg image shows through if JS is off or reduced-motion is on (the
   host stays empty). Tunables live in the HERO config in js/site.js. */
.hero-parallax {
  position: absolute; inset: 0; z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.hero-ring {
  position: absolute; inset: 0;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
}
.hero-ring-img {
  position: absolute;          /* inset set inline (oversized so shifts hide edges) */
  background-size: cover; background-position: center;
  will-change: transform;
}
.hero-parallax::after {        /* light scrim so the hero text stays legible */
  content: ""; position: absolute; inset: 0;
  background: rgba(0, 0, 0, 0.12);
}

/* Hero band — logo on the left, wordmark + tagline on the right. No grid
   coordinates: it's a two-track grid (logo takes its own width, the copy takes
   the rest). The copy column must have a definite width because .hero-title and
   .hero-tagline use container-query units to size their text — as shrink-to-fit
   flex items they'd collapse. */
.hero-inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--gap);
  padding: 2.5rem var(--gutter);
}
.hero-tagline { margin-top: 0.4rem; }

.hero-logo img {
  width: 100%;
  max-width: 190px;      /* keep the mark modest — it was filling the cell */
  height: auto;
}
.hero-title {
  text-align: right;              /* ALKABIL.AUDIO sits on the right */
  container-type: inline-size;    /* so the title sizes to THIS column's width */
}
/* One line that scales to its column: it never wraps (overrides the heading
   break-word safety net) and shrinks on smaller screens instead of stacking
   letters. Capped at the normal h2 size on wide screens. The clamp() is the
   fallback for browsers without container-query units. */
.hero-title h2 {
  white-space: nowrap;
  font-size: clamp(1.5rem, 7vw, var(--h2-size));
  font-size: min(var(--h2-size), 11cqi);
}
/* Same treatment as the title: one line that scales to its column. The "-"
   hyphens are line-break opportunities (the &nbsp;s only protect the spaces),
   so without nowrap this breaks onto two lines on narrower screens. */
.hero-tagline {
  font-family: var(--heading-font);
  text-transform: uppercase;
  text-align: right;
  container-type: inline-size;    /* so the line sizes to THIS column's width */
}
.hero-tagline p {
  white-space: nowrap;
  font-size: 1.1rem;              /* fallback without container-query units */
  font-size: min(1.1rem, 8cqi);
}
@media (max-width: 767px) {
  .hero-logo img { max-width: 140px; }
  .hero-title, .hero-tagline { text-align: left; }
  /* desktop parks the hero content at the bottom; on mobile that's too low, so
     center it, then nudge it down ~a third of the way toward the bottom so it
     doesn't sit dead-centre */
  .section-height--large { align-content: center; }
  .section-height--large .fgrid,
  .section-height--large .hero-inner { align-self: center; transform: translateY(15vh); }
  .hero-inner { grid-template-columns: 1fr; gap: 1.2rem; }
}

/* Film-grain / static overlay. Drop a <div class="grain"> in a section (after
   its .section-bg, before the .fgrid) to sprinkle animated procedural noise
   over the background image. The noise is an inline SVG feTurbulence — no image
   asset. Sits above the bg image (z 0, later in the DOM) and below the content
   (.fgrid, z 1); `overlay` blend lets the image show through. Tune opacity for
   strength, the animation speed for how "busy" the static is. */
.grain {
	position: absolute;
	inset: -8%;              /* oversized so the jitter never exposes an edge */
	z-index: 0;
	pointer-events: none;
	/* baseFrequency controls grain size. Higher = finer, lower = larger grains.
	numOctaves controls complexity. More octaves = finer layers of detail. */
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
	background-size: 150px 150px;	/*Larger values = larger grain. */
	opacity: 0.85;
	filter: contrast(250%);
	mix-blend-mode: overlay;
	animation: grain-flicker 0.5s steps(4) infinite;
}
@keyframes grain-flicker {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(-4%, 3%); }
  50%  { transform: translate(3%, -3%); }
  75%  { transform: translate(-2%, -4%); }
  100% { transform: translate(0, 0); }
}
@media (prefers-reduced-motion: reduce) { .grain { animation: none; } }

.home-gallery {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
}
.home-gallery img {
  width: 100%; height: 62vh;
  object-fit: cover;
}
@media (max-width: 767px) {
  .home-gallery { grid-template-columns: 1fr; }
  .home-gallery img { height: 48vh; }
}

/* This section breaks out of the 1500px content cap to run the full page width
   (with gutter margins so the text isn't edge-to-edge). It's a plain padded
   block, not the fgrid. */
.we-are { padding: 4.5rem var(--gutter); }
/* Scales with the window instead of sitting at full size all the way down: it
   reaches the normal h2 size around 1520px and shrinks below that, so it stops
   overwhelming smaller desktops. (Mobile is handled separately, further down.) */
.we-are h2 { font-size: clamp(1.6rem, 5.4vw, var(--h2-size)); }
.we-are .word-list { margin-top: 0.5em; }
.we-are-contact { margin-top: 2.5rem; }
@media (max-width: 767px) {
  .we-are { padding: 3rem var(--gutter); }
  .we-are h2 { font-size: 1.25rem; }   /* ~half the previous mobile size */
}

/* Release covers — artist pages AND the home newest-release block. They carry a
   soft drop shadow and grow slightly on hover. Tune --cover-hover-scale (top of
   this file) and the two box-shadows below. The hover lives on the wrapper, not
   the <a>, so it works for covers that aren't links (e.g. "coming soon"). */
/* NB: deliberately no `align-self` here. The cover hugging its image (so the
   hover area matches the artwork) is handled by `align-items: start` on
   .artist-release. Putting it on .release-cover itself would also land inside
   .newest-inner — a flex COLUMN, where align-self is the HORIZONTAL axis — and
   jam the home page's cover against the left edge instead of centring it. */
/* Home newest-release stack — marquee, cover, marquee. No grid coordinates:
   it's a centred column, and the cover just has a max width. */
.newest-inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2.2rem;
  padding: 3rem 0;
}
.newest-inner .marquee { width: 100%; }        /* marquees stay full-bleed */
.newest-inner .release-cover {                  /* cover size lives here now */
  width: min(calc(100% - var(--gutter) * 2), 560px);
}

.release-cover a { display: block; }
.release-cover img {
  width: 100%; height: auto;
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.38);
  transition: transform 0.45s cubic-bezier(0.22, 0.7, 0.3, 1),
              box-shadow 0.45s cubic-bezier(0.22, 0.7, 0.3, 1);
}
.release-cover:hover img {
  transform: scale(var(--cover-hover-scale, 1.04));
  box-shadow: 0 22px 52px rgba(0, 0, 0, 0.5);
}
@media (prefers-reduced-motion: reduce) {
  .release-cover img { transition: none; }
  .release-cover:hover img { transform: none; }
}

/* ---------------- Artist page: the release block ----------------
   Text left, cover right — and NO grid-row numbers to work out. The text just
   flows (title → blurb → button), so the block is however tall its content needs
   and editing the copy never means recalculating a layout. Two things fall out
   of `align-items: start`: the cover top-aligns with the title automatically
   (however long the title or blurb is), and the cover block hugs its image, so
   its hover area matches the artwork instead of trailing below it. */
.artist-release { padding: 4rem 0; }
.release-text .release-desc { margin-top: 1.4rem; }
.release-text .btn { margin-top: 2rem; }

@media (max-width: 767px) {
  .artist-release { padding: 2.5rem var(--gutter); }
  .release-text { margin-top: 2rem; }      /* cover sits above the text on phones */
}

@media (min-width: 768px) {
  /* same column template as .fgrid so the text lines up with the bio above */
  .artist-release {
    display: grid;
    grid-template-columns:
      minmax(var(--gutter), 1fr)
      repeat(24, minmax(0, calc((var(--site-max-width) - (var(--gap) * 23)) / 24)))
      minmax(var(--gutter), 1fr);
    column-gap: var(--gap);
    align-items: start;
  }
  /* the only positioning left: which columns each side occupies. MUST stay
     scoped to .artist-release — `.release-cover` alone would also capture the
     home page's newest-release cover, which is a .blk placed by --gd. */
  .artist-release > .release-text  { grid-column: 2 / 13; grid-row: 1; }
  .artist-release > .release-cover { grid-column: 15 / 26; grid-row: 1; }
}

/* Release cover shown through a tilted-square "window" — a 45°-rotated square,
   i.e. a diamond. Opt in per cover by adding the `clip-diamond` class to a
   `.release-cover`. The polygon lists the four points of the window as
   x%/y% pairs (here the edge midpoints = a diamond); change them for a
   different shape. Removing the class restores the full square. */
.release-cover.clip-diamond img {
  -webkit-clip-path: var(--cover-clip);
          clip-path: var(--cover-clip);
}

/* ---------------- Artists index (portfolio grid overlay) ---------------- */

.portfolio-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-height: 100vh;
}
.portfolio-grid .grid-item {
  position: relative;
  display: block;
  overflow: hidden;
  text-decoration: none;
}
.portfolio-grid .grid-item img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.6s ease;
}
.portfolio-grid .grid-item:hover img { transform: scale(1.03); }
.portfolio-grid .overlay {
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, 0.25);
  transition: background 0.3s;
}
.portfolio-grid .grid-item:hover .overlay { background: rgba(0, 0, 0, 0.45); }
.portfolio-grid .portfolio-title {
  position: absolute;
  left: 0; right: 0; bottom: 8%;
  text-align: center;
  color: var(--white);
  font-size: var(--h3-size);
  z-index: 1;
}
@media (max-width: 767px) {
  .portfolio-grid { grid-template-columns: 1fr; }
  .portfolio-grid .grid-item { min-height: 50vh; }
}

/* ---------------- Artist detail ---------------- */

/* Artist name — deliberately about half the normal h1 size. Fluid so it also
   fits small screens (change the clamp's max to resize). The bio's WIDTH is set
   by the block's grid area (`--gd`) in each artist page — see DOCUMENTATION. */
/* Artist bio — a centred measure, no grid coordinates. Widen/narrow the whole
   bio (name, copy and links) with the one max-width below. */
.artist-intro { padding-bottom: 3rem; }
.artist-bio {
  max-width: 1120px;
  margin: 0 auto;
  padding: 3rem var(--gutter) 0;
}
.artist-bio h1 { font-size: clamp(1.8rem, 6vw, 2.5rem); }
.artist-bio p { margin-top: 1em; }
.artist-bio .artist-links { margin-top: 1.4em; }
.artist-bio .artist-links a { display: inline-block; margin-right: 1.4rem; }

.artist-banner {
  height: 88vh;
  position: relative;
}
.artist-banner img {
  width: 100%; height: 100%;
  object-fit: cover;
}

/* Tighter than the global h2 leading (1.4em): a large display title reads better
   set close, and the smaller half-leading means the cover — which aligns to the
   top of the title's BOX — lines up with the top of the letterforms too. */
/* `none`, not just an absent property: .release-title is an <h2>, and the global
   h1–h4 rule forces uppercase — so leaving this out would SHOUT the title rather
   than render it as typed. Casing is controlled in the HTML. */
.release-title { text-transform: none; line-height: 1.12em; }
.release-desc p + p { margin-top: 1em; }   /* spacing BETWEEN paragraphs only */
.release-desc em { font-style: italic; }

/* Prev / Next bar — both ends filled by js/site.js from the ARTISTS order.
   Prev on the left, Next on the right; if only one artist exists, the single
   link centers. */
.item-pagination {
  display: flex;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 2.5rem var(--gutter);
  max-width: var(--site-max-width);
  margin: 0 auto;
}
.item-pagination a {
  text-decoration: none;
  transition: opacity 0.2s;
}
.item-pagination .pag-next { margin-left: auto; text-align: right; }
.item-pagination .pag-prev { text-align: left; }
.item-pagination a:hover { opacity: 0.6; }
.item-pagination .pag-label {
  font-family: var(--heading-font);
  text-transform: uppercase;
  font-size: 0.85rem;
  display: block;
  opacity: 0.6;
}
.item-pagination .pag-title {
  font-family: var(--heading-font);
  text-transform: uppercase;
  font-size: var(--h4-size);
}

/* ---------------- Info page ---------------- */

.big-q { font-size: calc(var(--h1-size) * 1.4); line-height: 1; }

/* ---------------- Info page: the text/photos split ----------------
   The page is TWO row-pairs, not one text column beside one photo column:

     row 1  |  ? + intro          |  photo 1
     row 2  |  SOME ANSWERS + FAQ |  photo 2

   Each row's height is set by its own text, and its photo stretches to fill
   exactly that — so the seam between the photos lands precisely where section 1
   ends, and opening a FAQ item grows row 2 only (photo 2), leaving photo 1
   alone. row-gap is 0, so the two still meet with no seam. Photos fill with
   object-fit: cover, so narrowing the window just crops them harder rather than
   leaving gaps ("fit to area"). See §1.17. */

/* this section has no .fgrid, so it carries its own bottom breathing room
   (the top padding is the fixed-header allowance, set inline in info.html) */
.info-split { padding-bottom: 6rem; }

/* MOBILE is plain block flow, so the DOM order *is* the reading order:
   ? → intro → photo 1 → SOME ANSWERS → FAQ → photo 2 */
.info-text { padding-left: var(--gutter); padding-right: var(--gutter); }
.info-text .big-q { text-align: center; margin-top: 3rem; }   /* the ? is centred… */
.info-intro { margin-top: 2rem; }                /* …everything else shares one left edge */
.info-answers { margin-top: 3rem; }
.info-text .faq { margin-top: 2.5rem; }

.info-photo { margin-top: 3rem; overflow: hidden; }
.info-photo img { display: block; width: 100%; height: auto; }

@media (min-width: 768px) {
  /* Two full-bleed halves. Deliberately NOT the 1500px-capped .fgrid template
     used elsewhere: that kept the text bunched toward the middle of wide
     screens with a dead margin on the left. Here each half grows with the
     window, so the text starts near the left edge and fills its side. */
  .info-split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 0;
    row-gap: 0;                    /* the two photos meet with no seam */
    align-items: stretch;          /* each photo fills its own row */
  }
  .info-r1 { grid-row: 1; }
  .info-r2 { grid-row: 2; }

  .info-text {
    grid-column: 1;
    align-self: center;            /* centred against its photo */
    /* Symmetric block padding does two jobs: it gives the photo beside it a
       taller frame, and it keeps the text optically centred within that frame.
       Raise/lower per row to resize that row's photo (and move the seam
       between the two photos down/up). */
  }
  .info-text.info-r1 { padding-block: 7rem; }
  .info-text.info-r2 { padding-block: 5rem; }
  .info-text > :first-child { margin-top: 0; }   /* keeps the padding symmetric */

  /* Type scales with the window: unchanged at ~1280px and up to the caps, and
     shrinking below that so the wider column never forces a cramped line. */
  .info-text { font-size: clamp(0.95rem, 1.8vw, 1.25rem); }
  .info-answers { font-size: clamp(1.9rem, 6.2vw, var(--h2-size)); }
  .info-text .faq summary { font-size: clamp(1.15rem, 2.7vw, 1.95rem); }

  .info-photo {
    grid-column: 2;                /* right half, out to the screen edge */
    margin-top: 0;
    min-height: 0;                 /* lets the TEXT drive the row height */
  }
  .info-photo img {
    height: 100%;
    min-height: 0;
    object-fit: cover;             /* fill the row, crop the overflow */
  }
}

.faq details {
  border-top: 1px solid currentColor;
  padding: 1rem 0;
}
.faq details:last-child { border-bottom: 1px solid currentColor; }
.faq summary {
  font-family: var(--heading-font);
  text-transform: uppercase;
  font-size: var(--h4-size);
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary { transition: opacity 0.2s ease; }
.faq summary:hover { opacity: 0.6; }
.faq summary::after {
  content: "+";
  font-family: var(--body-font);
  font-size: 1.4rem;
  /* the + rolls a half-turn into an × as it opens, matching the reveal timing */
  transition: transform 0.34s cubic-bezier(0.25, 0.6, 0.3, 1);
}
.faq details[open] summary::after { transform: rotate(225deg); }

/* Answer reveal. <details> renders its content only when open, so a CSS
   *transition* can't catch it — an animation plays as soon as it appears.
   Animating grid-template-rows 0fr → 1fr gives a true height slide (no
   magic-number max-height), so the answer cascades the list open beneath its
   question instead of popping in at full height. The inner element clips
   itself while the row is short. */
.faq .faq-answer {
  display: grid;
  grid-template-rows: 1fr;
  padding: 0;
}
/* NOTE: .faq-answer must hold exactly ONE child — the animation drives a single
   grid row, so extra children would land in an implicit row that never
   collapses. For a multi-paragraph answer, wrap the <p>s in one <div>. */
.faq .faq-answer > * {
  min-height: 0;
  overflow: hidden;
  padding: 0.8em 0 0.4em;   /* on the inner box so it's clipped away too */
}
.faq .faq-answer p + p { margin-top: 0.7em; }   /* spacing inside a wrapped answer */
.faq details[open] .faq-answer {
  animation: faq-reveal 0.34s cubic-bezier(0.25, 0.6, 0.3, 1);
}
@keyframes faq-reveal {
  from { grid-template-rows: 0fr; opacity: 0; }
  to   { grid-template-rows: 1fr; opacity: 1; }
}

/* Closing. A <details> un-renders its content the moment `open` is removed, so
   on its own it snaps shut. js/site.js cancels that, adds `.closing` to play
   this reverse animation, then closes it for real when the animation ends — so
   both directions run the same 0.34s slide. These rules must stay AFTER the
   [open] ones above: same specificity, so source order decides the winner. */
.faq details.closing .faq-answer {
  animation: faq-hide 0.34s cubic-bezier(0.25, 0.6, 0.3, 1);
}
/* the icon un-rotates at the same time (its own transition), not after */
.faq details.closing summary::after { transform: rotate(0deg); }
@keyframes faq-hide {
  from { grid-template-rows: 1fr; opacity: 1; }
  to   { grid-template-rows: 0fr; opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .faq details[open] .faq-answer,
  .faq details.closing .faq-answer { animation: none; }
  .faq summary::after { transition: none; }
}

/* newsletter — marquee then the form, stacked. No grid coordinates. */
.newsletter-section {
  display: flex;
  flex-direction: column;
  gap: 2.5rem;
  padding: 2rem 0 5rem;
}
.newsletter-section .marquee { width: 100%; }   /* marquee stays full-bleed */
.newsletter {
  text-align: center;
  max-width: 760px;                             /* the form's measure */
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.newsletter .nl-desc { margin-bottom: 1.6em; }
.newsletter form {
  display: flex;
  gap: var(--gap);
  justify-content: center;
  flex-wrap: wrap;
}
.newsletter input[type="email"] {
  font-family: var(--body-font);
  font-size: 1rem;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--black);
  background: transparent;
  color: inherit;
  /* 18rem (378px) is wider than a phone, so cap it at the available width —
     without this the field overflowed and was only hidden by the section's
     overflow: hidden */
  min-width: min(18rem, 100%);
  max-width: 100%;
}
.newsletter button {
  font-family: var(--heading-font);
  text-transform: uppercase;
  font-size: 0.9rem;
  padding: 0.9rem 1.9rem;
  border: 0;
  background: var(--black);
  color: var(--white);
  cursor: pointer;
  transition: opacity 0.2s;
}
.newsletter button:hover { opacity: 0.75; }
.emailoctopus-form {
  width: 100%;
  max-width: 760px;
  margin: 0 auto;
}

/* ---------------- Footer ---------------- */

.site-footer {
  background: var(--black);
  color: var(--white);
  padding: 3rem var(--gutter) 3.5rem;
}
/* Full-bleed like the header: contents run the whole page width, inset only by
   the --gutter padding on .site-footer (no max-width cap). */
.site-footer .footer-inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap);
}
.site-footer .footer-right { text-align: left; }
@media (min-width: 768px) {
  .site-footer .footer-right { justify-self: end; text-align: right; }
}
.site-footer a { color: inherit; }
.site-footer p { margin-bottom: 0.3em; }
@media (max-width: 600px) {
  .site-footer .footer-inner { grid-template-columns: 1fr; gap: 1.6rem; }
  .site-footer .footer-right { text-align: left; }
}
