/* ---- src/styles/fonts.css ---- */
/* Self-hosted free fonts (SIL Open Font License), latin subset, from Google Fonts.
   Mona Sans is variable: weight 200-900, width 75%-125%. IBM Plex Mono: 400 and 600.
   Paths are relative to the built stylesheet, assets/site.css. */
@font-face {
  font-family: "Mona Sans";
  font-style: normal;
  font-weight: 200 900;
  font-stretch: 75% 125%;
  font-display: swap;
  src: url(fonts/MonaSans-normal-200-900.woff2) format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/IBMPlexMono-normal-400.woff2) format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(fonts/IBMPlexMono-normal-600.woff2) format("woff2");
}

/* ---- src/styles/tokens.css ---- */
/* Mickey 9s design tokens. The only file allowed to hold raw values (px, hex).
   Everything else in the site uses these names. tools/lint.js fails the build if a raw px or hex value
   appears anywhere else (the one breakpoint, 1024px, is the only exception, because CSS cannot put a
   custom property in a media query).

   Read bottom to top: palette -> colour roles -> type -> spacing -> layout roles -> controls -> states. */

:root {
  /* ---------------------------------------------------------------- palette (10 colours, nothing else) */
  --black: #000000;
  --white: #ffffff;
  --grey-70: #4d4d4d;   /* 8.45:1 on white, 7.56:1 on grey-6 */
  --grey-6: #f0f0f0;
  --yellow: #fabc1d;    /* sampled from the QMU 2026 poster; black on it is 12.3:1 */
  --blue: #6898ff;      /* pure blue lightened until black on it is 7.5:1 */
  --orange: #ff8000;    /* pure orange; black on it is 8.3:1 */
  --green: #28b83e;     /* pure green darkened so it shows on white; black on it is 8.0:1 */
  --red: #f04a3e;       /* a calmer true red (Antony, 19 Oct); black on it is 5.75:1, the one colour under 7:1 (a red that reaches 7:1 turns peach) */
  /* Instagram's own pink (#ff0069) lightened until black on it is 7.5:1, the same rule as the blue above, so it sits
     in this palette (Antony, 23 Oct 2026, topic 362 msgs 4291, 4295). Facebook's blue and YouTube's red, put through
     the same rule, come out as this palette's own blue and red, so those two links use them. */
  --pink: #ff61a2;      /* black on it is 7.48:1 */

  /* ---------------------------------------------------------------- colour roles */
  --c-bg: var(--white);          /* the page */
  --c-text: var(--black);        /* all text, unless a role below says otherwise */
  --c-text-2: var(--grey-70);    /* labels, secondary facts, placeholder text */
  --c-rule: var(--black);        /* every rule and border */
  --c-fill: var(--grey-6);       /* input wells, table heads, disabled controls, placeholder stripes */
  --c-bar: var(--black);         /* section bars and primary buttons */
  --c-on-bar: var(--white);      /* text on a bar */
  --c-here: var(--yellow);       /* "you are here": current page, pointer, focused field, chosen option; pages outside a section */
  /* each menu position keeps its colour, left to right yellow, blue, orange, green, red (Antony, 19 Oct 2026); base.css applies them */
  --c-gigs: var(--yellow);       /* Gigs, the 1st menu cell */
  --c-list: var(--green);        /* List, the 4th menu cell */
  --c-shop: var(--orange);       /* Shop, product pages, Bag, Checkout, Order, the 3rd menu cell */
  --c-music: var(--blue);        /* Tunes (Music) and release pages, the 2nd menu cell */
  --c-bio: var(--red);           /* Script (Bio), the 5th menu cell */
  --c-instagram: var(--pink);    /* the links to each platform, wherever they are (footer, Bio, the design system) */
  --c-facebook: var(--blue);
  --c-youtube: var(--red);

  /* ---------------------------------------------------------------- type */
  --f-display: "Mona Sans", "Arial Narrow", "Helvetica Neue", Arial, sans-serif; /* set condensed (75%) */
  --f-text: "Mona Sans", "Helvetica Neue", Arial, sans-serif;                   /* set at normal width */
  --f-mono: "IBM Plex Mono", ui-monospace, Menlo, monospace;

  /* the scale: 10 sizes, each with its own line height on the 4px grid */
  --fs-12: 12px;  --lh-12: 16px;
  --fs-14: 14px;  --lh-14: 20px;
  --fs-16: 16px;  --lh-16: 24px;
  --fs-20: 20px;  --lh-20: 24px;
  --fs-24: 24px;  --lh-24: 24px;
  --fs-32: 32px;  --lh-32: 32px;
  --fs-40: 40px;  --lh-40: 40px;
  --fs-56: 56px;  --lh-56: 48px;
  --fs-80: 80px;  --lh-80: 72px;
  --fs-120: 120px; --lh-120: 104px;

  --w-regular: 400;
  --w-semibold: 600;
  --w-heavy: 800;
  --w-black: 900;
  --stretch-display: 75%;
  --stretch-text: 100%;
  --ls-label: 0.04em;   /* mono labels */
  --ls-caps: 0.01em;    /* condensed capitals */

  /* ---------------------------------------------------------------- spacing scale (the only gaps allowed) */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 24px;
  --s6: 32px;
  --s7: 48px;
  --s8: 64px;
  --s9: 96px;

  /* ---------------------------------------------------------------- rules */
  --rule: 2px;         /* every box edge and divider; also the gap between cells, so neighbours share one rule */
  --rule-thick: 4px;   /* focus ring, chosen option, current page marker, invalid field */

  /* ---------------------------------------------------------------- layout roles (phone first) */
  --max: 1376px;            /* content width at 1440 = 1440 - 2 x 32 */
  --margin: var(--s4);      /* page edge to content */
  --block: var(--s6);       /* between sections, header to first section, last section to footer */
  --pad: var(--s3);         /* inside every box */
  --gap-label: var(--s1);   /* a label to its value */
  --gap-stack: var(--s2);   /* stacked items inside a box: field label to input, input to message */
  --cols: 4;                /* grid columns */

  /* ---------------------------------------------------------------- controls */
  --ctl: 48px;              /* minimum tap target and control height */
  --ctl-lg: 64px;           /* big actions: Tickets, Add to bag, Checkout, Pay */
  --nav-h: 48px;
  --logo-h: 28px;           /* logo height in the header and footer */
  --credit-h: 26px;         /* Square9's logo in the Square9 stamp under the footer (topic 149 msg 4405) */
  --credit-label-h: 11px;   /* the stamp's label, outlined Tanker caps at a 15px size */
  --credit-border: 3px;     /* the stamp's outline */
  --credit-radius: 12px;    /* the stamp's corners: Square9's look, not this site's square one */
  --credit-offset: 6px;     /* the black block behind the card, and how far the card presses on hover */
  --t-credit: 120ms;        /* the stamp's press on hover */
  --count-w: 32px;          /* the bag count box */

  /* ---------------------------------------------------------------- media */
  --ratio-square: 1 / 1;
  --ratio-photo: 3 / 2;      /* every band photo (baked to 3:2 by tools/prep-images.py) */
  --ratio-hero: 3 / 2;       /* the lead photo on Home and Bio; 21:9 from 1024 */
  --ratio-video: 16 / 9;     /* video thumbnails (YouTube's own, cropped to 16:9 by tools/prep-images.py) */
  --thumb: 96px;            /* bag line image */

  /* ---------------------------------------------------------------- type roles (font shorthand + case) */
  --type-label: var(--w-regular) var(--fs-12) / var(--lh-12) var(--f-mono);
  --type-label-strong: var(--w-semibold) var(--fs-12) / var(--lh-12) var(--f-mono);
  --type-small: var(--w-regular) var(--fs-14) / var(--lh-14) var(--f-text);
  --type-mono-small: var(--w-semibold) var(--fs-14) / var(--lh-14) var(--f-mono);
  --type-body: var(--w-regular) var(--fs-16) / var(--lh-16) var(--f-text);
  --type-body-strong: var(--w-semibold) var(--fs-16) / var(--lh-16) var(--f-text);
  --type-input: var(--w-regular) var(--fs-16) / var(--lh-16) var(--f-mono);
  --type-input-lg: var(--w-regular) var(--fs-20) / var(--lh-20) var(--f-mono);
  --type-value: var(--w-heavy) condensed var(--fs-20) / var(--lh-20) var(--f-display);
  --type-title-s: var(--w-black) condensed var(--fs-24) / var(--lh-24) var(--f-display);
  --type-title-m: var(--w-black) condensed var(--fs-32) / var(--lh-32) var(--f-display);
  --type-title-l: var(--w-black) condensed var(--fs-40) / var(--lh-40) var(--f-display);
  --type-title-xl: var(--w-black) condensed var(--fs-56) / var(--lh-56) var(--f-display);
  --type-title-xxl: var(--w-black) condensed var(--fs-80) / var(--lh-80) var(--f-display);
  --type-title-xxxl: var(--w-black) condensed var(--fs-120) / var(--lh-120) var(--f-display);

  /* which size each role takes on a phone */
  --type-page: var(--type-title-xxl);
  --type-nav: var(--type-value);
  --type-bar: var(--type-title-s);
  --type-btn: var(--type-value);
  --type-btn-lg: var(--type-title-s);
  --type-date: var(--type-title-xl);
  --type-name: var(--type-title-l);
  --type-price-lg: var(--type-title-l);
}

/* the one breakpoint: 1024px and up */
@media (min-width: 1024px) {
  :root {
    --margin: var(--s6);
    --block: var(--s7);
    --pad: var(--s4);
    --cols: 12;
    --nav-h: 64px;
    --logo-h: 48px;
    --thumb: 128px;
    --ratio-hero: 21 / 9;
    --type-nav: var(--type-title-s);
    --type-bar: var(--type-title-m);
    --type-btn-lg: var(--type-title-m);
    --type-date: var(--type-title-xxl);
    --type-name: var(--type-title-xl);
    --type-page: var(--type-title-xxxl);
  }
}

/* ---- src/styles/base.css ---- */
/* Base: reset and the defaults every page starts from. Values come from tokens.css. */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; background: var(--c-bg); }
body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-text);
  font: var(--type-body);
  font-stretch: var(--stretch-text);
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
}
/* Mona Sans draws a slashed zero by default; switch it off so prices and dates read normally. */
body, input, button, select { font-feature-settings: "zero" 0, "ss01" 0; }
img { display: block; max-width: 100%; height: auto; }
h1, h2, h3, h4, p, ul, ol, dl, dd, figure, blockquote { margin: 0; }
ul, ol { padding: 0; list-style: none; }
button, input, select, textarea { font: inherit; color: inherit; margin: 0; }
button { cursor: pointer; }

/* each section's "you are here" colour: set on the page (body), a Home glimpse, or a menu cell */
[data-section="gigs"] { --c-here: var(--c-gigs); }
[data-section="list"] { --c-here: var(--c-list); }
[data-section="shop"] { --c-here: var(--c-shop); }
[data-section="music"] { --c-here: var(--c-music); }
[data-section="bio"] { --c-here: var(--c-bio); }
/* a link to a platform lights in that platform's colour, inside any section */
[data-platform="instagram"] { --c-here: var(--c-instagram); }
[data-platform="facebook"] { --c-here: var(--c-facebook); }
[data-platform="youtube"] { --c-here: var(--c-youtube); }
fieldset { margin: 0; padding: 0; border: 0; min-width: 0; }
legend { padding: 0; }
a { color: inherit; }
[hidden] { display: none !important; }

/* Focus: one ring everywhere, thick and black, never removed. On black it turns yellow. */
:focus-visible, .is-focus { outline: var(--rule-thick) solid var(--c-text); outline-offset: var(--rule); }

/* main is focused by the skip link; no ring round the whole page */
main:focus { outline: none; }

/* Screen-reader-only text */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; /* lint-ok: the standard visually-hidden pattern */
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Skip link: first thing on every page, shown on focus */
.skip {
  position: absolute; left: var(--margin); top: calc(-1 * var(--ctl-lg)); z-index: 10;
  display: flex; align-items: center; min-height: var(--ctl); padding: 0 var(--s4);
  background: var(--c-bar); color: var(--c-on-bar);
  font: var(--type-value); text-transform: uppercase; text-decoration: none;
}
.skip:focus { top: var(--margin); outline-color: var(--c-here); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
}

/* ---- src/styles/layout.css ---- */
/* Layout: the page frame. One content column, the same left and right edges on every page.
   Phone: 16px margins. 1024 and up: 32px margins, content up to 1376px wide (exactly 1376 at 1440). */

.wrap {
  width: 100%;
  max-width: calc(var(--max) + 2 * var(--margin));
  margin-inline: auto;
  padding-inline: var(--margin);
}

/* Vertical rhythm. Every gap between the big blocks is --block (the footer follows the content; it is not pushed to the screen's foot):
   header -> first block, block -> block, last block -> footer, footer -> page end. */
.page { display: flex; flex-direction: column; }
.page__main { display: flex; flex-direction: column; gap: var(--block); padding-block: var(--block); }
.page__foot { padding-bottom: var(--block); }

/* Grid: 4 columns on a phone, 12 from 1024. Cells share rules: the grid's own background is the rule
   colour and the gap between cells is one rule wide. */
.grid {
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  gap: var(--rule);
  background: var(--c-rule);
  border: var(--rule) solid var(--c-rule);
}
:where(.grid > *) { background: var(--c-bg); min-width: 0; }

/* Stack: ruled blocks one under another sharing one rule (a bar and what hangs from it, a notice over a form). */
.stack > :not([hidden]) ~ :not([hidden]) { border-top-width: 0; }

/* Split: a main column and a side column sharing one rule; side by side (8/12 + 4/12) from 1024. */
.split { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); align-items: start; }
:where(.split > *) { background: var(--c-bg); min-width: 0; align-self: stretch; }
.split :is(.lines, .totals, .formcells) { border-width: 0; }
.split :is(.lines, .totals) + :is(.lines, .totals) { border-top-width: var(--rule); }
.split__side { display: flex; flex-direction: column; }
.split__side > :not(:last-child) { border-bottom: var(--rule) solid var(--c-rule); }
@media (min-width: 1024px) { .split { grid-template-columns: minmax(0, 8fr) minmax(0, 4fr); } }

/* ---- src/components/frame.css ---- */
/* Frame components: header + nav, footer, section bar. The page title is the sr-only utility (base.css).
   States used here (see tokens.css): hover = --c-here; current page = --c-here + a 4px rule along the bottom
   (menu cells, Bag, footer links; never the logo);
   pressed = inverted; focus = the 4px ring, drawn inside cells so it never leaves the page edges. */

/* ------------------------------------------------------------------ header */
.head__bar { display: flex; border: var(--rule) solid var(--c-rule); }
.head__brand {
  flex: 1; display: flex; align-items: center;
  min-height: var(--ctl); padding: var(--pad);
  text-decoration: none;
}
.head__brand img, .foot__brand img { height: var(--logo-h); width: auto; }
.head__bag {
  display: flex; align-items: center; gap: var(--s2);
  min-width: var(--ctl); padding: 0 var(--pad);
  border-left: var(--rule) solid var(--c-rule);
  font: var(--type-nav); letter-spacing: var(--ls-caps); text-transform: uppercase; text-decoration: none;
}

/* the count box: bag count, and counts in section links */
.count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: var(--count-w); height: var(--count-w); padding: 0 var(--s1);
  border: var(--rule) solid currentColor;
  font: var(--type-mono-small); letter-spacing: 0;
}

/* one equal cell per section, however many the build has (four when the shop is off) */
.nav__list {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  border: var(--rule) solid var(--c-rule); border-top: 0;
}
.nav__list > li { min-width: 0; }
.nav__list > li + li { border-left: var(--rule) solid var(--c-rule); }
.nav__link {
  display: flex; align-items: center;
  min-height: var(--nav-h); padding: 0 var(--s2);
  font: var(--type-nav); letter-spacing: var(--ls-caps); text-transform: uppercase; text-decoration: none;
}
@media (min-width: 1024px) { .nav__link { padding: 0 var(--pad); } }

/* states shared by every cell-shaped link in the frame */
:is(.head__bag, .nav__link, .foot__link):hover,
:is(.head__bag, .nav__link, .foot__link).is-hover { background: var(--c-here); }
/* the logo is never filled as the current page: on Home it keeps aria-current for screen readers, but the
   menu shows nothing lit */
:is(.head__bag, .nav__link, .foot__link)[aria-current="page"],
:is(.head__bag, .nav__link, .foot__link).is-current {
  background: var(--c-here);
  box-shadow: inset 0 calc(-1 * var(--rule-thick)) 0 var(--c-rule);
}
:is(.head__bag, .nav__link, .foot__link):active,
:is(.head__bag, .nav__link, .foot__link).is-active { background: var(--c-bar); color: var(--c-on-bar); }
:is(.head__brand, .head__bag, .nav__link, .foot__link):focus-visible,
:is(.head__brand, .head__bag, .nav__link, .foot__link).is-focus { outline-offset: calc(-2 * var(--rule-thick)); }
/* the logo stays white whatever happens to it (Antony, 19 Oct): no hover, pressed or current fill; only the focus ring */

/* ------------------------------------------------------------------ footer */
.foot__grid {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule);
}
:where(.foot__grid > *) { background: var(--c-bg); min-width: 0; }
.foot__brand { display: flex; align-items: center; min-height: var(--ctl); padding: var(--pad); }
.foot__list { display: grid; gap: var(--rule); background: var(--c-rule); }
:where(.foot__list > li) { display: flex; background: var(--c-bg); min-width: 0; }
.foot__list--social { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.foot__contact { display: flex; flex-direction: column; justify-content: center; gap: var(--gap-label); padding: var(--pad); }
.foot__contact > .link { align-self: flex-start; }
/* each address with its name beside it, the names in one column so the addresses line up (Antony, topic 362 msg 4291) */
.foot__addresses { display: grid; grid-template-columns: max-content minmax(0, 1fr); column-gap: var(--s4); align-items: baseline; }
.foot__addresses > .link { justify-self: start; min-height: var(--s6); }   /* lines close together (msg 4295); a 32px target, agreed as the one exception to 48px (msg 4339) */

/* the credit under the footer: Square9's own stamp, the same on every site Square9 makes, in Square9's look rather
   than this site's (Antony, topic 149 msgs 4385, 4405, 4408, 23 Oct 2026): a white card with a black outline, the
   label outlined in Tanker left of Square9's logo, a black block behind it. On hover the card presses onto the block.
   Black and white only. Centred under the footer (msg 4303). */
.foot__credit { display: flex; justify-content: center; padding: var(--s5) 0 var(--s6); }
.foot__credit-link { position: relative; display: inline-flex; text-decoration: none; }
.foot__credit-link::before { content: ""; position: absolute; inset: 0; transform: translate(var(--credit-offset), var(--credit-offset)); background: var(--black); border-radius: var(--credit-radius); }
.foot__credit-card {
  position: relative; display: inline-flex; align-items: center; gap: var(--s2);
  padding: var(--s3) var(--s4); background: var(--white);
  border: var(--credit-border) solid var(--black); border-radius: var(--credit-radius);
  transition: transform var(--t-credit);
}
.foot__credit-label { display: block; height: var(--credit-label-h); width: auto; }
.foot__credit-logo { display: block; height: var(--credit-h); width: auto; }
.foot__credit-link:hover .foot__credit-card, .foot__credit-link.is-hover .foot__credit-card { transform: translate(var(--credit-offset), var(--credit-offset)); }
.foot__credit-link:focus-visible, .foot__credit-link.is-focus { outline-offset: var(--credit-offset); }
.foot__link {
  flex: 1; display: flex; align-items: center;
  min-height: var(--ctl); padding: 0 var(--pad);
  font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase; text-decoration: none;
}
@media (min-width: 1024px) {
  .foot__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .foot__list--legal { grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
}

/* prototype strip: only in the prototype build, never on the live site */
.proto {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--s4);
  padding: 0 var(--pad);
  border: var(--rule) solid var(--c-rule); border-top: 0;
  background: var(--c-fill);
}

/* ------------------------------------------------------------------ section bar */
.bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0 var(--s4);
  min-height: var(--ctl); padding: 0 var(--pad);
  background: var(--c-bar); color: var(--c-on-bar);
}
.bar__title { font: var(--type-bar); letter-spacing: var(--ls-caps); text-transform: uppercase; }
.bar__link {
  display: inline-flex; align-items: center; gap: var(--s2);
  min-height: var(--ctl); min-width: var(--ctl);
  padding: 0 var(--s2); margin-inline: calc(-1 * var(--s2));   /* hover box inset all round, like .link */
  font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase;
  text-decoration: underline; text-decoration-thickness: var(--rule); text-underline-offset: var(--s1);
}
.bar__link:hover, .bar__link.is-hover { background: linear-gradient(var(--c-here), var(--c-here)) center / 100% calc(var(--lh-20) + 2 * var(--s2)) no-repeat; color: var(--c-text); }
.bar__link:active, .bar__link.is-active { background: linear-gradient(var(--c-bg), var(--c-bg)) center / 100% calc(var(--lh-20) + 2 * var(--s2)) no-repeat; color: var(--c-text); }
.bar__link:focus-visible, .bar__link.is-focus { outline-color: var(--c-here); outline-offset: 0; }

/* ---- src/components/feedback.css ---- */
/* Feedback and marks: label, tag, placeholder, notice, error summary, text links. */

/* a small label: mono capitals. Used above every value, and anywhere a thing needs naming quietly */
.label { font: var(--type-label); letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--c-text-2); }

/* tag: a short black stamp ("Sold out", "Prototype") */
.tag {
  display: inline-flex; align-items: center;
  padding: var(--s1) var(--s2);
  background: var(--c-bar); color: var(--c-on-bar);
  font: var(--type-label-strong); letter-spacing: var(--ls-label); text-transform: uppercase;
}

/* placeholder: anything not known yet. Hatched, dashed, [bracketed]. It must never read as a fact. */
.ph {
  display: flex; align-items: center; justify-content: center;
  padding: var(--pad);
  background: repeating-linear-gradient(-45deg, var(--c-fill) 0 var(--s2), var(--c-bg) var(--s2) var(--s4));
  border: var(--rule) dashed var(--c-text-2);
  color: var(--c-text-2);
  font: var(--type-mono-small); text-align: center; text-transform: none; letter-spacing: 0;
}
.ph--block { justify-content: flex-start; align-items: flex-start; min-height: var(--s9); text-align: left; }
.ph--media { aspect-ratio: var(--ratio-square); width: 100%; border: 0; }
.ph--line { justify-content: flex-start; min-height: var(--ctl); text-align: left; }
.ph--inline { display: inline-flex; align-self: flex-start; padding: 0 var(--s1); }

/* notice: a message in a ruled box. Success is plain, error is inverted, prototype carries a tag. */
.notice {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--gap-stack);
  padding: var(--pad);
  border: var(--rule) solid var(--c-rule);
  font: var(--type-body-strong);
}
.notice__title { font: var(--type-title-s); letter-spacing: var(--ls-caps); text-transform: uppercase; }
.notice--success { box-shadow: inset 0 0 0 var(--rule) var(--c-rule); }
.notice--error { background: var(--c-bar); color: var(--c-on-bar); }
.notice--proto { background: var(--c-fill); }
.notice .btn, .notice .link { margin-top: 0; }

/* error summary (checkout): every problem at the top, each one a link to its field */
.errsum { padding: var(--pad); border: var(--rule-thick) solid var(--c-rule); display: flex; flex-direction: column; gap: var(--gap-stack); }
.errsum:focus-visible { outline-offset: var(--rule); }
.errsum__title { font: var(--type-title-s); letter-spacing: var(--ls-caps); text-transform: uppercase; }
.errsum__list { display: flex; flex-direction: column; }
.errsum__list a {
  display: flex; align-items: center; min-height: var(--ctl);
  font: var(--type-body-strong);
  text-decoration: underline; text-decoration-thickness: var(--rule); text-underline-offset: var(--s1);
}
.errsum__list a:hover { background: var(--c-here); }

/* text link: a standalone link or link-styled button, never inside running text, always a full tap target.
   Hover and pressed draw a box with the same space all round the text, inset from the 48px tap target
   (Antony, 19 Oct, option B); the side padding is taken back by the margin, so the text keeps its edge. */
.link {
  display: inline-flex; align-items: center; min-height: var(--ctl);
  padding: 0 var(--s2); margin-inline: calc(-1 * var(--s2)); border: 0; background: none;
  font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase;
  text-decoration: underline; text-decoration-thickness: var(--rule); text-underline-offset: var(--s1);
  cursor: pointer;
}
.link:hover, .link.is-hover { background: linear-gradient(var(--c-here), var(--c-here)) center / 100% calc(var(--lh-20) + 2 * var(--s2)) no-repeat; }
.link:active, .link.is-active { background: linear-gradient(var(--c-bar), var(--c-bar)) center / 100% calc(var(--lh-20) + 2 * var(--s2)) no-repeat; color: var(--c-on-bar); }
/* an email address keeps its own case, in body type; the hover box follows its line height */
.link--address { font: var(--type-body-strong); text-transform: none; letter-spacing: 0; }
.link--address:is(:hover, .is-hover, :active, .is-active) { background-size: 100% calc(var(--lh-16) + 2 * var(--s2)); }

/* ---- src/components/actions.css ---- */
/* Actions: buttons, crumbs (the way back up), row links. */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  min-height: var(--ctl); padding: 0 var(--s5);
  border: var(--rule) solid var(--c-rule); border-radius: 0;
  background: var(--c-bg); color: var(--c-text);
  font: var(--type-btn); letter-spacing: var(--ls-caps); text-transform: uppercase; text-align: center; text-decoration: none;
}
.btn--primary { background: var(--c-bar); color: var(--c-on-bar); }
.btn--lg { min-height: var(--ctl-lg); font: var(--type-btn-lg); letter-spacing: var(--ls-caps); }
.btn--block { display: flex; width: 100%; }
.btn--cell { border: 0; }   /* a button that fills a ruled cell, the cell draws the rules */
.btn:hover, .btn.is-hover { background: var(--c-here); color: var(--c-text); }
.btn:active, .btn.is-active { background: var(--c-bar); color: var(--c-on-bar); }
.btn--primary:active, .btn--primary.is-active { background: var(--c-bg); color: var(--c-text); }
.btn[disabled], .btn[aria-disabled="true"], .btn.is-disabled {
  background: var(--c-fill); color: var(--c-text-2); border-style: dashed; border-color: var(--c-text-2); cursor: not-allowed;
}
.btn--cell[disabled], .btn--cell.is-disabled { border: 0; }
.btn[aria-busy="true"], .btn.is-loading { background: var(--c-fill); color: var(--c-text); cursor: progress; }
/* focus on a black button: the black ring outside, and a yellow ring inside that shows on the black */
.btn--primary:focus-visible, .btn--primary.is-focus { box-shadow: inset 0 0 0 var(--rule-thick) var(--c-here); }
.btn--cell:focus-visible, .btn--cell.is-focus { outline-offset: calc(-2 * var(--rule-thick)); }  /* a cell button keeps its ring inside the cell */

/* crumbs: where this page sits, and a one-tap way back up */
.crumbs { display: flex; align-items: center; gap: var(--s2); min-width: 0; }
.crumbs__up {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  min-height: var(--ctl); min-width: var(--ctl); padding: 0 var(--s4);
  border: var(--rule) solid var(--c-rule);
  font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase; text-decoration: none;
}
.crumbs__up:hover, .crumbs__up.is-hover { background: var(--c-here); }
.crumbs__up:active, .crumbs__up.is-active { background: var(--c-bar); color: var(--c-on-bar); }
.crumbs__here { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* row links: a list of big links, one per ruled row */
.rows { display: grid; gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
:where(.rows > li) { display: flex; background: var(--c-bg); min-width: 0; }
.row {
  flex: 1; display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  min-height: var(--ctl-lg); padding: 0 var(--pad);
  font: var(--type-title-s); letter-spacing: var(--ls-caps); text-transform: uppercase; text-decoration: none;
}
.row:hover, .row.is-hover { background: var(--c-here); }
.row:active, .row.is-active { background: var(--c-bar); color: var(--c-on-bar); }
.row:active .label, .row.is-active .label { color: var(--c-on-bar); }
.row:focus-visible, .row.is-focus { outline-offset: calc(-2 * var(--rule-thick)); }
@media (min-width: 1024px) { .rows--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* ---- src/components/facts.css ---- */
/* Facts: the form look. Each fact is a ruled cell holding a small label and its value.
   A facts grid is 2 columns on a phone and 4 from 1024; cells share rules. */

.facts {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule);
}
:where(.facts > *) { background: var(--c-bg); min-width: 0; }
.facts--1 { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 1024px) {
  .facts { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .facts--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .facts--1 { grid-template-columns: minmax(0, 1fr); }
}

.fact { display: flex; flex-direction: column; gap: var(--gap-label); padding: var(--pad); }
.fact--full { grid-column: 1 / -1; }
.fact--wide { grid-column: 1 / -1; }
@media (min-width: 1024px) { .fact--wide { grid-column: span 2; } }
.fact__value { font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase; overflow-wrap: anywhere; }
.fact__value--big { font: var(--type-date); letter-spacing: var(--ls-caps); }
.fact__value--text { font: var(--type-body-strong); text-transform: none; letter-spacing: 0; }
.fact__note { font: var(--type-small); color: var(--c-text-2); }
.fact__line { display: block; }
.fact__pairs { display: grid; grid-template-columns: max-content max-content; gap: var(--gap-label) var(--s4); }
.fact__pairs dt { font: var(--type-body); text-transform: none; letter-spacing: 0; }
.fact__pairs dd { font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase; }
.fact--action { padding: 0; display: flex; }
.fact--action > .btn { flex: 1; }

/* a facts list in rows: label beside value (bio, order details) */
.facts--rows .fact { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: var(--s3); align-items: baseline; }
.facts--rows .fact__value { font: var(--type-body-strong); text-transform: none; letter-spacing: 0; }
.facts--rows .fact__value > * + * { margin-top: var(--gap-label); }
.facts--rows .fact > :not(.label) { grid-column: 2; justify-self: start; }

/* ticks: a ruled list of short facts (a tee's details) */
.ticks > li { padding-block: var(--s2); border-bottom: var(--rule) solid var(--c-rule); font: var(--type-body); }
.ticks > li:first-child { border-top: var(--rule) solid var(--c-rule); }

/* ---- src/components/forms.css ---- */
/* Forms: field (label, control, message), input, select, choices (size and colour), quantity, sign-up.
   Label above control, message below it, every gap --gap-stack. The field you are in turns --c-here.
   An invalid control gets a 4px edge and a black message that starts "Error:" for screen readers. */

.field { display: flex; flex-direction: column; gap: var(--gap-stack); min-width: 0; }
.field__label { font: var(--type-label-strong); letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--c-text); }
.field__hint { font: var(--type-small); color: var(--c-text-2); }
.field__error {
  align-self: flex-start; width: fit-content; padding: var(--s1) var(--s2);
  background: var(--c-bar); color: var(--c-on-bar);
  font: var(--type-mono-small);
}

.input, .select {
  width: 100%; min-width: 0; height: var(--ctl); padding: 0 var(--s3);
  border: var(--rule) solid var(--c-rule); border-radius: 0;
  background: var(--c-fill); color: var(--c-text);
  font: var(--type-input);
  -webkit-appearance: none; appearance: none;
}
.input:hover, .input.is-hover, .select:hover, .select.is-hover { background: var(--c-bg); }
.input:focus, .input.is-focus, .select:focus, .select.is-focus { background: var(--c-here); outline: var(--rule-thick) solid var(--c-text); outline-offset: var(--rule); }
.input:disabled, .select:disabled { border-style: dashed; border-color: var(--c-text-2); color: var(--c-text-2); cursor: not-allowed; }
.input[aria-invalid="true"], .select[aria-invalid="true"], .is-invalid .input, .is-invalid .select { box-shadow: inset 0 0 0 var(--rule) var(--c-rule); }

/* select: native control, drawn flat, with a solid down-pointer */
.select-wrap { position: relative; display: flex; }
.select { padding-right: var(--s7); cursor: pointer; }
.select-wrap::after {
  content: ""; position: absolute; right: var(--s4); top: 50%; pointer-events: none;
  border-left: var(--s2) solid transparent; border-right: var(--s2) solid transparent; border-top: var(--s2) solid var(--c-text);
  transform: translateY(-50%);
}

/* choices: radio buttons drawn as boxes (size, colour). Chosen = --c-here and a 4px edge.
   Not available = struck through, dashed and greyed, and cannot be chosen. */
.choices { display: block; min-width: 0; }
.choices > legend { float: left; width: 100%; margin-bottom: var(--gap-stack); }
.choices > legend + * { clear: both; }
.choices > .field__error { margin-top: var(--gap-stack); }
.choices__list { display: flex; flex-wrap: wrap; gap: var(--gap-stack); }
.choice { position: relative; display: flex; }
.choice__input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.choice__box {
  display: flex; align-items: center; justify-content: center;
  min-width: var(--ctl); min-height: var(--ctl); padding: 0 var(--s3);
  border: var(--rule) solid var(--c-rule); background: var(--c-bg);
  font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase;
}
.choice__input:hover + .choice__box, .choice.is-hover .choice__box { background: var(--c-here); }
.choice__input:checked + .choice__box, .choice.is-checked .choice__box { background: var(--c-here); box-shadow: inset 0 0 0 var(--rule) var(--c-rule); }
.choice__input:focus-visible + .choice__box, .choice.is-focus .choice__box { outline: var(--rule-thick) solid var(--c-text); outline-offset: var(--rule); }
.choice__input:active + .choice__box, .choice.is-active .choice__box { background: var(--c-bar); color: var(--c-on-bar); }
.choice__input:disabled { cursor: not-allowed; }
.choice__input:disabled + .choice__box, .choice.is-disabled .choice__box {
  background: var(--c-fill); color: var(--c-text-2); border-style: dashed; border-color: var(--c-text-2);
  text-decoration: line-through; text-decoration-thickness: var(--rule);
}
.is-invalid .choice__box { box-shadow: inset 0 0 0 var(--rule) var(--c-rule); }

/* quantity: minus, the number, plus; three cells sharing rules */
.qty { display: inline-flex; align-self: flex-start; }
.qty__btn, .qty__value {
  display: flex; align-items: center; justify-content: center;
  width: var(--ctl); height: var(--ctl);
  border: var(--rule) solid var(--c-rule);
  font: var(--type-value);
}
.qty > * + * { border-left-width: 0; }
.qty__btn { background: var(--c-bg); padding: 0; }
.qty__value { font: var(--type-mono-small); }
.qty__btn:hover, .qty__btn.is-hover { background: var(--c-here); }
.qty__btn:active, .qty__btn.is-active { background: var(--c-bar); color: var(--c-on-bar); }
.qty__btn:focus-visible, .qty__btn.is-focus { outline-offset: calc(-1 * var(--rule-thick)); }
.qty__btn:disabled { background: var(--c-fill); color: var(--c-text-2); cursor: not-allowed; }

/* sign-up: email and button on one line; the message underneath; success replaces the field */
.signup { display: flex; flex-direction: column; gap: var(--gap-stack); padding: var(--pad); border: var(--rule) solid var(--c-rule); }
.signup__row { display: flex; }
.signup__row .input { flex: 1; }
.signup__row .btn { flex: none; border-left: 0; }
.signup--lg .input, .signup--lg .btn { height: var(--ctl-lg); }
.signup--lg .input { font: var(--type-input-lg); }
.signup__done { font: var(--type-title-s); letter-spacing: var(--ls-caps); text-transform: uppercase; }
.signup__foot { display: flex; }
@media (min-width: 1024px) {
  .signup { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); column-gap: var(--s4); align-items: end; }
  .signup__foot { justify-content: flex-end; }
}

/* a form laid out in ruled cells (product buy box, checkout) */
.formcells { display: grid; gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
:where(.formcells > *) { background: var(--c-bg); min-width: 0; padding: var(--pad); }
.formcells > .formcells__flush { padding: 0; display: flex; }
.formcells > :empty { display: none; }
.formcells__msg { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0 var(--s4); box-shadow: inset 0 0 0 var(--rule) var(--c-rule); }
.formcells__flush > .btn { flex: 1; }
.formcells__group { display: flex; flex-direction: column; gap: var(--s4); }
.formcells__legend { font: var(--type-title-s); letter-spacing: var(--ls-caps); text-transform: uppercase; }
.formcells__pair { display: flex; flex-direction: column; gap: var(--s4); }
@media (min-width: 1024px) { .formcells__pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---- src/components/gigs.css ---- */
/* Gigs: the gig detail block (next gig) and gig rows (upcoming, past, sold out). */

/* gig detail: facts on the left, poster on the right from 1024; all cells share rules */
.gig { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
:where(.gig > *) { background: var(--c-bg); min-width: 0; }
.gig .facts { border: 0; }
.gig__poster { padding: var(--pad); }
.gig__poster img { width: 100%; }
@media (min-width: 1024px) {
  .gig--full { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
}
.fact--half { grid-column: span 1; }
@media (min-width: 1024px) { .fact--half { grid-column: span 2; } }
.gig__status { display: flex; flex-direction: column; align-items: flex-start; gap: var(--gap-stack); }
.gig__status > .btn { align-self: stretch; }

/* gig rows: one ruled row per gig. Desktop shows column labels above. */
.gigrows { display: grid; gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
:where(.gigrows > li) { background: var(--c-bg); min-width: 0; }
.gigrow {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "date status" "venue venue" "city city";
  column-gap: var(--s4); row-gap: var(--gap-label);
  padding: var(--pad);
}
.gigrow__date { grid-area: date; font: var(--type-title-s); letter-spacing: var(--ls-caps); text-transform: uppercase; align-self: center; }
.gigrow__venue { grid-area: venue; font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase; }
.gigrow__city { grid-area: city; font: var(--type-body); }
.gigrow__status { grid-area: status; display: flex; align-items: center; justify-content: flex-end; }
.gigrows__head { display: none; }
.gigrow--empty, .gigrow--ph { display: block; padding: var(--pad); }
/* past rows add With: on a phone a fourth line, labelled; on a desktop its own column */
.gigrow--past { grid-template-columns: minmax(0, 1fr); grid-template-areas: "date" "venue" "city" "with"; }
.gigrow__with { grid-area: with; font: var(--type-body); }
.gigrow__with:empty { display: none; }
.gigrow__label { margin-right: var(--s1); }
/* Show all: the button hangs under the first rows and shares their rules; once open it goes */
.more > .gigrows { border-top-width: 0; }
.more__btn { border-top-width: 0; list-style: none; cursor: pointer; }
.more__btn::-webkit-details-marker { display: none; }
.more[open] > .more__btn { display: none; }
@media (min-width: 1024px) {
  .gigrow, .gigrows__head {
    grid-template-columns: minmax(0, 3fr) minmax(0, 5fr) minmax(0, 2fr) minmax(0, 2fr);
    grid-template-areas: "date venue city status";
    align-items: center;
  }
  .gigrow--past {
    grid-template-columns: minmax(0, 3fr) minmax(0, 4fr) minmax(0, 2fr) minmax(0, 5fr);
    grid-template-areas: "date venue city with";
  }
  .gigrow__label { display: none; }
  .gigrow__with:empty { display: block; }
  .gigrow { min-height: var(--ctl-lg); padding-block: var(--s2); }
  .gigrow__status { justify-content: flex-start; }
  .gigrows__head { display: grid; column-gap: var(--s4); padding: var(--s2) var(--pad); background: var(--c-fill); }
  .gigrow--empty, .gigrow--ph { display: block; }
}

/* ---- src/components/shop.css ---- */
/* Shop: product card and grid, and the product page parts (photos, buy box, details). */

/* cards: a ruled grid of tees, 2 across on a phone; from 1024, 4 or 5 across, or wide: two across with the photo
   beside the text (one or two tees) */
.cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
:where(.cards > li) { background: var(--c-bg); min-width: 0; display: flex; }
/* a short last row: its last card fills it, with its photo kept one column wide beside the text
   (so one tee fills its row with the photo the size of the others) */
.cards > li:last-child:nth-child(odd) { grid-column: 1 / -1; }
.cards > li:last-child:nth-child(odd) .card { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cards > li:last-child:nth-child(odd) .card__media { border-bottom: 0; border-right: var(--rule) solid var(--c-rule); }
.cards > li:last-child:nth-child(odd) .card__body { align-content: start; }
@media (min-width: 1024px) {
  .cards--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .cards--5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .cards--wide > li:last-child:nth-child(odd) { grid-column: auto; }
  .cards--wide .card { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cards--wide .card__media { border-bottom: 0; border-right: var(--rule) solid var(--c-rule); }
  .cards--wide .card__body { align-content: start; }
  :is(.cards--4, .cards--5) > li:last-child:nth-child(odd) { grid-column: auto; }
  :is(.cards--4, .cards--5) > li:last-child:nth-child(odd) .card { display: flex; }
  :is(.cards--4, .cards--5) > li:last-child:nth-child(odd) .card__media { border-bottom: var(--rule) solid var(--c-rule); border-right: 0; }
  .cards--4 > li:last-child:nth-child(4n+1) { grid-column: span 4; }
  .cards--4 > li:last-child:nth-child(4n+2) { grid-column: span 3; }
  .cards--4 > li:last-child:nth-child(4n+3) { grid-column: span 2; }
  .cards--5 > li:last-child:nth-child(5n+1) { grid-column: span 5; }
  .cards--5 > li:last-child:nth-child(5n+2) { grid-column: span 4; }
  .cards--5 > li:last-child:nth-child(5n+3) { grid-column: span 3; }
  .cards--5 > li:last-child:nth-child(5n+4) { grid-column: span 2; }
  :is(.cards--4 > li:last-child:not(:nth-child(4n)), .cards--5 > li:last-child:not(:nth-child(5n))) .card { display: grid; }
  :is(.cards--4 > li:last-child:not(:nth-child(4n)), .cards--5 > li:last-child:not(:nth-child(5n))) .card__media { border-bottom: 0; border-right: var(--rule) solid var(--c-rule); }
  :is(.cards--4 > li:last-child:not(:nth-child(4n)), .cards--5 > li:last-child:not(:nth-child(5n))) .card__body { grid-column: 2 / -1; align-content: start; }
  .cards--4 > li:last-child:nth-child(4n+1) .card { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .cards--4 > li:last-child:nth-child(4n+2) .card { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .cards--4 > li:last-child:nth-child(4n+3) .card { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cards--5 > li:last-child:nth-child(5n+1) .card { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .cards--5 > li:last-child:nth-child(5n+2) .card { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .cards--5 > li:last-child:nth-child(5n+3) .card { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .cards--5 > li:last-child:nth-child(5n+4) .card { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.card { flex: 1; display: flex; flex-direction: column; text-decoration: none; }
.card__media { display: block; border-bottom: var(--rule) solid var(--c-rule); }
.card__media img { width: 100%; aspect-ratio: var(--ratio-square); object-fit: cover; }
.card__body {
  flex: 1; display: grid; grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "name name" "meta price";
  align-items: end; gap: var(--gap-stack);
  padding: var(--pad);
}
.card__name { grid-area: name; font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase; }
.card__meta { grid-area: meta; }
.card__price { grid-area: price; font: var(--type-value); letter-spacing: var(--ls-caps); }
.card:hover, .card.is-hover { background: var(--c-here); }
.card:hover .label, .card.is-hover .label { color: var(--c-text); }
.card:active, .card.is-active { background: var(--c-bar); color: var(--c-on-bar); }
.card:active .label, .card.is-active .label { color: var(--c-on-bar); }
.card:focus-visible, .card.is-focus { outline-offset: calc(-1 * var(--rule-thick)); }

/* product page: photos 7/12, buy box 5/12 from 1024; stacked on a phone */
.product { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
:where(.product > *) { background: var(--c-bg); min-width: 0; }
/* inside each column, parts are divided by a top rule (not the gap trick), so a shorter column stays white */
.product__media { display: flex; flex-direction: column; }
.product__media img { width: 100%; }
.product__media img + img { border-top: var(--rule) solid var(--c-rule); }
.product__info { display: flex; flex-direction: column; }
.product__info > * { min-width: 0; }
.product__info > * + * { border-top: var(--rule) solid var(--c-rule); }
.product__name { padding: var(--pad); font: var(--type-name); letter-spacing: var(--ls-caps); text-transform: uppercase; overflow-wrap: anywhere; }
.product__price { padding: var(--pad); font: var(--type-price-lg); letter-spacing: var(--ls-caps); }
.product__info .formcells { border-width: var(--rule) 0 0; }
.product__details { display: flex; flex-direction: column; gap: var(--gap-stack); padding: var(--pad); }
@media (min-width: 1024px) {
  .product { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
}

/* measuring diagram: a flat tee in grey with the measurements in black, at its drawn size (320 wide), shrinking
   with a narrower cell. Strokes stay one rule wide at any size. */
.teefig { display: block; min-width: 0; }
.teefig__svg { display: block; max-width: 100%; height: auto; }
.teefig__tee, .teefig__seam, .teefig__line { stroke-width: var(--rule); vector-effect: non-scaling-stroke; stroke-linejoin: round; }
.teefig__tee { fill: var(--c-bg); stroke: var(--c-text-2); }
.teefig__seam { fill: none; stroke: var(--c-text-2); }
.teefig__line { fill: none; stroke: var(--c-text); }
.teefig__label { font: var(--type-mono-small); letter-spacing: var(--ls-label); text-transform: uppercase; fill: var(--c-text); }

/* size guide: how it is measured (words and diagram), then the table; side by side from 1024, the table under
   the product photos and the diagram under the buy box */
.sizeguide { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-areas: "how" "chart"; gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
:where(.sizeguide > *) { background: var(--c-bg); min-width: 0; }
.sizeguide__how { grid-area: how; display: flex; flex-direction: column; gap: var(--s4); padding: var(--pad); }
.sizeguide__note { max-width: 40em; font: var(--type-body); }
.sizeguide__chart { grid-area: chart; }
@media (min-width: 1024px) {
  .sizeguide { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); grid-template-areas: "chart how"; }
}

/* size table: ruled cells in equal columns, the head row on the fill; flush with its cell, so each cell draws
   only its bottom and left rules and the outer edge is the cell's own */
.sizes { width: 100%; border-collapse: separate; border-spacing: 0; table-layout: fixed; }
.sizes th, .sizes td { padding: var(--s3) var(--pad); border: 0 solid var(--c-rule); border-width: 0 0 var(--rule) var(--rule); text-align: left; }
.sizes tr > :first-child { border-left-width: 0; }
.sizes tbody tr:last-child > * { border-bottom-width: 0; }
.sizes thead th { font: var(--type-label-strong); letter-spacing: var(--ls-label); text-transform: uppercase; background: var(--c-fill); }
.sizes tbody th, .sizes td { font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase; }

/* ---- src/components/bag.css ---- */
/* Bag and checkout: bag line, totals, order summary lines. */

.lines { display: grid; gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
:where(.lines > li) { background: var(--c-bg); min-width: 0; }

/* bag line: photo and name, then size, quantity, price and Remove */
.line {
  display: grid; grid-template-columns: var(--thumb) minmax(0, 1fr);
  grid-template-areas: "media main" "controls controls";
  gap: var(--s4) var(--pad); padding: var(--pad);
}
.line__media { grid-area: media; display: block; border: var(--rule) solid var(--c-rule); align-self: start; }
.line__media img { width: 100%; aspect-ratio: var(--ratio-square); object-fit: cover; }
.line__main { grid-area: main; display: flex; flex-direction: column; gap: var(--gap-stack); min-width: 0; }
.line__name {
  align-self: flex-start; display: inline-flex; align-items: center; min-height: var(--ctl);
  font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase;
  text-decoration: underline; text-decoration-thickness: var(--rule); text-underline-offset: var(--s1);
}
.line__name:hover { background: var(--c-here); }
.line__facts { display: flex; flex-wrap: wrap; gap: var(--gap-label) var(--s4); }
.line__facts > div { display: flex; gap: var(--s2); align-items: baseline; }
.line__facts dd { font: var(--type-body-strong); }
.line__price { font: var(--type-value); letter-spacing: var(--ls-caps); }
.line__controls { grid-area: controls; display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--s4); }
.line__controls .field { flex: 1 1 calc(var(--ctl) * 2); }
.line__controls .select-wrap { min-width: calc(var(--ctl) * 2); }
.line__controls .btn { margin-left: auto; }
@media (min-width: 1024px) {
  .line { grid-template-columns: var(--thumb) minmax(0, 1fr) auto; grid-template-areas: "media main controls"; align-items: center; }
  .line__controls { flex-wrap: nowrap; }
  .line__controls .field { flex: none; width: calc(var(--ctl) * 3); }
}

/* totals: label left, amount right, total last and heavier */
.totals { display: grid; gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
.totals__row { display: flex; align-items: center; justify-content: space-between; gap: var(--s4); min-height: var(--ctl); padding: 0 var(--pad); background: var(--c-bg); }
.totals__row dt { font: var(--type-label-strong); letter-spacing: var(--ls-label); text-transform: uppercase; }
.totals__row dd { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: flex-end; gap: 0 var(--s2); font: var(--type-value); letter-spacing: var(--ls-caps); text-align: right; }
.totals__row--total { min-height: var(--ctl-lg); }
.totals__row--total dd { font: var(--type-title-m); letter-spacing: var(--ls-caps); }
.totals__extra { font: var(--type-small); letter-spacing: 0; }

/* order summary line: compact, no controls */
.sumline { display: grid; grid-template-columns: var(--ctl-lg) minmax(0, 1fr) auto; gap: var(--pad); align-items: start; padding: var(--pad); }
.sumline__media { border: var(--rule) solid var(--c-rule); }
.sumline__media img { width: 100%; aspect-ratio: var(--ratio-square); object-fit: cover; }
.sumline__main { display: flex; flex-direction: column; gap: var(--gap-label); min-width: 0; }
.sumline__name { font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase; }
.sumline__price { font: var(--type-value); letter-spacing: var(--ls-caps); }

/* ---- src/components/music.css ---- */
/* Music: release card and grid, the release page block, tracklist, video card and grid. */

.rels { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
:where(.rels > li) { background: var(--c-bg); min-width: 0; display: flex; }
/* row (Music): two across on a phone, where the last of an odd number fills its row with the sleeve beside the
   text (the same sleeve size as the rest); every release in one row from 1024 */
.rels--row > li:last-child:nth-child(odd) { grid-column: 1 / -1; }
.rels--row > li:last-child:nth-child(odd) .rel { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.rels--row > li:last-child:nth-child(odd) .rel__media { border-bottom: 0; border-right: var(--rule) solid var(--c-rule); }
@media (min-width: 1024px) {
  .rels--row { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
  .rels--row > li:last-child:nth-child(odd) { grid-column: auto; }
  .rels--row > li:last-child:nth-child(odd) .rel { display: flex; }
  .rels--row > li:last-child:nth-child(odd) .rel__media { border-bottom: var(--rule) solid var(--c-rule); border-right: 0; }
}
.rel { flex: 1; display: flex; flex-direction: column; text-decoration: none; }
.rel__media { display: block; border-bottom: var(--rule) solid var(--c-rule); }
.rel__media img { width: 100%; aspect-ratio: var(--ratio-square); object-fit: cover; }
.rel__body { flex: 1; display: flex; flex-direction: column; gap: var(--gap-stack); padding: var(--pad); }
.rel__title { font: var(--type-title-s); letter-spacing: var(--ls-caps); text-transform: uppercase; }
.rel__meta { display: flex; flex-wrap: wrap; gap: var(--gap-label) var(--s2); align-items: center; }
.rel:hover, .rel.is-hover { background: var(--c-here); }
.rel:hover .label, .rel.is-hover .label { color: var(--c-text); }
.rel:active, .rel.is-active { background: var(--c-bar); color: var(--c-on-bar); }
.rel:active .label, .rel.is-active .label { color: var(--c-on-bar); }
.rel:focus-visible, .rel.is-focus { outline-offset: calc(-1 * var(--rule-thick)); }
/* wide: sleeve beside the text, for two releases across a desktop page */
@media (min-width: 1024px) {
  .rels--wide .rel { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rels--wide .rel__media { border-bottom: 0; border-right: var(--rule) solid var(--c-rule); }
}

/* release page: sleeve 7/12, facts and links 5/12 from 1024 */
.release { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
:where(.release > *) { background: var(--c-bg); min-width: 0; }
.release__media img { width: 100%; }
.release__info { display: flex; flex-direction: column; }
.release__info > * { min-width: 0; }
.release__info > * + * { border-top: var(--rule) solid var(--c-rule); }
.release__info .facts { border-width: var(--rule) 0 0; }
.release__title { padding: var(--pad); font: var(--type-name); letter-spacing: var(--ls-caps); text-transform: uppercase; }
.release__block { display: flex; flex-direction: column; gap: var(--gap-stack); padding: var(--pad); }
.release__block > .link { align-self: flex-start; }
/* Buy: one square box per download format (MP3, WAV), side by side */
.buy { display: flex; gap: var(--s2); }
.buy__box {
  display: flex; align-items: center; justify-content: center;
  width: var(--s9); aspect-ratio: var(--ratio-square);
  border: var(--rule) solid var(--c-rule);
  font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase; text-decoration: none;
}
.buy__box:hover, .buy__box.is-hover { background: var(--c-here); }
.buy__box:active, .buy__box.is-active { background: var(--c-bar); color: var(--c-on-bar); }
.buy__box:focus-visible, .buy__box.is-focus { outline-offset: calc(-2 * var(--rule-thick)); }
@media (min-width: 1024px) { .release { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); } }

/* tracklist: numbered rows; the numbers are the real track numbers */
.tracks { display: grid; gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
:where(.tracks > li) { display: grid; grid-template-columns: var(--ctl) minmax(0, 1fr); align-items: center; gap: var(--s3); min-height: var(--ctl); padding: 0 var(--pad); background: var(--c-bg); }
.tracks__no { font: var(--type-mono-small); color: var(--c-text-2); }
.tracks__title { font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase; padding-block: var(--s3); }

/* video card: YouTube's thumbnail at 16:9, the song, the year; the whole card links out to the video */
.vids { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
:where(.vids > li) { background: var(--c-bg); min-width: 0; display: flex; }
/* a short last row: its last card fills it, with its thumbnail kept one column wide beside the text */
.vids > li:last-child:nth-child(odd) { grid-column: 1 / -1; }
.vids > li:last-child:nth-child(odd) .vid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.vids > li:last-child:nth-child(odd) .vid__media { border-bottom: 0; border-right: var(--rule) solid var(--c-rule); }
@media (min-width: 1024px) {
  .vids { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .vids > li:last-child:nth-child(odd) { grid-column: auto; }
  .vids > li:last-child:nth-child(odd) .vid { display: flex; }
  .vids > li:last-child:nth-child(odd) .vid__media { border-bottom: var(--rule) solid var(--c-rule); border-right: 0; }
  .vids > li:last-child:nth-child(4n+1) { grid-column: span 4; }
  .vids > li:last-child:nth-child(4n+2) { grid-column: span 3; }
  .vids > li:last-child:nth-child(4n+3) { grid-column: span 2; }
  .vids > li:last-child:is(:nth-child(4n+1), :nth-child(4n+2), :nth-child(4n+3)) .vid { display: grid; }
  .vids > li:last-child:is(:nth-child(4n+1), :nth-child(4n+2), :nth-child(4n+3)) .vid__media { border-bottom: 0; border-right: var(--rule) solid var(--c-rule); }
  .vids > li:last-child:is(:nth-child(4n+1), :nth-child(4n+2), :nth-child(4n+3)) .vid__body { grid-column: 2 / -1; }
  .vids > li:last-child:nth-child(4n+1) .vid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .vids > li:last-child:nth-child(4n+2) .vid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .vids > li:last-child:nth-child(4n+3) .vid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.vid { flex: 1; display: flex; flex-direction: column; text-decoration: none; }
.vid__media { display: block; border-bottom: var(--rule) solid var(--c-rule); }
.vid__media img { width: 100%; aspect-ratio: var(--ratio-video); object-fit: cover; }
.vid__body { flex: 1; display: flex; flex-direction: column; gap: var(--gap-label); padding: var(--pad); }
.vid__title { font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase; }
.vid:hover, .vid.is-hover { background: var(--c-here); }
.vid:hover .label, .vid.is-hover .label { color: var(--c-text); }
.vid:active, .vid.is-active { background: var(--c-bar); color: var(--c-on-bar); }
.vid:active .label, .vid.is-active .label { color: var(--c-on-bar); }
.vid:focus-visible, .vid.is-focus { outline-offset: calc(-1 * var(--rule-thick)); }

/* ---- src/components/content.css ---- */
/* Content blocks: photo, prose. */

/* photo: every band photo is shown at 3:2 (the hero at 21:9 from 1024), filling its cell edge to edge */
.photo { display: block; border: var(--rule) solid var(--c-rule); }
.photo img { width: 100%; aspect-ratio: var(--ratio-photo); object-fit: cover; }
.photo--hero img { aspect-ratio: var(--ratio-hero); object-position: 50% 35%; }
:is(.split, .photos, .stack) .photo { border-width: 0; }
.stack > .photo:not(:first-child) { border-width: 0 var(--rule) var(--rule); }

.photos { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--rule); background: var(--c-rule); border: var(--rule) solid var(--c-rule); }
:where(.photos > li) { background: var(--c-bg); min-width: 0; }
@media (min-width: 1024px) { .photos { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* prose: running text (legal pages, bio). Lines stop at a readable length. */
.prose { display: flex; flex-direction: column; gap: var(--s4); padding: var(--pad); border: var(--rule) solid var(--c-rule); }
.prose > p { max-width: 40em; font: var(--type-body); }
.prose__head { font: var(--type-value); letter-spacing: var(--ls-caps); text-transform: uppercase; }
.prose > .ph { min-height: var(--s9); }
.split > .prose { border: 0; }
