/* public/assets/bsa.css, BreakStream Arts, "The Gallery".
   One rule governs everything here: the only colour on any page is inside an artwork.
   The interface is true black, two type voices and hairlines. No cards, no fills, no panels,
   no shadows, no chamfers, no accent hue. The negative space is the design. */

/* ── fonts: self-hosted, SIL OFL 1.1 (see /fonts/OFL.txt). Both faces are variable, so one
   file carries every weight the site uses and the weight range is declared, never synthesised.
   The fallback faces are SEPARATELY NAMED families: re-declaring "Jost" scoped to a dead
   unicode-range renders no glyph and prevents no reflow. ── */
@font-face{font-family:"EB Garamond";font-style:normal;font-weight:400 700;font-display:swap;src:url(/fonts/eb-garamond.woff2) format("woff2")}
@font-face{font-family:"EB Garamond";font-style:italic;font-weight:400 700;font-display:swap;src:url(/fonts/eb-garamond-italic.woff2) format("woff2")}
@font-face{font-family:"Jost";font-style:normal;font-weight:300 700;font-display:swap;src:url(/fonts/jost.woff2) format("woff2")}
@font-face{font-family:"Garamond Fallback";src:local("Iowan Old Style"),local("Palatino Linotype"),local("Palatino"),local("Georgia"),local("Times New Roman");size-adjust:92%;ascent-override:96%;descent-override:26%;line-gap-override:0%}
@font-face{font-family:"Jost Fallback";src:local("Futura"),local("Avenir Next"),local("Helvetica Neue"),local("Helvetica"),local("Arial");size-adjust:97%;ascent-override:98%;descent-override:22%;line-gap-override:0%}

/* ── tokens. Every ratio below is computed, not estimated; test/contrast.test.mjs parses this
   very block and recomputes each pair from the hex. ── */
:root{
  color-scheme:dark;

  /* ground. TRUE black everywhere, so every artwork bleeds into the page with no edge, no
     frame, no card. One raised surface exists on the whole site. */
  --wall:#000000;
  --wall-lift:#08080a;

  /* ink. Warm off-white, never #fff: paper white on black reads as printed wall text.
     Ratios are against --wall; --ink-3 and --hair-2 also clear their bar on --wall-lift. */
  --ink-1:#ece9e3;   /* 17.33:1  statement, titles, body, selected nav */
  --ink-2:#a29e97;   /*  7.87:1  labels, meta, nav rest, rank two of the statement */
  --ink-3:#827f79;   /*  5.26:1  catalogue numbers, column heads, notes */
  --hair:#1a1a19;    /*  1.21:1  DECORATIVE ONLY: section rules. Never a control. */
  --hair-2:#605e59;  /*  3.24:1 on --wall, 3.09:1 on --wall-lift. CONTROL borders only. */

  /* No accent hue exists in the interface. One warm cream is reserved for the selected
     price cell, and that is the only non-black surface on the site. */
  --sale:#e8d6a8;      /* 14.62:1 against --sale-ink */
  --sale-ink:#000000;

  /* status ink, used by form errors only. Both computed against --wall. */
  --err:#ffb4b4;       /* 11.06:1 */
  --ok:#a9d9b4;        /* 11.61:1 */

  /* type: two voices, nothing else */
  --serif:"EB Garamond","Garamond Fallback","Iowan Old Style","Palatino Linotype",Palatino,Georgia,serif;
  --sans:"Jost","Jost Fallback","Futura","Avenir Next","Helvetica Neue",Helvetica,Arial,sans-serif;

  --t-micro:0.6875rem;    /* 11px  tracked caps: eyebrows, legends, column heads */
  --t-mini:0.75rem;       /* 12px  wall-label secondary, breadcrumb */
  --t-small:0.8125rem;    /* 13px  meta, nav, prices, footer links */
  --t-body:1.0625rem;     /* 17px  serif reading text */
  --t-lede:clamp(1.0625rem,.98rem + .38vw,1.25rem);
  --t-title:clamp(1.25rem,1.1rem + .62vw,1.625rem);
  --t-statement:clamp(1.75rem,1.10rem + 2.05vw,2.75rem);  /* 28px -> 44px */

  --track-caps:.22em;
  --track-caps-tight:.14em;
  --measure:34em;

  /* space. 4px base, top of the scale deliberately enormous. */
  --sp-1:.25rem; --sp-2:.5rem;  --sp-3:.75rem; --sp-4:1rem;
  --sp-5:1.5rem; --sp-6:2rem;   --sp-7:2.75rem;--sp-8:4rem;
  --sp-9:6rem;   --sp-10:8rem;  --sp-11:11rem; --sp-12:15rem;

  --gutter:clamp(1.25rem,5vw,4.5rem);
  --band:clamp(4.5rem,11vw,11rem);
  --shell:1180px;
  --shell-wide:1560px;

  /* motion: a trail arrives instantly and decays over most of a second. So does every state
     here. Rest carries --out; :hover / :focus-within overrides to --in. */
  --in:70ms;   --ease-in:linear;
  --out:820ms; --ease-out:cubic-bezier(.05,.72,.12,1);

  /* the one knob that changes when real footage lands */
  --plate-h:min(78vh,880px);
}
@media(max-width:899px){ :root{ --plate-h:min(56vh,460px) } }

/* ── base ─────────────────────────────────────────────────────────────────────────────── */
*,*::before,*::after{box-sizing:border-box}
/* display on a class beats the UA sheet's [hidden]{display:none}: without this the Update
   button that bsa.js hides on a JS-enhanced cart line stays on screen. */
[hidden]{display:none!important}
html{background:var(--wall);-webkit-text-size-adjust:100%}
body{margin:0;background:var(--wall);color:var(--ink-1);
  font:400 var(--t-body)/1.62 var(--serif);-webkit-font-smoothing:antialiased;
  min-block-size:100svh;display:flex;flex-direction:column}
main{flex:1 0 auto}
img,picture,video,svg{display:block;max-inline-size:100%}
p,ul,ol,blockquote,dl{margin:0 0 var(--sp-5);max-inline-size:var(--measure)}
h1,h2,h3,h4{margin:0 0 var(--sp-4);font-weight:400;line-height:1.15;text-wrap:balance}
h1{font-family:var(--serif);font-style:italic;font-size:clamp(1.75rem,1.4rem + 1.4vw,2.5rem)}
h2{font-family:var(--serif);font-style:italic;font-size:var(--t-title)}
h3{font-family:var(--serif);font-style:italic;font-size:1.1875rem}
h4{font-family:var(--sans);font-size:var(--t-small)}
a{color:inherit;text-decoration-thickness:1px;text-underline-offset:.18em;
  text-decoration-color:var(--hair-2);
  transition:color var(--out) var(--ease-out),text-decoration-color var(--out) var(--ease-out)}
a:hover,a:focus-visible{color:var(--ink-1);text-decoration-color:var(--ink-1);
  transition-duration:var(--in);transition-timing-function:var(--ease-in)}
hr{border:0;block-size:1px;background:var(--hair);margin:var(--band) 0;max-inline-size:none}
strong{font-weight:500}
:focus-visible{outline:2px solid var(--ink-1);outline-offset:3px}

/* THE one tracked-caps treatment on the site. Four roles share it because they are one rank:
   applying it to nav as well would collapse three ranks of hierarchy into one texture. */
.caps,.prices thead th,.buy legend,fieldset>legend,.disc>summary,.foot__col h2,
.btn,.link,.motion-toggle,.marker,.tag,.field>span,.crumb,
.label__no,.cell__no,.chosen dt,.spec dt,.cart thead th,.cart__qty label{
  font-family:var(--sans);font-weight:400;font-size:var(--t-micro);
  text-transform:uppercase;letter-spacing:var(--track-caps);color:var(--ink-3)}
.sr{position:absolute;inline-size:1px;block-size:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.skip{position:absolute;inset-inline-start:var(--sp-4);inset-block-start:-100%;z-index:10;
  padding:var(--sp-2) var(--sp-4);background:var(--ink-1);color:var(--wall);text-decoration:none}
.skip:focus{inset-block-start:var(--sp-3)}
.meta,small{font-family:var(--sans);font-size:var(--t-small);color:var(--ink-2);
  font-variant-numeric:tabular-nums}
.lede{font-family:var(--serif);font-size:var(--t-lede);color:var(--ink-2);max-inline-size:var(--measure)}

/* every number on the site is Jost with tabular figures */
.prices,.totals,.cart,.chosen,.order-no,.event time,.cell__meta,.label__meta,.site-cart{
  font-variant-numeric:tabular-nums}

/* ── the centre-out hairline: the one formal property all thirteen works share ─────────── */
.rule,.cell::after,.site-nav a::after,.link::after,.marker::after{
  content:"";display:block;block-size:1px;background:var(--ink-1);
  transform:scaleX(0);transform-origin:center;
  transition:transform var(--out) var(--ease-out)}
.cell:hover::after,.cell:focus-within::after,
.site-nav a:hover::after,.site-nav a:focus-visible::after,
.link:hover::after,.link:focus-visible::after{
  transform:scaleX(1);transition-duration:var(--in);transition-timing-function:var(--ease-in)}
.rule{max-inline-size:none;background:var(--hair);transform:scaleX(1)}

/* ── shell ────────────────────────────────────────────────────────────────────────────── */
.page,.site-header,.site-footer>*{
  inline-size:min(100% - 2*var(--gutter),var(--shell-wide));margin-inline:auto}
.page{padding-block:var(--sp-7) var(--band)}
/* Text sits on the 1180 measure and centres; the work is wider than the words, so plates,
   grids and section wrappers run the full 1560 shell. Enumerating the text children instead
   of using * left every block a module outside this file emits (the checkout form, the cart
   table) sitting 58px off the heading above it. */
/* No auto margin: a child that declares its own narrower measure (.prose at 34em) would
   otherwise centre itself inside the shell and sit 300px right of the heading above it.
   Text starts on the shell's left edge; only the things that mean to be centred say so. */
.page>*{max-inline-size:var(--shell)}
.page>:is(.open,.plate,.section,.grid,.works,.strip,.detail--wide){max-inline-size:none}
.section{margin-block-end:var(--band)}
.page>.section:last-child{margin-block-end:0}
.section--top{margin-block-start:var(--band)}
.centred--gap{margin-block-start:var(--sp-9)}
.wide{max-inline-size:none}

/* ── header ───────────────────────────────────────────────────────────────────────────── */
/* aspect ratio of public/brand/wordmark.svg and of the square mark. Change these WITH the file. */
:root{--wordmark-ratio:1460/100;--mark-ratio:1/1}
.site-header{display:flex;align-items:center;gap:var(--sp-5) var(--sp-6);flex-wrap:wrap;
  padding-block:var(--sp-5) var(--sp-4);border-block-end:1px solid var(--hair)}
.brand{flex:0 0 auto;display:block;text-decoration:none;padding-block:var(--sp-1)}
/* The wordmark is ONE swappable asset. It is drawn as a mask so a single file inherits the
   ink colour: replacing public/brand/wordmark.svg changes the lockup everywhere. A swap is the
   SVG plus one number, --wordmark-ratio (below the header rules), because the box has to match
   the new file's proportions or center/contain letterboxes it.
   Licence note: the client's own banner face is personal-use only, so it is not shipped. */
.brand__lockup{display:block;block-size:19px;inline-size:auto;aspect-ratio:var(--wordmark-ratio);background:var(--ink-1);
  -webkit-mask:url(/brand/wordmark.svg) no-repeat center/contain;
  mask:url(/brand/wordmark.svg) no-repeat center/contain;
  transition:background-color var(--out) var(--ease-out)}
.brand:hover .brand__lockup{transition-duration:var(--in)}
.site-nav{flex:1 1 auto;min-inline-size:0}
.site-nav ul{display:flex;gap:var(--sp-2) var(--sp-5);list-style:none;margin:0;padding:0;
  justify-content:flex-end;overflow-x:auto;scroll-snap-type:x proximity;scrollbar-width:none;
  min-inline-size:0;max-inline-size:none}
.site-nav ul::-webkit-scrollbar{display:none}
.site-nav li{flex:0 0 auto;scroll-snap-align:start}
.site-nav a{display:block;font-family:var(--sans);font-size:var(--t-small);color:var(--ink-2);
  text-decoration:none;white-space:nowrap;padding-block:var(--sp-2) var(--sp-1)}
.site-nav a:hover,.site-nav a:focus-visible{color:var(--ink-1)}
.site-nav a[aria-current="page"]{color:var(--ink-1)}
.site-nav a[aria-current="page"]::after{transform:scaleX(1)}
.site-cart{flex:0 0 auto;font-family:var(--sans);font-size:var(--t-small);color:var(--ink-1);
  text-decoration:none;white-space:nowrap;padding-block:var(--sp-2) var(--sp-1);
  border-block-end:1px solid var(--hair-2)}
.site-cart:hover,.site-cart:focus-visible{border-color:var(--ink-1)}
@media(max-width:899px){
  .site-header{gap:var(--sp-3)}
  .brand{order:1}
  .site-cart{order:2;margin-inline-start:auto}
  .site-nav{order:3;flex-basis:100%}
  /* wrap, do not scroll: overflow-x with scrollbar-width:none put Events and Contact,
     the two booking routes, past the right edge with nothing on screen saying so. */
  .site-nav ul{justify-content:flex-start;gap:var(--sp-3) var(--sp-4);padding-block-end:var(--sp-1);
    flex-wrap:wrap;overflow-x:visible}
  /* the 14.6:1 lockup squashed into a 390px flex row is an illegible smear: below 900px the
     compact S3 monogram carries the identity instead. Same swap discipline, second file. */
  .brand__lockup{block-size:22px;inline-size:auto;aspect-ratio:var(--mark-ratio);
    -webkit-mask-image:url(/brand/mark.svg);mask-image:url(/brand/mark.svg)}
}

/* ── footer ───────────────────────────────────────────────────────────────────────────── */
.site-footer{margin-block-start:auto;padding-block:var(--sp-8) var(--sp-6)}
.site-footer>*{border-block-start:1px solid var(--hair)}
.foot{display:grid;gap:var(--sp-7) var(--sp-6);padding-block-start:var(--sp-7);
  grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}
.foot__col h2{margin:0 0 var(--sp-4)}
.foot__col ul{list-style:none;margin:0;padding:0;display:grid;gap:var(--sp-2)}
.foot__col a{font-family:var(--sans);font-size:var(--t-small);color:var(--ink-2);text-decoration:none}
.foot__col a:hover,.foot__col a:focus-visible{color:var(--ink-1)}
/* the typeset wordmark lives here and only here: the header carries the real asset */
.wordmark-type{display:block;font-family:var(--sans);font-size:var(--t-micro);font-weight:400;
  text-transform:uppercase;letter-spacing:.3em;color:var(--ink-1);margin-block-end:var(--sp-4)}
.wordmark-type sup{font-family:var(--serif);font-size:.9rem;letter-spacing:0;
  vertical-align:.5em;margin-inline-start:.1em}
.foot__base{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--sp-3) var(--sp-6);
  margin-block-start:var(--sp-8);padding-block-start:var(--sp-4);
  font-family:var(--sans);font-size:var(--t-small);color:var(--ink-3)}
.foot__base p{margin:0;max-inline-size:none}
.foot__base a{color:var(--ink-2)}
.motion-toggle{margin-inline-start:auto;background:transparent;border:0;cursor:pointer;
  padding:var(--sp-1) 0;border-block-end:1px solid var(--hair-2)}
.motion-toggle:hover{color:var(--ink-1);border-color:var(--ink-1)}

/* ── the opening: statement, rank one and rank two, then the spine ────────────────────── */
.open{text-align:center;padding-block:var(--sp-8) 0;max-inline-size:none}
.open>h1{margin:0 0 var(--sp-7)}
.statement{font-family:var(--serif);font-size:var(--t-statement);line-height:1.22;
  color:var(--ink-1);text-wrap:balance;max-inline-size:22ch;margin:0 auto var(--sp-5)}
.statement--2{font-size:var(--t-lede);line-height:1.5;color:var(--ink-2);
  max-inline-size:46ch;margin:0 auto}
.spine{inline-size:1px;block-size:var(--sp-9);margin:var(--sp-6) auto var(--sp-8);
  background:linear-gradient(var(--ink-2),transparent)}

/* ── plates: an artwork on the wall, no frame, no edge, no plate border ───────────────── */
.plate{margin:0 0 var(--sp-6);max-inline-size:none}
.plate__frame{display:grid;place-items:center;background:var(--wall);margin:0;
  max-block-size:var(--plate-h)}
/* DESCENDANT combinator, not `>`: the <img> is a grandchild inside <picture> and a <video>
   is a direct child, so a child selector silently changes the height at the footage swap. */
.plate__frame :is(img,video){inline-size:auto;block-size:auto;
  max-inline-size:100%;max-block-size:var(--plate-h);object-fit:contain}
.plate__frame picture{display:contents}
.hero__loop{position:absolute;inset:0;inline-size:100%;block-size:100%;object-fit:cover;
  mix-blend-mode:screen;pointer-events:none}

/* wall label: centred on the work's own axis, stacking its meta lines on a phone */
.label{margin:var(--sp-5) auto 0;text-align:center;max-inline-size:44ch}
.label__no{display:block;margin-block-end:var(--sp-2)}
.label__title{display:block;font-family:var(--serif);font-style:italic;font-size:var(--t-title);
  color:var(--ink-1);margin:0 0 var(--sp-2);line-height:1.2}
.label__title a{text-decoration:none}
.label__meta{display:block;font-family:var(--sans);font-size:var(--t-mini);color:var(--ink-2);
  margin:0;max-inline-size:none}
.label__meta span+span::before{content:" · ";color:var(--ink-3)}
@media(max-width:639px){
  .label__meta span{display:block}
  .label__meta span+span::before{content:none}
}

/* ── section markers ──────────────────────────────────────────────────────────────────── */
.marker{display:block;margin:0 0 var(--sp-8);max-inline-size:none}
.marker.centred{text-align:center}
.marker::after{display:none}

/* ── selected works: two-up at full size, wall label under each ───────────────────────── */
.works{display:grid;gap:var(--band) var(--sp-8);grid-template-columns:1fr}
@media(min-width:900px){.works{grid-template-columns:repeat(2,minmax(0,1fr))}}
.works .plate__frame{max-block-size:min(62vh,640px)}
.works .plate__frame :is(img,video){max-block-size:min(62vh,640px)}

/* ── the plate index: equal square wells in a hard column count ───────────────────────── */
.grid{display:grid;list-style:none;margin:0;padding:0;
  column-gap:clamp(2rem,3.2vw,3.5rem);row-gap:calc(1.5 * clamp(2rem,3.2vw,3.5rem));
  grid-template-columns:1fr;max-inline-size:none}
@media(min-width:640px){.grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(min-width:900px){.grid{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media(min-width:1280px){.grid{grid-template-columns:repeat(4,minmax(0,1fr))}}
.grid--small{max-inline-size:60%;margin-inline:auto}
.grid--small .cell__title{font-size:1.0625rem}
.grid--small .cell__meta{font-size:var(--t-mini)}
@media(max-width:639px){.grid--small{max-inline-size:none}}
.cell{display:block;text-decoration:none;color:inherit;min-inline-size:0}
.cell:focus-visible{outline:none}
/* The well is square and the image is contained, so every caption in a row lands on one
   baseline whatever the work's aspect ratio. `object-fit:cover` is banned sitewide: every
   work is bilaterally symmetric and a crop destroys the only property all thirteen share. */
.cell__well{position:relative;aspect-ratio:1/1;background:var(--wall);display:grid;place-items:center;overflow:hidden}
.cell__well picture{display:contents}
/* The image is taken out of flow and pinned to the well, so its box IS the square and
   object-fit:contain can do its job. With block-size:100% on a grid item in an
   aspect-ratio box the height resolves to auto, the img lays out at its natural ratio,
   and every portrait work loses its bottom to overflow:hidden. */
.cell__well img{position:absolute;inset:0;inline-size:100%;block-size:100%;object-fit:contain}
.cell:focus-visible .cell__well{outline:2px solid var(--ink-1);outline-offset:4px}
.cell__cap{display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-3);
  padding-block:var(--sp-4) var(--sp-1)}
.cell__title{font-family:var(--serif);font-style:italic;font-size:var(--t-title);
  color:var(--ink-1);margin:0;line-height:1.2;font-weight:400}
.cell__no{letter-spacing:var(--track-caps-tight);white-space:nowrap}
.cell__meta{font-family:var(--sans);font-size:var(--t-small);color:var(--ink-2);
  margin:0 0 var(--sp-3);max-inline-size:none}
.footnote{font-family:var(--serif);font-size:var(--t-body);color:var(--ink-2);
  margin:var(--sp-8) auto 0;max-inline-size:var(--measure);text-align:center}

/* ── links that are not buttons ───────────────────────────────────────────────────────── */
.link{display:inline-block;text-decoration:none;color:var(--ink-1);
  border-block-end:1px solid var(--hair-2);padding-block-end:var(--sp-1)}
.link:hover,.link:focus-visible{border-color:transparent}
.link::after{margin-block-start:1px}
.centred{text-align:center;max-inline-size:none}

/* ── the one off-axis block on the homepage ───────────────────────────────────────────── */
.onwork{display:grid;gap:var(--sp-8);align-items:start;grid-template-columns:1fr}
@media(min-width:1000px){.onwork{grid-template-columns:minmax(0,var(--measure)) minmax(0,1fr)}}
.onwork p{color:var(--ink-2)}
.onwork .plate__frame,.onwork .plate__frame :is(img,video){max-block-size:min(52vh,520px)}

/* ── prints and gear strip: hairline-separated rows, no cards, no fills ───────────────── */
.strip{display:grid;gap:0;margin:0;max-inline-size:none;border-block-start:1px solid var(--hair)}
.strip>div{display:grid;gap:var(--sp-2) var(--sp-6);padding-block:var(--sp-5);
  border-block-end:1px solid var(--hair)}
@media(min-width:900px){.strip>div{grid-template-columns:14rem minmax(0,1fr) auto;align-items:baseline}}
.strip p{margin:0;color:var(--ink-2);max-inline-size:var(--measure)}
.strip .tag{justify-self:start}

/* ── two quiet links, side by side, no panel ──────────────────────────────────────────── */
.quiet{display:grid;gap:var(--sp-7) var(--sp-8);grid-template-columns:1fr}
@media(min-width:900px){.quiet{grid-template-columns:repeat(2,minmax(0,1fr))}}
.quiet p{color:var(--ink-2);margin:0 0 var(--sp-4)}

/* ── artwork detail ───────────────────────────────────────────────────────────────────── */
.crumb{margin:0 0 var(--sp-6);letter-spacing:var(--track-caps-tight);max-inline-size:none}
.crumb a{color:var(--ink-2);text-decoration:none}
.crumb a:hover,.crumb a:focus-visible{color:var(--ink-1)}
.detail{display:grid;gap:var(--sp-8);align-items:start;grid-template-columns:1fr;
  margin:var(--band) auto 0;max-inline-size:var(--shell)}
@media(min-width:1000px){.detail{grid-template-columns:minmax(0,1fr) minmax(360px,26rem)}}
/* nothing to say on the left (no description on file) means the buy decision is the page:
   it centres on the work's own axis rather than hanging off the left margin. */
.detail--single{max-inline-size:34rem;grid-template-columns:minmax(0,1fr)}
.detail h2{margin-block-end:var(--sp-4)}
.work__desc{color:var(--ink-2);max-inline-size:var(--measure)}
.work__desc p{color:inherit}

/* the price schedule. All prices visible at once, at 390px as well as at 1440px. */
.prices{inline-size:100%;border-collapse:collapse;margin:0 0 var(--sp-5);
  font-family:var(--sans)}
.prices caption{text-align:start}
.prices thead th{letter-spacing:var(--track-caps-tight);text-align:end;
  padding:0 var(--sp-2) var(--sp-3);border-block-end:1px solid var(--hair);white-space:nowrap}
.prices thead th:first-child{text-align:start}
.prices tbody th{text-align:start;font-weight:400;font-size:var(--t-small);color:var(--ink-1);
  padding:var(--sp-4) var(--sp-2);white-space:nowrap;vertical-align:middle}
.prices tbody th span{display:block;font-size:var(--t-micro);color:var(--ink-3);
  text-transform:lowercase;letter-spacing:0}
.prices td{padding:0;vertical-align:middle}
.prices td label{display:block;padding:var(--sp-4) var(--sp-2);text-align:end;
  font-size:var(--t-small);color:var(--ink-2);cursor:pointer;
  transition:color var(--out) var(--ease-out),background-color var(--out) var(--ease-out)}
.prices td label:hover{color:var(--ink-1);transition-duration:var(--in);transition-timing-function:var(--ease-in)}
.prices input:checked+label{background:var(--sale);color:var(--sale-ink)}
/* the ring has to read on cream AND on black, so it is drawn as a paired shadow inside the
   cell rather than as an outline that disappears the moment it lands on --sale */
.prices input:focus-visible+label{outline:none;
  box-shadow:inset 0 0 0 2px var(--wall),inset 0 0 0 4px var(--ink-1)}
.prices input:disabled+label{color:var(--ink-3);text-decoration:line-through;cursor:not-allowed;
  box-shadow:inset 0 0 0 1px var(--hair-2)}
/* buyBox() checks the first variant even when nothing is sellable, so checked+disabled is
   reachable: --ink-3 on the cream fill is 2.78:1. */
.prices input:checked:disabled+label{color:var(--sale-ink);opacity:.55}
/* The fill IS the state, and a background colour is the first thing forced-colors throws away.
   The inset ring survives it; the media query then restores a real selected colour pair. */
.prices input:checked+label{box-shadow:inset 0 0 0 2px currentColor}
@media(forced-colors:active){
  .prices input:checked+label{forced-color-adjust:none;background:Highlight;color:HighlightText}
  .prices input:checked:disabled+label{background:Canvas;color:GrayText;opacity:1}
}
.prices tbody tr+tr th,.prices tbody tr+tr td{border-block-start:1px solid var(--hair)}
.prices__note{font-family:var(--sans);font-size:var(--t-mini);color:var(--ink-3);
  margin:0 0 var(--sp-5)}
.chosen{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;
  gap:var(--sp-3);margin:0 0 var(--sp-5);padding-block-end:var(--sp-3);
  border-block-end:1px solid var(--hair);font-family:var(--sans)}
.chosen dt{margin:0}
.chosen dd{margin:0;font-size:var(--t-small);color:var(--ink-1)}
.chosen output{font-variant-numeric:tabular-nums}
.buy{margin:0}
.buy fieldset{border:0;padding:0;margin:0 0 var(--sp-5);min-inline-size:0}
.buy legend{padding:0;margin-block-end:var(--sp-3)}
.buy__row{display:flex;flex-wrap:wrap;gap:var(--sp-4);align-items:end}
.buy__row .field{margin:0;flex:0 0 5rem}
.buy__note{font-family:var(--sans);font-size:var(--t-mini);color:var(--ink-3);
  margin:var(--sp-4) 0 0;max-inline-size:var(--measure)}

/* what makes a framed print feel like an object: dt in the caps voice, dd in the reading one */
.spec{display:grid;grid-template-columns:auto 1fr;gap:var(--sp-3) var(--sp-5);
  margin:var(--sp-7) 0;border-block-start:1px solid var(--hair);padding-block-start:var(--sp-5)}
.spec dt{padding-block-start:.25em}
.spec dd{margin:0;font-family:var(--serif);font-size:.9375rem;color:var(--ink-2)}

/* disclosures: a hairline top border, nothing else. No fill, no box. */
.disc{border-block-start:1px solid var(--hair);padding-block:var(--sp-4)}
.disc>summary{cursor:pointer;list-style:none;display:flex;justify-content:space-between;
  gap:var(--sp-4);align-items:baseline;color:var(--ink-2)}
.disc>summary::-webkit-details-marker{display:none}
.disc>summary::after{content:"+";font-family:var(--sans);color:var(--ink-3)}
.disc[open]>summary::after{content:"\2013"}
.disc>summary:hover{color:var(--ink-1)}
.disc p{margin:var(--sp-4) 0 0;color:var(--ink-2);font-size:.9375rem}

/* ── buttons: a caps label, a hairline, nothing else ──────────────────────────────────── */
.btn{display:inline-flex;align-items:center;justify-content:center;
  padding:var(--sp-3) var(--sp-5);background:transparent;color:var(--ink-1);
  border:1px solid var(--hair-2);text-decoration:none;cursor:pointer;
  transition:border-color var(--out) var(--ease-out),color var(--out) var(--ease-out)}
.btn:hover,.btn:focus-visible{border-color:var(--ink-1);color:var(--ink-1);
  transition-duration:var(--in);transition-timing-function:var(--ease-in)}
.btn[disabled],.btn[aria-disabled="true"]{color:var(--ink-3);border-color:var(--hair);cursor:not-allowed}
.btn--small{padding:var(--sp-2) var(--sp-3)}
.cta{display:flex;flex-wrap:wrap;gap:var(--sp-4);margin-block:var(--sp-6) var(--band)}
/* A button is 42px tall and a paragraph's line box is 27px, so two buttons in a <p> (which is
   how shop.js writes its empty states) overlap the moment they wrap. Any paragraph that holds
   one becomes a wrapping row instead. */
p:has(>.btn){display:flex;flex-wrap:wrap;gap:var(--sp-4);align-items:center;
  margin-block-end:var(--sp-6);max-inline-size:none}

/* ── forms ────────────────────────────────────────────────────────────────────────────── */
.form{max-inline-size:40rem}
.field{display:block;margin:0 0 var(--sp-5)}
.field>span{display:block;margin-block-end:var(--sp-2)}
input:not([type=radio]):not([type=checkbox]),select,textarea{
  font:400 var(--t-small)/1.5 var(--sans);color:var(--ink-1);background:transparent;
  border:0;border-block-end:1px solid var(--hair-2);border-radius:0;
  padding:var(--sp-2) 0;inline-size:100%;max-inline-size:100%}
input:focus-visible,select:focus-visible,textarea:focus-visible{outline:none;
  border-color:var(--ink-1);box-shadow:0 1px 0 0 var(--ink-1)}
textarea{min-block-size:8rem;resize:vertical}
input[type=checkbox],input[type=radio]{accent-color:var(--ink-1);inline-size:1rem;block-size:1rem;
  margin:0 var(--sp-2) 0 0;vertical-align:-.1em}
fieldset{border:0;border-block-start:1px solid var(--hair);padding:var(--sp-5) 0 0;
  margin:0 0 var(--sp-7);min-inline-size:0}
fieldset>legend{padding:0}
.radios,.pills{display:flex;flex-wrap:wrap;gap:var(--sp-3) var(--sp-5);margin:0 0 var(--sp-5)}
.radios label,.pills label,.check{font-family:var(--sans);font-size:var(--t-small);color:var(--ink-2)}
.radios label,.pills label{display:inline-flex;align-items:center;gap:var(--sp-1)}
.pills input:checked+.pill__label{color:var(--ink-1)}
/* /checkout/ renders the same picker as LINKS, so the page carries exactly one form. Same list,
   same type, same gap: only the control differs, and .pill--on marks the level in force. */
ul.pills{list-style:none;padding:0}
a.pill{font-family:var(--sans);font-size:var(--t-small);color:var(--ink-2);text-decoration:none;
  display:inline-flex;align-items:center;gap:var(--sp-1);border-block-end:1px solid transparent}
a.pill:hover,a.pill:focus-visible{border-block-end-color:currentColor}
a.pill--on{color:var(--ink-1);border-block-end-color:currentColor}
.pill__price{color:var(--ink-3);font-variant-numeric:tabular-nums}
.pill__why{color:var(--ink-3);font-size:var(--t-mini)}
.shipto{margin:0 0 var(--sp-6)}
.shipto .field{max-inline-size:8rem}
/* A read-only field is the destination the review was already priced for, not a text box: it
   must not invite an edit the quoted total would not follow. Colour only, no new background,
   so the contrast pairs stay the ones test/contrast.test.mjs checks. */
input[readonly]{color:var(--ink-2);border-block-end-style:dashed;cursor:default}
.check{display:flex;gap:var(--sp-2);align-items:flex-start;margin:0 0 var(--sp-4)}
.check input{flex:0 0 auto;margin-block-start:.2em}
.form__row{display:grid;gap:var(--sp-4) var(--sp-5);grid-template-columns:repeat(auto-fit,minmax(11rem,1fr))}
.form__actions{display:flex;flex-wrap:wrap;gap:var(--sp-4);align-items:center}
.form__actions small{color:var(--ink-3)}
.hp{position:absolute;inset-inline-start:-9999px;inline-size:1px;block-size:1px;overflow:hidden}
.error{color:var(--err);font-family:var(--sans);font-size:var(--t-small)}
.ok{color:var(--ok);font-family:var(--sans);font-size:var(--t-small)}
/* the newsletter is one line, one bare underlined input, one caps submit. No box. */
.news{display:flex;flex-wrap:wrap;align-items:end;gap:var(--sp-4) var(--sp-5);max-inline-size:40rem}
.news .field{flex:1 1 16rem;margin:0}

/* ── prose pages ──────────────────────────────────────────────────────────────────────── */
.prose{max-inline-size:var(--measure);color:var(--ink-2)}
.prose h2{color:var(--ink-1);margin-block-start:var(--sp-8)}
.prose h3{color:var(--ink-1);margin-block-start:var(--sp-7)}
.prose>:first-child{margin-block-start:0}
.prose li{margin-block-end:var(--sp-2)}
.prose blockquote{border-inline-start:1px solid var(--hair-2);padding-inline-start:var(--sp-4);
  margin-inline-start:0;font-style:italic}
.prose figure{margin:var(--sp-7) 0;background:var(--wall)}
.prose img{inline-size:auto;block-size:auto;margin-inline:auto}
.prose a{color:var(--ink-1)}
.def{font-family:var(--serif);font-size:var(--t-statement);line-height:1.25;color:var(--ink-1);
  text-wrap:balance;max-inline-size:24ch;margin:0 0 var(--sp-8)}
.steps{counter-reset:s;list-style:none;padding:0;display:grid;gap:var(--sp-4);
  max-inline-size:var(--measure)}
.steps li{counter-increment:s;display:grid;grid-template-columns:2.5rem 1fr;gap:var(--sp-4)}
.steps li::before{content:counter(s,decimal-leading-zero);font-family:var(--sans);
  font-size:var(--t-micro);color:var(--ink-3);letter-spacing:var(--track-caps-tight);
  padding-block-start:.5em}
.tag{display:inline-block;color:var(--ink-3);border-block-end:1px solid var(--hair-2);
  white-space:nowrap}

.faq details{border-block-end:1px solid var(--hair);padding-block:var(--sp-4)}
.faq summary{cursor:pointer;list-style:none;display:flex;justify-content:space-between;
  gap:var(--sp-4);align-items:baseline;font-family:var(--serif);font-style:italic;
  font-size:var(--t-title);color:var(--ink-1)}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";font-family:var(--sans);font-size:var(--t-small);color:var(--ink-3)}
.faq details[open] summary::after{content:"\2013"}
.faq details>div{padding-block:var(--sp-4) var(--sp-2);color:var(--ink-2);max-inline-size:var(--measure)}

.events{list-style:none;padding:0;margin:0 0 var(--band);display:grid;gap:0;
  border-block-start:1px solid var(--hair);max-inline-size:none}
.event{display:grid;gap:var(--sp-2) var(--sp-6);padding-block:var(--sp-5);
  border-block-end:1px solid var(--hair)}
@media(min-width:900px){.event{grid-template-columns:14rem minmax(0,1fr);align-items:baseline}}
.event time{font-family:var(--sans);font-size:var(--t-small);color:var(--ink-2)}
.event h3{margin:0}
.event p{margin:0;color:var(--ink-2);font-size:.9375rem}

/* ── notices: a hairline rule, and the one raised surface on the site ─────────────────── */
.notice{background:var(--wall-lift);border-block-start:1px solid var(--hair-2);
  padding:var(--sp-4) var(--sp-5);margin:0 0 var(--sp-6);max-inline-size:var(--measure);
  font-family:var(--sans);font-size:var(--t-small);color:var(--ink-2)}
.notice p{margin:0;max-inline-size:none}
.notice--fixed{position:sticky;inset-block-start:0;z-index:5}
.notice strong{color:var(--ink-1)}

/* ── cart / checkout / order ──────────────────────────────────────────────────────────── */
.cart{inline-size:100%;border-collapse:collapse;margin:0 0 var(--sp-7);font-family:var(--sans);
  font-size:var(--t-small);max-inline-size:none}
.cart th,.cart td{text-align:start;padding:var(--sp-4) var(--sp-2);
  border-block-end:1px solid var(--hair);vertical-align:top}
.cart thead th{letter-spacing:var(--track-caps-tight);font-weight:400}
.cart td.num,.cart th.num{text-align:end;white-space:nowrap}
.cart strong{font-family:var(--serif);font-style:italic;font-size:var(--t-title);font-weight:400;
  color:var(--ink-1)}
.cart small{color:var(--ink-3)}
.cart form{display:inline-flex;gap:var(--sp-3);align-items:center}
.cart input[type=number]{inline-size:3.5rem}
.totals{max-inline-size:24rem;margin-inline-start:auto;margin-block-end:var(--sp-7);
  font-family:var(--sans);font-size:var(--t-small);color:var(--ink-2)}
.totals div{display:flex;justify-content:space-between;gap:var(--sp-5);padding-block:var(--sp-2)}
.totals .grand{color:var(--ink-1);border-block-start:1px solid var(--hair-2);
  margin-block-start:var(--sp-2);padding-block-start:var(--sp-3)}
.checkout{max-inline-size:40rem}
.waiver__text{max-block-size:18rem;overflow:auto;padding:var(--sp-4) var(--sp-5);
  background:var(--wall-lift);border-block-start:1px solid var(--hair-2);
  margin:0 0 var(--sp-5);font-size:.9375rem;color:var(--ink-2)}
.review{list-style:none;padding:0;margin:0 0 var(--sp-5);font-family:var(--sans);font-size:var(--t-small)}
.review li{display:flex;justify-content:space-between;gap:var(--sp-5);padding-block:var(--sp-2);
  border-block-end:1px solid var(--hair);color:var(--ink-2)}
.order-no{font-family:var(--sans);font-size:var(--t-title);letter-spacing:.12em;color:var(--ink-1)}

/* ── video: the designed thin state until footage lands ───────────────────────────────── */
.player{max-inline-size:900px;aspect-ratio:16/9;background:var(--wall);margin:0 0 var(--sp-6)}
.player video{inline-size:100%;block-size:100%;object-fit:contain}

/* ── image protection, scoped to the artwork element ONLY (§6.7). A document-wide handler
   breaks copying the phone number and the order total, which annoys exactly the people who
   were going to buy something. ── */
[data-protect]{position:relative;user-select:none;-webkit-user-select:none;-webkit-user-drag:none;-webkit-touch-callout:none}
[data-protect] img{-webkit-user-drag:none;user-select:none;pointer-events:none}
[data-protect]::after{content:"";position:absolute;inset:0;background:transparent}
@media print{
  [data-protect] :is(img,picture,video){display:none!important}
  [data-protect]::before{content:"BreakStream Arts, breakstreamarts.com";color:#000;
    font-family:var(--sans);padding:2rem;display:block}
  .site-nav,.site-cart,.site-footer,.buy,.cta,.motion-toggle,.skip{display:none}
  body{background:#fff;color:#000}
}

/* ── motion. Two motions exist on this site: the centre-out hairline and an ink transition.
   Banned: brightness() or opacity on any artwork at any time, parallax, scroll reveals,
   lightboxes, autoplay, entrance animations. ── */
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{transition-duration:.01ms!important;animation-duration:.01ms!important;
    animation-iteration-count:1!important;scroll-behavior:auto!important}
  .hero__loop{display:none}
}
:root[data-motion="off"] .hero__loop{display:none}
:root[data-motion="off"] *,:root[data-motion="off"] *::before,:root[data-motion="off"] *::after{
  transition-duration:.01ms!important;animation-duration:.01ms!important}

/* ── mobile ───────────────────────────────────────────────────────────────────────────── */
@media(max-width:639px){
  .page{padding-block-start:var(--sp-5)}
  .open{padding-block-start:var(--sp-7)}
  /* 19ch at 28px forces seven lines in a 350px column; 22ch is the floor that reads */
  .statement{max-inline-size:22ch}
  .spine{block-size:var(--sp-9);margin-block:var(--sp-6) var(--sp-8)}
  .cart thead{display:none}
  .cart td{display:block;padding-inline:0;border:0}
  .cart tr{display:block;border-block-end:1px solid var(--hair);padding-block:var(--sp-3)}
  .cart td.num{text-align:start}
  .totals{margin-inline-start:0}
  /* the price schedule STAYS a table at 390px: nothing here drops below 13px */
  .prices tbody th{font-size:var(--t-small);padding-inline:0 var(--sp-2)}
  .prices td label{font-size:var(--t-small)}
  .prices thead th{font-size:var(--t-micro);letter-spacing:.06em}
}

/* ── /cart/, /checkout/ and /order/complete/ are rendered by shop.js and orders.js, which own
   their own class names. The design is one design, so those names are dressed here rather than
   by reaching into a module this file does not own. Same tokens, same rules, no new ideas. ── */
.tile{display:block;min-inline-size:0}
.tile__link{display:block;text-decoration:none;color:inherit}
.tile__frame{position:relative;aspect-ratio:1/1;background:var(--wall);display:grid;place-items:center;overflow:hidden}
.tile__frame picture{display:contents}
.tile__frame img{position:absolute;inset:0;inline-size:100%;block-size:100%;object-fit:contain}
.tile__link:focus-visible{outline:none}
.tile__link:focus-visible .tile__frame{outline:2px solid var(--ink-1);outline-offset:4px}
.tile__title{font-family:var(--serif);font-style:italic;font-weight:400;font-size:var(--t-title);
  color:var(--ink-1);margin:var(--sp-4) 0 var(--sp-1);line-height:1.2}
.tile__price{font-family:var(--sans);font-size:var(--t-small);color:var(--ink-2);margin:0;
  font-variant-numeric:tabular-nums}
.tile__link::after{content:"";display:block;block-size:1px;background:var(--ink-1);
  margin-block-start:var(--sp-3);transform:scaleX(0);transform-origin:center;
  transition:transform var(--out) var(--ease-out)}
.tile__link:hover::after,.tile__link:focus-visible::after{transform:scaleX(1);
  transition-duration:var(--in);transition-timing-function:var(--ease-in)}

.cart tfoot th{text-align:end;font-weight:400;color:var(--ink-2)}
.cart tfoot td{text-align:end;white-space:nowrap;color:var(--ink-1)}
.cart__unit,.cart__line{text-align:end;white-space:nowrap;font-variant-numeric:tabular-nums}
.cart__variant{color:var(--ink-3)}
.cart__item strong{display:block;margin-block-end:var(--sp-1)}
.cart__qty,.cart__remove{display:inline-flex;gap:var(--sp-3);align-items:center;margin:0}
.cart__qty label{display:inline-flex;gap:var(--sp-2);align-items:center;
  letter-spacing:var(--track-caps-tight)}
.cart__qty input[type=number]{inline-size:3.5rem}
.cart tfoot .cart__total th,.cart tfoot .cart__total td{color:var(--ink-1);
  border-block-start:1px solid var(--hair-2)}
.cart__actions{display:flex;flex-wrap:wrap;gap:var(--sp-4);margin-block:var(--sp-7)}
.cart__note,.checkout__note,.field__note{font-family:var(--sans);font-size:var(--t-mini);
  color:var(--ink-3);max-inline-size:var(--measure)}
.checkout__edit{font-family:var(--sans);font-size:var(--t-small)}
.form__error{color:var(--err);font-family:var(--sans);font-size:var(--t-small)}
.form__error[hidden]{display:none}
.btn--ghost{border-color:var(--hair-2)}
.banner{font-family:var(--sans);font-size:var(--t-small);color:var(--ink-2);
  background:var(--wall-lift);border-block-start:1px solid var(--hair-2);
  padding:var(--sp-4) var(--sp-5);margin:0 0 var(--sp-6);max-inline-size:var(--measure)}
.tag--fire{color:var(--ink-1)}
.waiver{margin-block:var(--sp-7)}
#order-status{font-family:var(--sans);font-size:var(--t-small);color:var(--ink-2)}
.order-no strong{font-family:var(--sans);font-weight:400;letter-spacing:.12em;color:var(--ink-1)}
@media(max-width:639px){
  .cart tfoot th{text-align:start}
  .cart__qty,.cart__remove{margin-block-start:var(--sp-2)}
}
