/* ==========================================================================
   House of Kalamkari
   Museum palette — cream paper, indigo, madder, ochre.
   Everything is driven by the custom properties in :root.
   ========================================================================== */

:root {
  /* --- colour ------------------------------------------------------------ */
  --paper:      #F7F2E7;
  --paper-warm: #F1E9D9;
  --paper-deep: #E7DCC5;
  --ink:        #1A1613;
  --ink-soft:   #4A423A;
  --ink-faint:  #8C8172;
  --indigo:     #1F2E4A;
  --indigo-lt:  #33456A;
  --madder:     #A6382A;
  --ochre:      #BE8A3C;
  --line:       rgba(26,22,19,.14);
  --line-soft:  rgba(26,22,19,.07);

  --accent:     var(--madder);

  /* --- type -------------------------------------------------------------- */
  --serif: "Cormorant Garamond", "Iowan Old Style", Palatino, Georgia, serif;
  --sans:  "Jost", ui-sans-serif, -apple-system, "Segoe UI", sans-serif;

  --step--1: clamp(.78rem, .74rem + .18vw, .875rem);
  --step-0:  clamp(.95rem, .9rem + .25vw, 1.06rem);
  --step-1:  clamp(1.3rem, 1.1rem + .9vw, 1.9rem);
  --step-2:  clamp(1.8rem, 1.35rem + 2.1vw, 3.2rem);
  --step-3:  clamp(2.4rem, 1.5rem + 4.2vw, 5.4rem);
  --step-4:  clamp(3rem, 1.4rem + 7.4vw, 9rem);

  /* --- space ------------------------------------------------------------- */
  --gut: clamp(1.15rem, .6rem + 2.6vw, 4.5rem);
  --sec: clamp(4.5rem, 2.5rem + 9vw, 11rem);
  --maxw: 1440px;

  /* --- motion ------------------------------------------------------------ */
  --ease: cubic-bezier(.22, 1, .36, 1);
  --ease-soft: cubic-bezier(.4, 0, .2, 1);
  --dur: .9s;
}

/* ==========================================================================
   Reset & base
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--step-0);
  font-weight: 350;
  line-height: 1.65;
  letter-spacing: .005em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* the faintest woven-cloth tooth over the whole page */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: .5;
  mix-blend-mode: multiply;
  background-image:
    repeating-linear-gradient(0deg,  rgba(26,22,19,.035) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(90deg, rgba(26,22,19,.028) 0 1px, transparent 1px 3px);
}

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

h1, h2, h3, h4 {
  font-family: var(--serif);
  font-weight: 300;
  line-height: 1.04;
  letter-spacing: -.012em;
  text-wrap: balance;
}

p { text-wrap: pretty; }

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

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

::selection { background: var(--indigo); color: var(--paper); }

:focus-visible {
  outline: 2px solid var(--madder);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 10001;
  background: var(--indigo); color: var(--paper);
  padding: .8rem 1.4rem; font-size: var(--step--1);
}
.skip-link:focus { left: .5rem; top: .5rem; }


/* ==========================================================================
   Layout helpers
   ========================================================================== */

.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gut); }
.wrap--narrow { max-width: 74ch; }
.wrap--mid { max-width: 1100px; }

.section { padding-block: var(--sec); }
.section--tight { padding-block: calc(var(--sec) * .6); }

/* small letterspaced label above headings */
.eyebrow {
  font-size: var(--step--1);
  letter-spacing: .34em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--ink-faint);
  display: flex;
  align-items: center;
  gap: .9rem;
}
.eyebrow::before {
  content: "";
  width: clamp(1.5rem, 4vw, 3.5rem);
  height: 1px;
  background: var(--ink-faint);
  opacity: .6;
}
.eyebrow--center { justify-content: center; }
.eyebrow--center::after {
  content: "";
  width: clamp(1.5rem, 4vw, 3.5rem);
  height: 1px;
  background: var(--ink-faint);
  opacity: .6;
}

.display  { font-size: var(--step-3); }
.title    { font-size: var(--step-2); }
.subtitle { font-size: var(--step-1); font-family: var(--serif); font-weight: 300; }

.lede {
  font-size: clamp(1.02rem, .95rem + .45vw, 1.28rem);
  line-height: 1.72;
  color: var(--ink-soft);
  font-weight: 300;
}

/* A highlighted line set into a run of body copy \u2014 the turn in the argument,
   held apart from the paragraphs on either side by a madder rule. */
.pull {
  margin: 2.6rem 0;
  padding: .2rem 0 .2rem 1.4rem;
  border-left: 2px solid var(--madder);
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(1.2rem, 1rem + .9vw, 1.72rem);
  line-height: 1.42;
  color: var(--ink);
}
.pull strong { font-weight: 400; color: var(--madder); }
@media (min-width: 720px) { .pull { margin: 3.2rem 0; padding-left: 2rem; } }

/* Anchor targets sit below the fixed header when jumped to, not under it. */
:target, [id]:target { scroll-margin-top: clamp(4.5rem, 9vw, 6.5rem); }

/* No long-press "Save Image" sheet on a phone, no drag to the desktop, no
   accidental text selection over a photograph. A deterrent only - see
   protectImages() in main.js. */
.card__media img, .lb__media img, .frame img, .band__media img, .hero img,
.card__media video, .lb__media video {
  -webkit-touch-callout: none;
  -webkit-user-drag: none;
  user-select: none;
  pointer-events: none;
}

.measure { max-width: 62ch; }
.center { text-align: center; }
.center .eyebrow { justify-content: center; }
.center .eyebrow::after {
  content: ""; width: clamp(1.5rem, 4vw, 3.5rem); height: 1px;
  background: var(--ink-faint); opacity: .6;
}

/* ==========================================================================
   Ornament
   ========================================================================== */

.rule {
  display: flex; align-items: center; justify-content: center; gap: 1.1rem;
  color: var(--ink-faint);
}
.rule::before, .rule::after {
  content: ""; height: 1px; flex: 1; max-width: 22vw;
  background: linear-gradient(90deg, transparent, var(--line), transparent);
}
.rule svg { width: 26px; height: 26px; opacity: .55; }

/* a phrase lifted out of running text — madder, and one step up in weight,
   which reads as emphasis without the clunk of real bold in a light face */
.accent {
  color: var(--madder);
  font-weight: 400;
}

/* ==========================================================================
   Buttons
   ========================================================================== */

.btn {
  --btn-fg: var(--paper);
  --btn-bg: var(--indigo);
  position: relative;
  display: inline-flex; align-items: center; gap: .7rem;
  padding: .95em 1.9em;
  font-size: var(--step--1);
  letter-spacing: .18em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--btn-fg);
  background: var(--btn-bg);
  border: 1px solid var(--btn-bg);
  transition: background-color .4s var(--ease-soft),
              border-color .4s var(--ease-soft),
              transform .4s var(--ease),
              box-shadow .4s var(--ease);
}
/* The text colour NEVER changes on hover, and nothing slides across the
   label. An invert (dark→light while the text goes light→dark) passes through
   a moment where text and background are both mid-tone and the label is
   invisible. Only the background shifts, so contrast holds throughout. */
.btn:hover, .btn:focus-visible {
  background: var(--btn-bg-hover, var(--indigo-lt));
  border-color: var(--btn-bg-hover, var(--indigo-lt));
  transform: translateY(-2px);
  box-shadow: 0 12px 24px -14px rgba(26, 22, 19, .55);
}
.btn:active { transform: translateY(0); box-shadow: none; }


.btn--light {
  --btn-fg: var(--indigo);
  --btn-bg: var(--paper);
  --btn-bg-hover: var(--paper-deep);
}

/* underline-on-hover text link */
.link {
  position: relative;
  font-size: var(--step--1);
  letter-spacing: .16em;
  text-transform: uppercase;
  padding-bottom: .3em;
}
.link::after {
  content: "";
  position: absolute; left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0); transform-origin: right;
  transition: transform .5s var(--ease);
}
.link:hover::after { transform: scaleX(1); transform-origin: left; }

/* ==========================================================================
   Header
   ========================================================================== */

.header {
  position: fixed; inset: 0 0 auto; z-index: 900;
  display: flex; align-items: center;
  padding-block: clamp(.8rem, 1.6vw, 1.4rem);
  transition: transform .55s var(--ease), background-color .5s, box-shadow .5s, color .5s;
}
.header::before {
  content: "";
  position: absolute; inset: 0;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(14px) saturate(1.1);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  border-bottom: 1px solid var(--line-soft);
  opacity: 0;
  transition: opacity .5s var(--ease-soft);
}
.header.is-stuck::before { opacity: 1; }
.header.is-hidden { transform: translateY(-105%); }

/* over a dark hero, before scrolling */
.header.is-over-hero { color: var(--paper); }

.header__inner {
  position: relative;
  width: 100%; max-width: var(--maxw); margin-inline: auto;
  padding-inline: var(--gut);
  display: flex; align-items: center; justify-content: space-between; gap: 2rem;
}

.lockup { display: flex; align-items: center; gap: .8rem; }
.lockup svg { width: clamp(30px, 3.4vw, 42px); height: auto; }
.lockup__text { line-height: 1; }
.lockup__top {
  display: block;
  font-size: clamp(.48rem, .45rem + .12vw, .58rem);
  letter-spacing: .3em; text-transform: uppercase;
  opacity: .7; margin-bottom: .34em;
  white-space: nowrap;
}
.lockup__name {
  display: block;
  font-family: var(--serif);
  font-size: clamp(1.02rem, .85rem + .7vw, 1.5rem);
  letter-spacing: .16em;
}

.nav { display: flex; align-items: center; gap: clamp(1.1rem, 2.2vw, 2.4rem); }
.nav a {
  font-size: var(--step--1);
  letter-spacing: .15em;
  text-transform: uppercase;
  position: relative;
  padding-block: .4em;
  white-space: nowrap;
}
.nav a::after {
  content: "";
  position: absolute; left: 0; bottom: 0; width: 100%; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: right;
  transition: transform .45s var(--ease);
}
.nav a:hover::after, .nav a[aria-current="page"]::after { transform: scaleX(1); transform-origin: left; }
.nav a[aria-current="page"] { color: var(--madder); }
.header.is-over-hero .nav a[aria-current="page"] { color: var(--paper); }

/* Enquire sits OUTSIDE .nav so it is never hidden with the menu links. */
.header__actions {
  display: flex;
  align-items: center;
  gap: clamp(.4rem, 1.2vw, .9rem);
}
.nav__cta { white-space: nowrap; }

@media (max-width: 560px) {
  .nav__cta { padding: .8em 1.1em; letter-spacing: .12em; font-size: .68rem; }
}

/* ==========================================================================
   Header search
   Collapsed it is just an icon; expanded, the field grows out of it to the
   left so nothing else in the header shifts.
   ========================================================================== */

.hsearch { position: relative; display: flex; align-items: center; }

.hsearch__toggle {
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  color: inherit;
  transition: background .35s var(--ease-soft), color .35s;
}
.hsearch__toggle:hover { background: var(--line-soft); }
.hsearch__toggle svg { width: 19px; height: 19px; }

.hsearch__form {
  display: flex; align-items: center;
  width: 0;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
  transition: width .45s var(--ease), opacity .3s var(--ease-soft);
}
.hsearch.is-open .hsearch__form {
  width: clamp(190px, 26vw, 290px);
  opacity: 1;
  pointer-events: auto;
}

.hsearch__input {
  flex: 1; min-width: 0;
  font: inherit;
  font-size: var(--step--1);
  color: var(--ink);
  background: var(--paper-warm);
  border: 1px solid var(--line);
  border-radius: 100px;
  padding: .62em 2.3em .62em 1.1em;
  transition: border-color .3s, background .3s;
}
.hsearch__input::placeholder { color: var(--ink-faint); }
.hsearch__input:focus { outline: none; border-color: var(--ink-faint); background: var(--paper); }
/* the browser's own clear cross would sit on top of ours */
.hsearch__input::-webkit-search-cancel-button { display: none; }

.hsearch__clear {
  position: absolute; right: 46px;
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  color: var(--ink-faint);
  transition: color .3s, background .3s;
}
.hsearch__clear:hover { color: var(--ink); background: var(--line-soft); }
.hsearch__clear svg { width: 13px; height: 13px; }
.hsearch:not(.is-open) .hsearch__clear { display: none; }

/* over the hero the header is light-on-dark, so the field must invert */
.header.is-over-hero .hsearch__input {
  color: var(--paper);
  background: rgba(247, 242, 231, .12);
  border-color: rgba(247, 242, 231, .28);
}
.header.is-over-hero .hsearch__input::placeholder { color: rgba(247, 242, 231, .6); }
.header.is-over-hero .hsearch__input:focus { background: rgba(247, 242, 231, .2); }
.header.is-over-hero .hsearch__toggle:hover,
.header.is-over-hero .hsearch__clear:hover { background: rgba(247, 242, 231, .14); }
.header.is-over-hero .hsearch__clear { color: rgba(247, 242, 231, .7); }

/* on a phone the field takes the room it needs and the menu button waits */
@media (max-width: 620px) {
  .hsearch.is-open .hsearch__form { width: min(58vw, 240px); }
  .hsearch.is-open ~ .nav__cta { display: none; }
}

/* --- the line above the grid reporting what matched --------------------- */
.searchline {
  font-size: var(--step--1);
  color: var(--ink-soft);
  margin-bottom: 1.6rem;
  display: flex; align-items: center; gap: .7rem; flex-wrap: wrap;
}
/* `display:flex` above beats the browser's own [hidden]{display:none}, so the
   attribute needs an explicit rule or the element can never hide. */
.searchline[hidden] { display: none; }
.searchline__q { color: var(--ink); font-weight: 400; }
.searchline__clear {
  font-size: .68rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--madder);
  border-bottom: 1px solid currentColor;
  padding-bottom: .1em;
  transition: opacity .3s;
}
.searchline__clear:hover { opacity: .65; }

.empty__hint {
  margin-top: .6rem;
  font-size: var(--step--1);
  color: var(--ink-faint);
}

/* a category with nothing in it under the current search */
.chip:disabled { opacity: .32; pointer-events: none; }

/* burger */
.burger {
  display: none;
  width: 44px; height: 44px;
  position: relative; z-index: 1002;
  margin-right: -10px;
}
.burger span {
  position: absolute; left: 11px; width: 22px; height: 1.5px;
  background: currentColor;
  transition: transform .45s var(--ease), opacity .3s;
}
.burger span:nth-child(1) { top: 18px; }
.burger span:nth-child(2) { top: 25px; }
.burger.is-open span:nth-child(1) { transform: translateY(3.5px) rotate(45deg); }
.burger.is-open span:nth-child(2) { transform: translateY(-3.5px) rotate(-45deg); }

/* mobile drawer */
.drawer {
  position: fixed; inset: 0; z-index: 1001;
  background: var(--indigo); color: var(--paper);
  display: grid; place-content: center;
  gap: 1.2rem; text-align: center;
  clip-path: circle(0% at calc(100% - 3rem) 2.4rem);
  transition: clip-path .75s var(--ease);
  visibility: hidden;
}
.drawer.is-open { clip-path: circle(150% at calc(100% - 3rem) 2.4rem); visibility: visible; }
.drawer a {
  font-family: var(--serif);
  font-size: clamp(1.9rem, 7vw, 3rem);
  letter-spacing: .04em;
  opacity: 0; transform: translateY(18px);
  transition: opacity .6s var(--ease), transform .6s var(--ease);
}
.drawer.is-open a { opacity: 1; transform: none; }
.drawer.is-open a:nth-child(1) { transition-delay: .18s; }
.drawer.is-open a:nth-child(2) { transition-delay: .24s; }
.drawer.is-open a:nth-child(3) { transition-delay: .30s; }
.drawer.is-open a:nth-child(4) { transition-delay: .36s; }
.drawer.is-open a:nth-child(5) { transition-delay: .42s; }
.drawer.is-open a:nth-child(6) { transition-delay: .48s; }
.drawer__mark { width: 54px; margin: 0 auto 1rem; opacity: .5; }

@media (max-width: 1040px) {
  .nav { display: none; }
  .burger { display: block; }
}

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  align-items: end;
  overflow: hidden;
  background: var(--indigo);
  color: var(--paper);
}
.hero__media { position: absolute; inset: 0; z-index: 0; }
.hero__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transform: scale(1.14);
  transition: opacity 1.6s var(--ease-soft);
  will-change: transform;
}
.hero__media img.is-loaded { opacity: .68; animation: kenburns 26s var(--ease-soft) forwards; }
@keyframes kenburns { to { transform: scale(1); } }

.hero__scrim {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(180deg, rgba(14,20,34,.62) 0%, rgba(14,20,34,.12) 32%, rgba(14,20,34,.30) 62%, rgba(14,20,34,.86) 100%);
}

.hero__inner {
  position: relative; z-index: 2;
  width: 100%; max-width: var(--maxw); margin-inline: auto;
  padding: 0 var(--gut) clamp(3.5rem, 8vh, 7rem);
}

.hero__title {
  font-size: var(--step-4);
  line-height: .94;
  letter-spacing: -.02em;
  margin-block: .3em .55em;
}
.hero__title em {
  font-style: italic;
  color: var(--ochre);
}

/* word-by-word mask reveal */
.reveal-words .word { display: inline-block; overflow: hidden; vertical-align: bottom; }
.reveal-words .word > span {
  display: inline-block;
  transform: translateY(105%);
  transition: transform 1.05s var(--ease);
  transition-delay: var(--d, 0s);
}
.reveal-words.is-in .word > span { transform: translateY(0); }

.hero__meta {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: clamp(1rem, 3vw, 2.5rem);
}
.hero__lede { max-width: 46ch; color: rgba(247,242,231,.86); font-weight: 300; }

.hero__cue {
  position: absolute; z-index: 2;
  left: 50%; bottom: 1.6rem; transform: translateX(-50%);
  display: grid; justify-items: center; gap: .6rem;
  font-size: .58rem; letter-spacing: .4em; text-transform: uppercase;
  color: rgba(247,242,231,.72);
}
.hero__cue i {
  display: block; width: 1px; height: 46px;
  background: linear-gradient(180deg, rgba(247,242,231,.8), transparent);
  animation: cue 2.6s var(--ease-soft) infinite;
  transform-origin: top;
}
@keyframes cue {
  0%   { transform: scaleY(0); opacity: 0; }
  35%  { transform: scaleY(1); opacity: 1; }
  100% { transform: scaleY(1) translateY(46px); opacity: 0; }
}

/* small hero for inner pages */
.pagehead {
  position: relative;
  padding-block: clamp(8rem, 18vh, 13rem) clamp(2.5rem, 6vw, 5rem);
  overflow: hidden;
}
.pagehead::after {
  content: ""; position: absolute; left: var(--gut); right: var(--gut); bottom: 0;
  height: 1px; background: var(--line);
}
.pagehead__title { font-size: var(--step-3); margin-block: .18em .34em; }

/* ==========================================================================
   Marquee
   ========================================================================== */

.marquee {
  overflow: hidden;
  border-block: 1px solid var(--line);
  padding-block: clamp(.9rem, 2vw, 1.5rem);
  background: var(--paper-warm);
  user-select: none;
}
.marquee__track {
  display: flex; width: max-content;
  animation: marquee 44s linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__group {
  display: flex; align-items: center; gap: clamp(1.6rem, 4vw, 3.4rem);
  padding-right: clamp(1.6rem, 4vw, 3.4rem);
}
.marquee span {
  font-family: var(--serif);
  font-size: clamp(1.1rem, .9rem + 1.1vw, 2rem);
  font-style: italic;
  color: var(--ink-soft);
  white-space: nowrap;
}
.marquee svg { width: 16px; height: 16px; color: var(--ochre); flex: none; }
@keyframes marquee { to { transform: translateX(-50%); } }

/* ==========================================================================
   Scroll reveals
   ========================================================================== */

[data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
  transition-delay: var(--d, 0s);
}
[data-reveal="fade"]  { transform: none; }
[data-reveal="left"]  { transform: translateX(-34px); }
[data-reveal="right"] { transform: translateX(34px); }
[data-reveal="scale"] { transform: scale(.94); }
[data-reveal].is-in   { opacity: 1; transform: none; }

/* image that unveils behind a sliding curtain */
.unveil { position: relative; overflow: hidden; }
.unveil::after {
  content: ""; position: absolute; inset: 0; z-index: 2;
  background: var(--paper);
  transform-origin: bottom;
  transition: transform 1.15s var(--ease);
  transition-delay: var(--d, 0s);
}
.unveil.is-in::after { transform: scaleY(0); }
.unveil img { transform: scale(1.16); transition: transform 1.6s var(--ease); transition-delay: var(--d, 0s); }
.unveil.is-in img { transform: scale(1); }

/* ==========================================================================
   Media frames
   ========================================================================== */

.frame {
  position: relative;
  overflow: hidden;
  background: var(--paper-deep);
}
.frame img, .frame video { width: 100%; height: 100%; object-fit: cover; }

/* blur-up placeholder */
.ph { position: relative; overflow: hidden; background: var(--paper-deep); }
.ph__lqip {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  filter: blur(18px) saturate(1.2);
  transform: scale(1.1);
  transition: opacity .7s var(--ease-soft);
}
.ph img.ph__real { opacity: 0; transition: opacity .8s var(--ease-soft); }
.ph.is-loaded img.ph__real { opacity: 1; }
.ph.is-loaded .ph__lqip { opacity: 0; }




/* ==========================================================================
   Item card
   ========================================================================== */

.card { position: relative; display: block; width: 100%; text-align: left; }

/* Every card is the same shape regardless of the photograph inside it.
   4:5 is chosen deliberately: it matches the median of our own portrait
   photographs (0.78), so most pieces nearly fill the frame, while a wide
   piece sits as a complete plate rather than being cropped in half.
   The piece is CONTAINED, never cropped — the whole drawn field is the
   product. The ground and hairline read as a mount. */
.card__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--paper-warm);
  padding: clamp(.45rem, 2.2%, 1.1rem);
  box-shadow: inset 0 0 0 1px rgba(26, 22, 19, .09);
  transition: background .55s var(--ease-soft), box-shadow .55s var(--ease);
}
.card__media img {
  width: 100%; height: 100%;
  object-fit: contain;
  transition: transform 1.1s var(--ease);
}
/* Hover — the plate lifts toward you and a soft shadow appears beneath it. */
/* The whole card is the plate — photograph AND caption sit inside the frame,
   so the text never looks detached and the cast shadow falls below the card
   rather than tinting the paper behind the title. */
.card {
  /* constant, so the hover frame has room beneath the art no. without the
     layout shifting when you point at it */
  padding-bottom: .8rem;
  transition: transform .55s var(--ease), box-shadow .55s var(--ease);
}
.card:hover, .card:focus-visible {
  transform: translateY(-8px);
  box-shadow:
    0 0 0 7px var(--paper),
    0 0 0 8px var(--indigo),
    0 32px 56px -24px rgba(26, 22, 19, .5);
}

.card:hover .card__media,
.card:focus-visible .card__media {
  background: var(--paper-deep);
  box-shadow: inset 0 0 0 1px rgba(26, 22, 19, .16);
}
.card:hover .card__media img { transform: scale(1.035); }

.card__zoom {
  position: absolute; z-index: 2; right: .7rem; bottom: .7rem;
  width: 42px; height: 42px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--paper); color: var(--indigo);
  opacity: 0; transform: translateY(10px) scale(.8);
  transition: opacity .5s var(--ease), transform .5s var(--ease);
}
.card:hover .card__zoom, .card:focus-visible .card__zoom { opacity: 1; transform: none; }
.card__zoom svg { width: 16px; height: 16px; }

/* Title above, art no. beneath — so a two-line title can never push one card's
   caption out of line with its neighbours. */
.card__body { padding-top: .9rem; }
.card__title {
  font-family: var(--serif);
  font-size: clamp(1.05rem, .95rem + .5vw, 1.32rem);
  font-weight: 400;
  line-height: 1.28;
  /* a very long title truncates at two lines rather than shoving the grid about */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  /* a kalam stroke under the words — not a rule across the card */
  text-decoration: underline 1px transparent;
  text-underline-offset: .2em;
  transition: color .4s var(--ease-soft), text-decoration-color .5s var(--ease-soft);
}
.card:hover .card__title,
.card:focus-visible .card__title {
  color: var(--madder);
  text-decoration-color: var(--madder);
}

.card:hover .card__artno { color: var(--madder); }
.card__artno {
  transition: color .4s var(--ease-soft);
  display: block;
  margin-top: .3rem;
  font-size: .66rem;
  letter-spacing: .22em;
  color: var(--ink-faint);
  white-space: nowrap;
}

.card__badge {
  position: absolute; z-index: 2; left: 0; top: .9rem;
  background: var(--indigo); color: var(--paper);
  font-size: .6rem; letter-spacing: .22em; text-transform: uppercase;
  padding: .45em 1em .45em .9em;
}
.card__badge--film { background: var(--madder); }

/* ==========================================================================
   Grid / collections
   ========================================================================== */

/* the collection's own search field — always visible, unlike the header one */
.gsearch {
  position: relative;
  display: flex; align-items: center;
  max-width: 460px;
  margin-top: 2.2rem;
}
.gsearch__icon {
  position: absolute; left: 1.05rem;
  display: grid; place-items: center;
  color: var(--ink-faint);
  pointer-events: none;
}
.gsearch__icon svg { width: 17px; height: 17px; }
.gsearch__input {
  width: 100%;
  font: inherit;
  font-size: var(--step-0);
  color: var(--ink);
  background: var(--paper-warm);
  border: 1px solid var(--line);
  border-radius: 100px;
  padding: .82em 2.8em .82em 2.9em;
  transition: border-color .3s, background .3s;
}
.gsearch__input::placeholder { color: var(--ink-faint); }
.gsearch__input:focus {
  outline: none;
  border-color: var(--ink-faint);
  background: var(--paper);
}
.gsearch__input::-webkit-search-cancel-button { display: none; }
.gsearch__clear {
  position: absolute; right: .6rem;
  width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  color: var(--ink-faint);
  opacity: 0; pointer-events: none;
  transition: opacity .25s, color .3s, background .3s;
}
.gsearch__clear svg { width: 14px; height: 14px; }
.gsearch__clear:hover { color: var(--ink); background: var(--line-soft); }
.gsearch.has-value .gsearch__clear { opacity: 1; pointer-events: auto; }

.filters {
  display: flex; flex-wrap: wrap; gap: .55rem;
  padding-block: 1.5rem 2.5rem;
}
.chip {
  font-size: var(--step--1);
  letter-spacing: .13em; text-transform: uppercase;
  padding: .62em 1.25em;
  border: 1px solid var(--line);
  border-radius: 100px;
  color: var(--ink-soft);
  transition: background .4s var(--ease-soft), color .4s, border-color .4s;
  white-space: nowrap;
}
.chip:hover { border-color: var(--ink-faint); }
.chip[aria-pressed="true"] { background: var(--indigo); border-color: var(--indigo); color: var(--paper); }
.chip b { font-weight: 400; opacity: .55; margin-left: .45em; font-size: .85em; }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 268px), 1fr));
  /* the hover ring extends 8px beyond each card on every side — both gaps
     must clear two of those plus breathing room, or neighbouring rings touch */
  gap: clamp(1.6rem, 2.8vw, 3rem) clamp(1.4rem, 2.1vw, 2.1rem);
}
.grid--2 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 420px), 1fr)); }

/* Entrance — the mount wipes down to uncover the piece, echoing the curtain
   reveal on the home page.
   NOTE: the card itself animates OPACITY ONLY. A finished animation with
   fill-mode `both` locks whatever it animated, overriding normal rules
   regardless of specificity — so animating transform here would silently
   disable the hover lift below. */
.grid > .card {
  animation: fade-in .7s var(--ease) both;
  animation-delay: var(--d, 0s);
}
/* The wipe goes on the media's CONTENTS, never on .card__media itself:
   a clip-path clips the element's own box-shadow, so wiping the mount would
   permanently clip away the hover ring and cast shadow. */
.grid > .card .card__media > .ph,
.grid > .card .card__media > video {
  animation: wipe .9s var(--ease) both;
  animation-delay: var(--d, 0s);
}
@keyframes fade-in { from { opacity: 0; } }
@keyframes wipe    { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }

.empty {
  padding: clamp(3rem, 8vw, 6rem) 0;
  text-align: center; color: var(--ink-faint);
}
.empty svg { width: 46px; margin: 0 auto 1.2rem; opacity: .35; }

/* ==========================================================================
   Category band (home)
   ========================================================================== */

.band { display: grid; gap: clamp(1.6rem, 4vw, 4rem); align-items: center; }
@media (min-width: 900px) {
  .band { grid-template-columns: 1fr 1fr; }
  .band--flip .band__text { order: -1; }
}
.band__media { position: relative; }
.band__media .frame {
  box-shadow: 0 30px 70px -40px rgba(26,22,19,.55);
}
.band__media .frame img { transition: transform 1.4s var(--ease); }
.band:hover .band__media .frame img { transform: scale(1.04); }


/* ==========================================================================
   Process timeline
   ========================================================================== */

.steps { position: relative; display: grid; gap: clamp(2.2rem, 5vw, 4.5rem); }
.steps::before {
  content: ""; position: absolute; left: 0; top: .6rem; bottom: .6rem;
  width: 1px; background: var(--line);
}
.steps::after {
  content: ""; position: absolute; left: 0; top: .6rem;
  width: 1px; height: var(--progress, 0%);
  background: var(--madder);
  transition: height .1s linear;
}
@media (min-width: 900px) {
  .steps::before, .steps::after { left: 50%; }
}

.step { position: relative; padding-left: 2.6rem; }
.step::before {
  content: ""; position: absolute; left: -4px; top: .62rem;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--paper); border: 1px solid var(--ink-faint);
  transition: background .5s var(--ease), border-color .5s, transform .5s var(--ease);
}
.step.is-reached::before { background: var(--madder); border-color: var(--madder); transform: scale(1.25); }
/* The stage vignette draws itself as the stage scrolls into view.
   Every stroked element carries pathLength="1", so one dasharray value makes
   them all draw over the same span of time regardless of real length. */
.step__art {
  display: block;
  width: clamp(66px, 8vw, 92px);
  margin-bottom: 1.1rem;
  color: var(--madder);
  /* hidden until the stage is reached: a round line cap still paints a dot at
     zero dash length, so un-drawn diagrams would show faint specks */
  opacity: 0;
  transition: opacity .3s var(--ease-soft);
}
.step__art svg { width: 100%; height: auto; overflow: visible; }
.step.is-reached .step__art { opacity: 1; }

/* The whole diagram draws at once when its stage arrives — every stroke
   together, as one gesture. pathLength="1" is what makes that possible: it
   normalises each path's length so they all complete in the same span
   instead of short strokes snapping while long ones lag. */
.step__art [pathLength] {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1.1s var(--ease-soft);
}
.step.is-reached .step__art [pathLength] { stroke-dashoffset: 0; }

/* filled pieces — buds, seeds, drops — settle in as the lines finish */
.step__art .ink {
  fill: currentColor;
  stroke: none;
  opacity: 0;
  transition: opacity .55s var(--ease-soft) .7s;
}
.step.is-reached .step__art .ink { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .step__art [pathLength] { stroke-dashoffset: 0; transition: none; }
  .step__art .ink { opacity: 1; transition: none; }
}

@media (min-width: 900px) {
  /* follow the side the text is on */
  .step .step__art            { margin-left: auto; margin-right: 0; }
  .step:nth-child(even) .step__art { margin-left: 0; margin-right: auto; }
}

.step__n {
  font-size: .68rem; letter-spacing: .26em; color: var(--madder);
  text-transform: uppercase; display: block; margin-bottom: .55rem;
}
.step h3 { font-size: var(--step-1); margin-bottom: .5rem; }
.step p { color: var(--ink-soft); max-width: 54ch; }

@media (min-width: 900px) {
  .step { width: 50%; padding-left: 0; padding-right: 3.5rem; text-align: right; }
  .step::before { left: auto; right: -5px; }
  .step:nth-child(even) {
    margin-left: 50%; padding-right: 0; padding-left: 3.5rem; text-align: left;
  }
  .step:nth-child(even)::before { right: auto; left: -4px; }
  .step:nth-child(even) p { margin-left: 0; }
  .step p { margin-left: auto; }
}

/* the end of the line — where the timeline arrives */
.steps__end {
  position: relative;
  padding-left: 2.6rem;
  padding-top: 1.4rem;
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(1.15rem, 1rem + .6vw, 1.5rem);
  line-height: 1.3;
  color: var(--ink);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}
.steps__end.is-reached { opacity: 1; transform: none; }

/* the terminal mark — the line stops here.
   It sits just after .steps, so the track (which ends .6rem inside that
   block) reads as arriving at this dot rather than running past it. */
.steps__end::before {
  content: "";
  position: absolute; left: -7.5px; top: 0;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--paper);
  border: 1.5px solid var(--ink-faint);
  transition: background .6s var(--ease), border-color .6s, box-shadow .6s;
}
/* a short connector closing the gap left by the track's own inset */
.steps__end::after {
  content: "";
  position: absolute; left: 0; top: -12px;
  width: 1px; height: 14px;
  background: var(--line);
  transition: background .6s var(--ease);
}
.steps__end.is-reached::before {
  background: var(--madder);
  border-color: var(--madder);
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--madder) 14%, transparent);
}
.steps__end.is-reached::after { background: var(--madder); }

@media (min-width: 900px) {
  /* the line runs down the middle here, so the destination centres on it */
  .steps__end {
    width: 100%;
    padding-left: 0;
    padding-top: 2.6rem;
    text-align: center;
  }
  .steps__end::before { left: 50%; margin-left: -8px; top: -8px; }
  .steps__end::after  { left: 50%; top: -22px; height: 16px; }
}

/* ==========================================================================
   Dye swatches
   ========================================================================== */

/* Nine colours, so the grid is set to divide cleanly: 3x3 on a wide screen,
   2 columns below with the ninth spanning the row so nothing is orphaned.
   auto-fit was leaving 7 across and 2 stranded. */
.swatches {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
}
@media (min-width: 620px) {
  .swatches { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 619px) {
  /* an odd count in two columns would leave a half-width last cell */
  .swatches > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}
.swatch { background: var(--paper); padding: clamp(1.2rem, 3vw, 2.2rem); text-align: center; }
.swatch i {
  display: block; width: 58px; height: 58px; border-radius: 50%;
  margin: 0 auto 1rem; background: var(--c);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.08);
  transition: transform .6s var(--ease);
}
.swatch:hover i { transform: scale(1.12); }
.swatch b { display: block; font-family: var(--serif); font-size: 1.15rem; font-weight: 400; }
.swatch span { display: block; font-size: var(--step--1); color: var(--ink-faint); margin-top: .25rem; }

/* ==========================================================================
   Quote / pull
   ========================================================================== */

.quote {
  background: var(--indigo); color: var(--paper);
  position: relative; overflow: hidden;
}
.quote__mark {
  position: absolute; right: -2%; top: 50%; transform: translateY(-50%);
  width: clamp(200px, 32vw, 420px); opacity: .07; color: var(--paper);
}
.quote blockquote {
  font-family: var(--serif);
  font-size: clamp(1.5rem, 1rem + 2.6vw, 3rem);
  font-style: italic; font-weight: 300; line-height: 1.28;
  max-width: 22ch;
}
.quote cite {
  display: block; margin-top: 1.8rem;
  font-family: var(--sans); font-style: normal;
  font-size: var(--step--1); letter-spacing: .24em; text-transform: uppercase;
  color: rgba(247,242,231,.66);
}

/* ==========================================================================
   Contact
   ========================================================================== */

/* "You are asking about SAR-03." — shown only when the visitor arrived here
   from a particular piece. */
.about-piece {
  margin-top: 1.2rem;
  padding-left: 1rem;
  border-left: 2px solid var(--madder);
  font-size: var(--step-0);
  color: var(--ink-soft);
  max-width: 54ch;
}

/* --- contact cards ------------------------------------------------------
   Big icon, centred. The whole content block is a link; Copy is a separate
   button so clicking to open and clicking to copy never overlap. */

.contact-cards {
  display: grid;
  gap: clamp(1rem, 2vw, 1.6rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr));
}

.ccard {
  display: flex;
  flex-direction: column;
  background: var(--paper-warm);
  box-shadow: inset 0 0 0 1px var(--line);
  transition: background .45s var(--ease-soft), box-shadow .45s var(--ease-soft),
              transform .45s var(--ease);
}
.ccard:hover, .ccard:focus-within {
  background: var(--paper-deep);
  box-shadow: inset 0 0 0 1px var(--ink-faint);
  transform: translateY(-4px);
}

/* the clickable content */
.ccard__main {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: clamp(2rem, 4vw, 2.8rem) clamp(1.4rem, 3vw, 2rem) 0;
  cursor: pointer;
}

.ccard__icon {
  display: grid; place-items: center;
  width: 76px; height: 76px;
  border-radius: 50%;
  background: var(--paper);
  color: var(--madder);
  box-shadow: inset 0 0 0 1px var(--line);
  margin-bottom: 1.4rem;
  transition: background .45s var(--ease-soft), color .45s var(--ease-soft),
              box-shadow .45s var(--ease-soft);
}
.ccard__icon svg { width: 34px; height: 34px; }
.ccard:hover .ccard__icon, .ccard:focus-within .ccard__icon {
  background: var(--indigo);
  color: var(--paper);
  box-shadow: inset 0 0 0 1px var(--indigo);
}

.ccard__title {
  font-family: var(--serif);
  font-size: 1.5rem;
  font-weight: 400;
  margin-bottom: .3rem;
}

.ccard__value {
  font-size: var(--step-0);
  color: var(--ink);
  word-break: break-word;
  text-decoration: underline 1px transparent;
  text-underline-offset: .2em;
  transition: color .35s, text-decoration-color .35s;
}
.ccard:hover .ccard__value, .ccard:focus-within .ccard__value {
  color: var(--madder);
  text-decoration-color: var(--madder);
}

.ccard__note {
  font-size: var(--step--1);
  color: var(--ink-faint);
  margin-top: .6rem;
  line-height: 1.55;
  max-width: 26ch;
}

/* the small arrow that says "this opens something" */
.ccard__go {
  position: absolute; top: 1rem; right: 1rem;
  display: grid; place-items: center;
  width: 26px; height: 26px;
  color: var(--ink-faint);
  opacity: 0; transform: translate(-4px, 4px);
  transition: opacity .4s var(--ease-soft), transform .4s var(--ease), color .4s;
}
.ccard__go svg { width: 15px; height: 15px; }
.ccard:hover .ccard__go, .ccard:focus-within .ccard__go {
  opacity: 1; transform: none; color: var(--madder);
}

/* Copy — the only button on the card */
.ccard__btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  margin: clamp(1.5rem, 3vw, 2rem) clamp(1.4rem, 3vw, 2rem) clamp(1.4rem, 3vw, 2rem);
  padding: .75em 1em;
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  background: var(--paper);
  border: 1px solid var(--line);
  cursor: pointer;
  transition: background .3s var(--ease-soft), color .3s, border-color .3s;
}
.ccard__btn svg { width: 14px; height: 14px; flex: none; }
.ccard__btn:hover, .ccard__btn:focus-visible {
  background: var(--indigo); border-color: var(--indigo); color: var(--paper);
}
.ccard__btn.is-copied {
  background: var(--madder); border-color: var(--madder); color: var(--paper);
}

/* ==========================================================================
   Footer
   ========================================================================== */

.footer {
  background: var(--indigo); color: var(--paper);
  padding-block: clamp(3.5rem, 7vw, 6rem) 2rem;
}
.footer a { color: rgba(247,242,231,.78); }
.footer a:hover { color: var(--paper); }
.footer__top { display: grid; gap: clamp(2rem, 5vw, 4rem); }
@media (min-width: 820px) { .footer__top { grid-template-columns: 1.4fr 1fr 1fr; } }
.footer__mark { width: 52px; color: var(--paper); opacity: .85; margin-bottom: 1.2rem; }
.footer h4 {
  font-family: var(--sans); font-size: .68rem; letter-spacing: .3em;
  text-transform: uppercase; color: rgba(247,242,231,.5); margin-bottom: 1.1rem; font-weight: 400;
}
.footer ul { list-style: none; padding: 0; display: grid; gap: .6rem; }
.footer__tag { font-family: var(--serif); font-style: italic; font-size: 1.25rem; max-width: 30ch; color: rgba(247,242,231,.8); }
.footer__bottom {
  margin-top: clamp(2.5rem, 6vw, 4.5rem);
  padding-top: 1.8rem;
  border-top: 1px solid rgba(247,242,231,.14);
  display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between;
  font-size: var(--step--1); color: rgba(247,242,231,.5);
}

.socials { display: flex; flex-wrap: wrap; gap: .7rem; }
.footer__addr {
  margin-top: 1.3rem;
  font-size: var(--step--1);
  line-height: 1.6;
  color: rgba(247, 242, 231, .6);
}
.socials a {
  width: 42px; height: 42px; border-radius: 50%;
  border: 1px solid rgba(247,242,231,.22);
  display: grid; place-items: center;
  transition: background .4s var(--ease-soft), transform .4s var(--ease), border-color .4s;
}
.socials a:hover { background: rgba(247,242,231,.12); transform: translateY(-3px); border-color: rgba(247,242,231,.5); }
.socials svg { width: 17px; height: 17px; }

/* ---- moving between pages ---------------------------------------------- *
   Swapping content is near-instant, which reads as a flicker rather than a
   change. The content fades out, the new page fades in, and a hairline bar
   crosses the top meanwhile.                                               */

main#main {
  transition: opacity .22s var(--ease-soft);
}
html.is-navigating main#main { opacity: 0; }

/* the bar travels once across the top rather than looping */
html.is-navigating::after {
  content: "";
  position: fixed; inset: 0 auto auto 0; z-index: 10000;
  height: 2px; width: 100%;
  background: linear-gradient(90deg,
    transparent, var(--madder) 35%, var(--ochre) 70%, transparent);
  transform-origin: left;
  animation: nav-bar 1.1s var(--ease-soft) infinite;
  pointer-events: none;
}
@keyframes nav-bar {
  0%   { transform: scaleX(0);   opacity: 0; }
  35%  { opacity: 1; }
  100% { transform: scaleX(1);   opacity: 0; }
}

/* The mark, drawing and undrawing itself — the opening animation in
   miniature. It appears only after 350ms, so a fast page swap never waits
   on it and a slow one is explained. */
.navload {
  position: fixed; z-index: 10000;
  top: 50%; left: 50%;
  width: clamp(44px, 6vw, 62px);
  margin: 0;
  transform: translate(-50%, -50%);
  color: var(--ink-faint);
  opacity: 0;
  pointer-events: none;
}
.navload svg { width: 100%; height: auto; }

/* Draws itself once — exactly like the opening animation — then holds and
   breathes. A looping redraw was tried and abandoned: the paths have very
   different lengths, so one stroke-dasharray makes parts flicker in and out
   at different rates. */
html.is-navigating .navload {
  animation: navload-in .35s var(--ease-soft) .35s both,
             navload-breathe 2.2s var(--ease-soft) 1.2s infinite;
}
html.is-navigating .navload [stroke] {
  stroke-dasharray: 320;
  stroke-dashoffset: 320;
  animation: navload-draw .85s var(--ease-soft) .35s forwards;
}
html.is-navigating .navload [fill]:not([fill="none"]) {
  opacity: 0;
  animation: navload-bud .5s var(--ease) .85s forwards;
}

@keyframes navload-in   { from { opacity: 0; } to { opacity: 1; } }
@keyframes navload-draw { to { stroke-dashoffset: 0; } }
@keyframes navload-bud  { to { opacity: 1; } }
@keyframes navload-breathe {
  0%, 100% { opacity: 1;  transform: translate(-50%, -50%) scale(1); }
  50%      { opacity: .55; transform: translate(-50%, -50%) scale(.965); }
}

@media (prefers-reduced-motion: reduce) {
  html.is-navigating .navload { animation: navload-in .2s .35s both; }
  html.is-navigating .navload [stroke],
  html.is-navigating .navload [fill]:not([fill="none"]) { animation: none; }
}

html.is-navigating { cursor: progress; }

@media (prefers-reduced-motion: reduce) {
  main#main { transition: none; }
  html.is-navigating main#main { opacity: 1; }
}

/* ==========================================================================
   Music toggle
   Bottom-left corner, deliberately quiet. Sits below the item viewer's
   z-index so it never floats over a piece.
   ========================================================================== */

.bgm {
  position: fixed; z-index: 700;
  left: clamp(.9rem, 2vw, 1.6rem);
  bottom: clamp(.9rem, 2vw, 1.6rem);
  width: 44px; height: 44px;
  border-radius: 50%;
  display: grid; place-items: center;
  color: var(--ink-soft);
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--line);
  box-shadow: 0 8px 22px -14px rgba(26, 22, 19, .5);
  transition: color .3s, background .3s var(--ease-soft),
              border-color .3s, transform .35s var(--ease);
}
.bgm:hover { color: var(--ink); border-color: var(--ink-faint); transform: scale(1.06); }
.bgm:active { transform: scale(.94); }
.bgm svg { width: 19px; height: 19px; }

/* one icon or the other, never both */
.bgm__on { display: none; }
.bgm.is-on .bgm__on  { display: block; }
.bgm.is-on .bgm__off { display: none; }
.bgm.is-on { color: var(--madder); border-color: color-mix(in srgb, var(--madder) 45%, transparent); }

/* the viewer covers the page; the toggle must not sit on top of it */
body.is-locked .bgm { opacity: 0; pointer-events: none; }
.bgm { transition: opacity .3s, color .3s, background .3s var(--ease-soft),
                   border-color .3s, transform .35s var(--ease); }

@media print { .bgm { display: none; } }

/* ==========================================================================
   Item viewer
   The ground is a WARM near-black drawn from --ink, not a cool black, so
   moving from the cream page into the viewer stays inside the same palette.
   ========================================================================== */

.lb {
  position: fixed; inset: 0; z-index: 2000;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  --lb-ground: #17130E;
  background: var(--lb-ground);
  color: var(--paper);
  opacity: 0; visibility: hidden;
  transition: opacity .4s var(--ease-soft), visibility .4s;
}
.lb.is-open { opacity: 1; visibility: visible; }

/* --- top bar: counter · identity · close ------------------------------- */
.lb__top {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1rem;
  padding: clamp(.7rem, 1.6vw, 1.05rem) clamp(.9rem, 2.4vw, 1.8rem);
  border-bottom: 1px solid rgba(247, 242, 231, .1);
}
/* the mark, so a screenshot of a piece still carries the house */
.lb__brand { display: block; width: clamp(28px, 3.2vw, 38px); color: var(--paper); opacity: .85; }
.lb__brand svg { width: 100%; height: auto; }

/* which piece of how many — sat bottom-left, level with the zoom pill */
.lb__count {
  position: absolute; z-index: 4;
  left: clamp(.9rem, 2.2vw, 1.8rem);
  bottom: clamp(1rem, 2.4vw, 1.6rem);
  height: 44px;
  display: inline-flex; align-items: center;
  font-size: .7rem; letter-spacing: .2em;
  color: rgba(247, 242, 231, .52);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}
@media (max-width: 560px) {
  .lb__count { height: auto; bottom: .6rem; left: .8rem; font-size: .64rem; }
  /* still 44px — the accessible minimum — just less padding around them */
  .lb__nav   { width: 44px; height: 44px; }
  .lb__nav svg { width: 16px; height: 16px; }
  .lb__zbtn  { width: 44px; }
  .lb__zbtn, .lb__zlevel { height: 44px; }
  .lb__zlevel { min-width: 62px; }
  .lb__brand { width: 28px; }
}
.lb__icon {
  justify-self: end;
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid rgba(247, 242, 231, .22);
  color: var(--paper);
  transition: background .3s, border-color .3s;
}
.lb__icon:hover { background: rgba(247, 242, 231, .14); border-color: rgba(247, 242, 231, .55); }
.lb__icon svg { width: 17px; height: 17px; }

/* identity always visible, never scrolled away */
.lb__title {
  text-align: center;
  font-family: var(--serif); font-weight: 300;
  font-size: clamp(1.15rem, 1rem + .8vw, 1.85rem);
  line-height: 1.2;
  letter-spacing: -.005em;
  /* long titles wrap rather than shove the close button off the bar */
  max-width: 46ch;
}
/* bottom-right of the image: the art no. beside the piece it identifies */
.lb__artline {
  position: absolute; z-index: 4;
  right: clamp(.9rem, 2.2vw, 1.8rem);
  bottom: clamp(1rem, 2.4vw, 1.6rem);
  height: 44px;
  display: inline-flex; align-items: center; gap: .55rem;
}
@media (max-width: 560px) {
  .lb__artline { height: auto; bottom: .55rem; right: .8rem; gap: .35rem; }
}
.lb__artkey {
  font-size: .68rem; letter-spacing: .18em; text-transform: uppercase;
  color: rgba(247,242,231,.58);
  white-space: nowrap;
}
@media (max-width: 560px) { .lb__artkey { font-size: .6rem; letter-spacing: .14em; } }
.lb__artno {
  /* 600 is loaded specifically for this: small letterspaced type on a dark
     ground needs real weight, and 500 still reads as medium */
  font-size: .74rem; letter-spacing: .2em;
  font-weight: 600;
  color: #D6A24C;
  font-variant-numeric: tabular-nums;
}
.lb__copy {
  position: relative;
  display: grid; place-items: center;
  width: 30px; height: 30px;
  border-radius: 50%;
  color: rgba(247, 242, 231, .55);
  border: 1px solid rgba(247, 242, 231, .18);
  transition: background .3s var(--ease-soft), color .3s, border-color .3s,
              transform .35s var(--ease);
}
.lb__copy svg { width: 13px; height: 13px; }
/* the visible circle stays small; the tappable area is a comfortable 44px */
.lb__copy::after { content: ""; position: absolute; inset: -7px; border-radius: 50%; }
.lb__copy:hover, .lb__copy:focus-visible {
  background: rgba(247, 242, 231, .14);
  border-color: rgba(247, 242, 231, .5);
  color: var(--paper);
  transform: scale(1.12);
}
.lb__copy:active { transform: scale(.94); }
.lb__copy.is-copied {
  background: var(--madder); border-color: var(--madder); color: var(--paper);
  transform: none;
}

/* --- body -------------------------------------------------------------- */
.lb__body {
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  min-height: 0;
}
@media (min-width: 900px) {
  .lb__body {
    grid-template-rows: none;
    grid-template-columns: minmax(0, 1fr) clamp(300px, 27vw, 420px);
  }
}

/* --- the photograph ---------------------------------------------------- */
.lb__viewer {
  position: relative;
  min-height: 0;
  overflow: hidden;
}
/* The box is positioned, not sized by percentages. A height of 100% only
   resolves if every ancestor has a definite height — one `auto` anywhere in
   that chain and the image falls back to its natural size, overflows, and
   gets clipped with no way to reach the rest of it. Absolute insets cannot
   fail that way. The inset on the bottom is the room the zoom pill needs. */
.lb__media {
  position: absolute;
  inset: clamp(.8rem, 2.2vw, 1.8rem) clamp(.8rem, 2.2vw, 1.8rem)
         clamp(4.2rem, 7vw, 5.4rem);
  display: grid; place-items: center;
  overflow: hidden;
  touch-action: pan-y;
}
.lb__media.can-pan { cursor: grab; touch-action: none; }
.lb__media.is-zoomed { cursor: grab; touch-action: none; }
.lb__media.is-grabbing { cursor: grabbing; }

.lb__media img, .lb__media video {
  max-width: 100%; max-height: 100%;
  object-fit: contain;
  transform-origin: center;
  will-change: transform;
  opacity: 0;
  user-select: none; -webkit-user-drag: none;
  transition: opacity .45s var(--ease-soft);
}
.lb__media:not(.is-grabbing) img { transition: opacity .45s var(--ease-soft), transform .26s var(--ease); }
.lb__media img.is-ready, .lb__media video.is-ready { opacity: 1; }

/* --- zoom controls, centred beneath the image -------------------------- */
.lb__zoom {
  position: absolute; z-index: 4;
  left: 50%; bottom: clamp(1rem, 2.4vw, 1.6rem);
  transform: translateX(-50%);
  display: flex; align-items: center;
  border: 1px solid rgba(247, 242, 231, .2);
  border-radius: 100px;
  background: rgba(23, 19, 14, .84);
  backdrop-filter: blur(8px);
  overflow: hidden;
}
.lb__zoom[hidden] { display: none; }
.lb__zbtn, .lb__zlevel {
  display: grid; place-items: center; height: 46px;
  color: var(--paper);
  transition: background .3s, opacity .3s;
}
.lb__zbtn { width: 48px; }
.lb__zbtn svg { width: 17px; height: 17px; }
.lb__zlevel {
  min-width: 72px; font-size: .7rem; letter-spacing: .08em;
  font-variant-numeric: tabular-nums;
  border-inline: 1px solid rgba(247, 242, 231, .16);
}
.lb__zbtn:hover, .lb__zlevel:hover { background: rgba(247, 242, 231, .14); }
.lb__zbtn:disabled { opacity: .26; pointer-events: none; }

/* --- prev / next ------------------------------------------------------- */
.lb__nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  z-index: 3;
  width: 48px; height: 48px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid rgba(247, 242, 231, .2);
  background: rgba(23, 19, 14, .6);
  backdrop-filter: blur(6px);
  color: var(--paper);
  transition: background .3s, border-color .3s, opacity .3s;
}
.lb__nav--prev { left: clamp(.3rem, 1vw, 1rem); }
.lb__nav--next { right: clamp(.3rem, 1vw, 1rem); }
.lb__nav:hover { background: rgba(247, 242, 231, .18); border-color: rgba(247, 242, 231, .5); }
.lb__nav:disabled { opacity: 0; pointer-events: none; }
.lb__nav svg { width: 18px; height: 18px; }
.lb__nav.is-dim { opacity: .16; }
.lb__nav.is-dim:hover { opacity: 1; }

/* --- the description panel --------------------------------------------- */
.lb__info {
  --lb-pad: clamp(1.1rem, 2.4vw, 2rem);
  display: flex; flex-direction: column;
  border-top: 1px solid rgba(247, 242, 231, .1);
  overflow-y: auto;
  overscroll-behavior: contain;
  max-height: 32vh;
}

/* the category heads the panel and stays put while the description scrolls.
   The panel carries no padding of its own — otherwise text would scroll
   through the gap above a sticky heading. */
.lb__cat {
  position: sticky; top: 0; z-index: 2;
  background: var(--lb-ground);
  padding: var(--lb-pad) var(--lb-pad) .8rem;
  font-family: var(--sans);
  font-size: .68rem; font-weight: 400;
  letter-spacing: .3em; text-transform: uppercase;
  line-height: 1.4;
  color: rgba(247, 242, 231, .55);
  border-bottom: 1px solid rgba(247, 242, 231, .1);
}
/* a short fade under the locked heading, so a line of description scrolling
   beneath it softens away instead of being sliced through the letters */
.lb__cat::after {
  content: "";
  position: absolute; left: 0; right: 0; top: 100%;
  height: 16px;
  background: linear-gradient(var(--lb-ground), transparent);
  pointer-events: none;
}
@media (min-width: 900px) {
  .lb__info {
    border-top: 0;
    border-left: 1px solid rgba(247, 242, 231, .1);
    max-height: none;
    /* NOT justify-content:center — centring a flex column that overflows
       clips the top and makes it unreachable by scrolling. */
  }
}
.lb__desc {
  padding: 1.3rem var(--lb-pad) 0;
  font-size: var(--step-0);
  line-height: 1.8;
  color: rgba(247, 242, 231, .78);
  max-width: 46ch;
}
.lb__desc[hidden] { display: none; }
.lb__hint {
  margin-top: auto;
  padding: 1.8rem var(--lb-pad) var(--lb-pad);
  font-size: .66rem; line-height: 1.6;
  color: rgba(247, 242, 231, .32);
}
@media (hover: none), (max-width: 899px) { .lb__hint { display: none; } }

body.is-locked { overflow: hidden; }

/* ==========================================================================
   Preloader
   ========================================================================== */

.preload {
  position: fixed; inset: 0; z-index: 5000;
  background: var(--paper);
  display: grid; place-items: center;
  transition: opacity .8s var(--ease-soft), visibility .8s;
}
.preload.is-done { opacity: 0; visibility: hidden; }
.preload svg { width: clamp(64px, 12vw, 104px); color: var(--indigo); }
.preload [stroke] {
  stroke-dasharray: 300; stroke-dashoffset: 300;
  animation: draw 1.7s var(--ease-soft) forwards;
}
.preload [fill]:not([fill="none"]) { opacity: 0; animation: bloom .9s var(--ease) .75s forwards; }
@keyframes draw  { to { stroke-dashoffset: 0; } }
@keyframes bloom { to { opacity: 1; } }

/* ==========================================================================
   Motion & print
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  [data-reveal], .reveal-words .word > span { opacity: 1 !important; transform: none !important; }
  .unveil::after { transform: scaleY(0) !important; }
  .unveil img, .hero__media img { transform: none !important; }
  .hero__media img { opacity: .68; }
  .marquee__track { animation: none; }
}

@media print {
  .header, .footer, .hero__cue, .lb, .preload, body::before { display: none !important; }
  body { background: #fff; }
}
