/* ==========================================================================
   Lynda Hopkins | Painting & Mosaics
   Shared design system
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;1,300;1,400;1,500&family=Manrope:wght@300;400;500;600;700&display=swap');

:root {
  /* Outdoor light: sky, meadow, and atmospheric mist */
  --ink:        #2c3e50;
  --ink-soft:   #56697a;
  --paper:      #f7fbfd;
  --paper-warm: #e9f2f7;
  --canvas:     #d4e8f2;
  --line:       #c5dbe6;

  --sky:        #a5d6f0;
  --sky-deep:   #6fa9c8;
  --sage:       #a3d2b4;
  --sage-deep:  #5e8e72;
  --meadow:     #c0d9b4;
  --cream:      #e8e2b3;
  --mist:       #bcc8d8;

  --ochre:      #c8a96b;
  --ochre-deep: #8a6c3a;
  --rose:       #d4a89f;
  --rust:       #8a4f3a;
  --slate:      #5a7187;
  --shadow:     #2c3e50;

  /* Type */
  --serif:  'Cormorant Garamond', 'Playfair Display', Georgia, serif;
  --sans:   'Manrope', 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;

  /* Spacing & rhythm */
  --gutter: clamp(2.75rem, 9vw, 7rem);
  --max:    1280px;
  --max-narrow: 760px;

  /* Motion */
  --ease: cubic-bezier(.2,.7,.2,1);
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* Always reserve the scrollbar gutter so locking body overflow when
     the cart drawer or lightbox opens doesn't cause the page to reflow
     into the freed pixels. The setDrawer() padding-right hack covers
     older browsers that don't support this property. */
  scrollbar-gutter: stable;
}

body {
  margin: 0;
  font-family: var(--sans);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Subtle paper grain on the body */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.05 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  opacity: .55;
  mix-blend-mode: multiply;
}

main, header, footer, section { position: relative; z-index: 1; }

/* ---------- Typography ---------- */
h1,h2,h3,h4 {
  font-family: var(--serif);
  font-weight: 400;
  color: var(--ink);
  letter-spacing: .002em;
  margin: 0 0 .4em;
}

h1 {
  font-size: clamp(2.6rem, 6.4vw, 5.2rem);
  line-height: 1.02;
  letter-spacing: -.012em;
}

h2 {
  font-size: clamp(2rem, 3.8vw, 3rem);
  line-height: 1.1;
}

h3 {
  font-size: clamp(1.25rem, 1.8vw, 1.6rem);
  line-height: 1.25;
}

p { margin: 0 0 1.1em; }

.eyebrow {
  font-family: var(--sans);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ochre-deep);
  margin: 0 0 1.1em;
  display: inline-flex;
  align-items: center;
  gap: .9em;
}
.eyebrow::before {
  content: "";
  width: 28px;
  height: 1px;
  background: var(--ochre-deep);
  display: inline-block;
}

.lede {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.15rem, 1.6vw, 1.45rem);
  line-height: 1.5;
  color: var(--ink-soft);
  max-width: 60ch;
}

a {
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color .25s var(--ease), color .25s var(--ease);
}
a:hover { border-bottom-color: var(--ochre-deep); }

/* ---------- Layout ---------- */
.wrap     { max-width: var(--max); margin: 0 auto; padding: 0 var(--gutter); }
.wrap--n  { max-width: var(--max-narrow); margin: 0 auto; padding: 0 var(--gutter); }

.section { padding: clamp(4rem, 9vw, 8rem) 0; }
.section--soft { background: var(--paper-warm); }
.section--ink  { background: var(--ink); color: var(--paper); }
.section--ink h1, .section--ink h2, .section--ink h3 { color: var(--paper); }
.section--ink .eyebrow { color: var(--canvas); }
.section--ink .eyebrow::before { background: var(--canvas); }
.section--ink a { color: var(--paper); }

/* ---------- Header / nav ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  backdrop-filter: blur(10px);
  background: rgba(247, 251, 253, 0.82);
  border-bottom: 1px solid var(--line);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(1.2rem, 3vw, 3rem);
  padding: 1.1rem 0;
  max-width: var(--max);
  margin: 0 auto;
}

.brand {
  font-family: var(--serif);
  font-size: 1.45rem;
  letter-spacing: .01em;
  display: inline-flex;
  align-items: center;
  gap: .6em;
  white-space: nowrap;
  position: relative;
}
.brand-link {
  display: inline-flex;
  align-items: center;
  gap: .6em;
  border: 0;
  color: inherit;
}
.brand-link:hover { border-bottom-color: transparent; }
.brand .brand-mark {
  display: inline-block;
  width: 52px; height: 60px;
  border-radius: 50%;
  background-image: url('images/lynda-portrait.jpg');
  background-size: cover;
  background-position: center 30%;
  -webkit-mask-image: radial-gradient(ellipse 70% 75% at 50% 50%, #000 55%, transparent 100%);
          mask-image: radial-gradient(ellipse 70% 75% at 50% 50%, #000 55%, transparent 100%);
  flex-shrink: 0;
}
.brand .brand-sub {
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--ink-soft);
  position: absolute;
  right: 0;
  top: 100%;
  margin-top: -.6em;
}

.nav-links {
  display: flex;
  flex: 1;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .4rem clamp(.7rem, 1.5vw, 1.6rem);
  list-style: none;
  margin: 0; padding: 0;
}
.nav-links a,
.nav-links .cart-toggle {
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink);
  border: 0;
  position: relative;
  padding: .25rem 0;
  line-height: 1;
  white-space: nowrap;
}
.nav-links a::after {
  content: "";
  position: absolute;
  left: 0; right: 100%;
  bottom: -2px;
  height: 1px;
  background: var(--ochre-deep);
  transition: right .35s var(--ease);
}
.nav-links a:hover::after,
.nav-links a[aria-current="page"]::after { right: 0; }
.nav-links a[aria-current="page"] { color: var(--ochre-deep); }

.nav-toggle {
  display: none;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
}
.nav-toggle span {
  display: block;
  width: 22px;
  height: 1.5px;
  background: var(--ink);
  transition: transform .25s var(--ease), opacity .25s var(--ease);
}
.nav-toggle.is-open span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav-toggle.is-open span:nth-child(2) { opacity: 0; }
.nav-toggle.is-open span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

@media (max-width: 760px) {
  .brand-sub { display: none; }
  .brand .brand-mark { width: 28px; height: 34px; }
  .nav { padding: 1.1rem var(--gutter); }

  .nav-toggle { display: inline-flex; }

  .site-header { position: relative; }

  .nav-links {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: .5rem var(--gutter) 1.25rem;
    background: rgba(247, 251, 253, 0.98);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--line);
    box-shadow: 0 16px 40px -24px rgba(44,62,80,.25);
    max-height: 0;
    overflow: hidden;
    visibility: hidden;
    opacity: 0;
    transition: max-height .35s var(--ease), opacity .25s var(--ease), visibility 0s linear .35s;
  }
  .nav-links[data-open="true"] {
    max-height: 80vh;
    opacity: 1;
    visibility: visible;
    transition: max-height .35s var(--ease), opacity .25s var(--ease), visibility 0s;
  }
  .nav-links li { border-bottom: 1px solid var(--line); }
  .nav-links li:last-child { border-bottom: 0; }
  .nav-links a,
  .nav-links .cart-toggle {
    display: block;
    padding: .95rem 0;
    font-size: 13px;
    letter-spacing: .12em;
    width: 100%;
    text-align: left;
  }
  .nav-links a::after { display: none; }
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-block;
  font-family: var(--sans);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  padding: .95em 1.6em;
  border: 1px solid var(--ink);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  transition: background .25s var(--ease), color .25s var(--ease);
}
.btn:hover { background: var(--ink); color: var(--paper); border-bottom-color: var(--ink); }
.btn--ink   { background: var(--ink); color: var(--paper); }
.btn--ink:hover { background: var(--ochre-deep); border-color: var(--ochre-deep); }
.btn--ghost { border-color: var(--paper); color: var(--paper); }
.btn--ghost:hover { background: var(--paper); color: var(--ink); }

/* ---------- Hero ---------- */
.hero {
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  gap: clamp(2rem, 5vw, 5rem);
  align-items: center;
  padding: clamp(3rem, 8vw, 7rem) 0 clamp(3rem, 7vw, 6rem);
}
.hero-copy h1 { margin-bottom: .3em; }
.hero-copy h1 em,
.page-head h1 em {
  font-style: italic;
  color: var(--sky-deep);
  font-weight: 300;
}
.hero-meta {
  margin-top: 2rem;
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}
.hero-art {
  aspect-ratio: 4 / 5;
  position: relative;
  box-shadow:
    0 30px 60px -30px rgba(44,62,80,.28),
    0 -20px 50px -30px rgba(44,62,80,.18),
    0 8px 24px -16px rgba(44,62,80,.15),
    0 -6px 18px -12px rgba(44,62,80,.12);
}
.hero-art:has(.tile img) { aspect-ratio: auto; }
.hero-art .tile:has(img) {
  aspect-ratio: auto !important;
  height: auto !important;
}
.hero-art .tile:has(img) img { height: auto; }
@media (max-width: 880px) {
  .hero { grid-template-columns: 1fr; }
}

/* ---------- Painting tile (placeholder) ---------- */
.tile {
  position: relative;
  display: block;
  background: var(--canvas);
  overflow: hidden;
  border: 0;
  isolation: isolate;
  transition: transform .5s var(--ease);
}
.tile svg { display: block; width: 100%; height: 100%; }
.tile img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;
}
/* When a tile contains a real photograph: drop the canvas-blue background
   (so the painting isn't sitting in a blue mat), and suppress the canvas
   texture overlay (which was designed for the SVG placeholders and would
   noise-up a real photo). */
.tile:has(img) { background: transparent; }
.tile:has(img)::after { display: none; }

/* In the gallery, photographic tiles use a fixed 4/5 box (matching the
   store's product cards) so every tile in a row is the same height — the
   photo bottoms line up and the captions beneath them sit on a shared
   baseline. The painting is never cropped: `object-fit: contain` plus
   `object-position: center bottom` (inherited from `.tile img` above)
   sits the whole work against the bottom of its box, with any leftover
   space appearing above shorter/narrower works. This is the same
   letterbox model the store uses. (Earlier the gallery sized each photo
   to its natural ratio with a per-tile .offset stagger; the artist asked
   for the tidy, store-style aligned grid instead — see CLAUDE.md §7.) */
.tile::after {
  /* canvas weave & subtle vignette */
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse at 50% 105%, rgba(44,62,80,.14), transparent 60%),
    repeating-linear-gradient(0deg, rgba(255,255,255,.02) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(90deg, rgba(44,62,80,.02) 0 1px, transparent 1px 3px);
  mix-blend-mode: multiply;
}

.tile-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin-top: .9rem;
  padding-bottom: .25rem;
  border-bottom: 1px solid var(--line);
}
.tile-meta h3 {
  font-size: 1.1rem;
  font-style: italic;
  margin: 0;
}
.tile-meta .medium {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.tile-meta .status {
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: .18em;
  text-transform: uppercase;
  padding: .25em .6em;
  border: 1px solid var(--line);
  color: var(--ink-soft);
  white-space: nowrap;
}
.tile-meta .status.sold { border-color: var(--rust); color: var(--rust); }

.work {
  display: block;
  text-decoration: none;
  border: 0;
}
.work:hover .tile { transform: translateY(-3px); }

/* ---------- Galleries ---------- */
.featured-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(1rem, 2.2vw, 1.8rem);
  margin-top: 3rem;
}
.featured-grid .work { grid-column: span 4; }
.featured-grid .work .tile { aspect-ratio: 4 / 5; }
.featured-grid .work:nth-child(1) { grid-column: span 5; }
.featured-grid .work:nth-child(1) .tile { aspect-ratio: 4 / 5; }
.featured-grid .work:nth-child(2) { grid-column: span 4; margin-top: 4rem; }
.featured-grid .work:nth-child(2) .tile { aspect-ratio: 3 / 4; }
.featured-grid .work:nth-child(3) { grid-column: span 3; }
.featured-grid .work:nth-child(3) .tile { aspect-ratio: 3 / 5; }
@media (max-width: 880px) {
  .featured-grid .work,
  .featured-grid .work:nth-child(n) { grid-column: span 12; margin-top: 0; }
}

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: clamp(1.5rem, 3vw, 2.5rem);
  row-gap: clamp(1.5rem, 3vw, 2.5rem);
  margin-top: 2.5rem;
}
/* Every work spans 4 of 12 columns → a clean three-up grid, like the store.
   The .tall/.wide/.square shape classes and the .offset stagger are
   intentionally neutralised: photographic tiles all share the 4/5 box from
   the `.tile img` rules above so the grid stays aligned (CLAUDE.md §7). */
.gallery-grid .work { grid-column: span 4; }
.gallery-grid .work .tile,
.gallery-grid .work.tall .tile,
.gallery-grid .work.wide .tile,
.gallery-grid .work.square .tile { aspect-ratio: 4 / 5; }
.gallery-grid .work.span6,
.gallery-grid .work.span8 { grid-column: span 4; }
.gallery-grid .work.offset { margin-top: 0; }
@media (max-width: 880px) {
  .gallery-grid .work,
  .gallery-grid .work.span6,
  .gallery-grid .work.span8 { grid-column: span 6; margin-top: 0; }
}
@media (max-width: 540px) {
  .gallery-grid .work,
  .gallery-grid .work.span6,
  .gallery-grid .work.span8 { grid-column: span 12; margin-top: 0; }
}

/* ---------- Filters ---------- */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  margin: 2rem 0 0;
}
.chip {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  padding: .7em 1.2em;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  transition: all .2s var(--ease);
}
.chip:hover { border-color: var(--ink); }
.chip.is-active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}

/* Sub-row chips (only visible while a parent chip with sub-tabs is active).
   Smaller, lighter border, muted active state so the hierarchy reads
   parent-then-child rather than two equal-weight rows. */
.filters--sub {
  margin-top: .8rem;
}
.filters--sub[hidden] { display: none; }
.chip--sub {
  font-size: 10.5px;
  padding: .55em 1em;
  border-color: var(--mist);
  color: var(--ink-soft);
}
.chip--sub:hover { border-color: var(--ink-soft); color: var(--ink); }
.chip--sub.is-active {
  background: var(--ink-soft);
  color: var(--paper);
  border-color: var(--ink-soft);
}

/* ---------- Page header ---------- */
.page-head {
  padding: clamp(4rem, 9vw, 8rem) 0 clamp(2rem, 4vw, 3.5rem);
}
/* Page-head h1: sized a touch smaller than the hero scale and capped at half
   the content width, so a long heading reads horizontally across ~half the page
   in a few lines instead of stacking into a tall narrow column. Short headings
   sit well within this and are unaffected. (Mobile restores full width below.) */
.page-head h1 {
  font-size: clamp(2.3rem, 4.6vw, 3.8rem);
  max-width: 50%;
}
.page-head .lede { margin-top: 1.4rem; }

/* ---------- Two-column copy ---------- */
.cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 6vw, 6rem);
  align-items: start;
}
.cols.cols--center { align-items: center; }
@media (max-width: 880px) { .cols { grid-template-columns: 1fr; } }

/* ---------- Exhibition timeline ---------- */
.timeline {
  list-style: none;
  margin: 3rem 0 0;
  padding: 0;
  border-top: 1px solid var(--line);
}
.timeline li {
  display: grid;
  grid-template-columns: 130px 96px 1fr auto;
  gap: clamp(1rem, 3vw, 2.5rem);
  padding: 1.6rem 0;
  border-bottom: 1px solid var(--line);
  align-items: center;
}
/* Exhibition rows: always four columns (thumb | year | body | tag), so
   entries with and without photos line up in the same column rhythm.
   The leftmost column sits empty on rows without a photo, which keeps
   `<2023>` at the same horizontal position whether or not the entry
   has a thumb. Explicit grid-column on each child means we don't
   need a `:has()` rule any more — just place every child by name. */
.timeline--plain li { grid-template-columns: 96px 130px 1fr auto; }
.timeline--plain li > .exhibition-thumb { grid-column: 1; }
.timeline--plain li > .year             { grid-column: 2; }
.timeline--plain li > div               { grid-column: 3; }
.timeline--plain li > .tag              { grid-column: 4; }
.timeline .year {
  font-family: var(--serif);
  font-size: 1.6rem;
  font-style: italic;
  color: var(--ochre-deep);
  align-self: center;
  justify-self: end;
  text-align: right;
}
.timeline-thumb {
  display: block;
  width: 96px;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border: 0;
  box-shadow: -3px 3px 10px rgba(44,62,80,.14);
  align-self: center;
  justify-self: center;
  opacity: .85;
  transition: transform .35s var(--ease), opacity .35s var(--ease);
  /* Soft paper-tone backdrop behind any letterbox/pillarbox space
     left by object-fit: contain below. Without it, contain'd images
     would sit on whatever the row's background happens to be and
     look unintentional. */
  background: var(--paper);
}
.timeline-thumb img {
  width: 100%;
  height: 100%;
  /* contain (not cover) so landscape photos like the Zebra mosaics
     and portrait covers like Bird Talk both show in full inside the
     96-square frame, accepting a small amount of letterboxing in
     exchange for the whole subject being visible. */
  object-fit: contain;
  display: block;
}
.timeline-thumb:hover { transform: translateY(-2px); opacity: 1; }
.timeline-thumb.is-empty { box-shadow: none; opacity: 0; }
.timeline .show-title {
  font-family: var(--serif);
  font-size: 1.35rem;
  margin: 0 0 .15rem;
}
.timeline .venue {
  font-family: var(--sans);
  font-size: 12.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.timeline .show-blurb {
  font-size: 14.5px;
  margin: .55rem 0 0;
  color: var(--ink-soft);
  max-width: 60ch;
}
.timeline .tag {
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: .2em;
  text-transform: uppercase;
  padding: .35em .7em;
  border: 1px solid var(--line);
  color: var(--ink-soft);
  white-space: nowrap;
  align-self: center;
  text-decoration: none;
  transition: background .18s ease, color .18s ease, border-color .18s ease;
}
a.tag:hover { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.timeline .tag.upcoming { color: var(--sage-deep); border-color: var(--sage-deep); }
@media (max-width: 700px) {
  /* Thumb-left card layout: keeps the desktop relationship of "thumbnail
     beside text" instead of a stack where the thumb blew up to row width.
     Year sits above the title in column 2; thumb spans all rows on the
     left at its fixed 96px size. */
  .timeline li {
    grid-template-columns: 96px 1fr;
    column-gap: 1rem;
    row-gap: .35rem;
    align-items: start;
  }
  .timeline .year {
    grid-column: 2;
    grid-row: 1;
    justify-self: start;
    text-align: left;
    font-size: 1.2rem;
    line-height: 1.1;
    margin: 0 0 .1rem;
  }
  .timeline-thumb {
    grid-column: 1;
    grid-row: 1 / span 3;
    justify-self: start;
    align-self: start;
    width: 96px;
  }
  .timeline-thumb.is-empty { display: none; }
  .timeline > li > div {
    grid-column: 2;
    grid-row: 2;
    min-width: 0;
  }
  .timeline .show-title { font-size: 1.1rem; }
  .timeline .tag {
    grid-column: 2;
    grid-row: 3;
    justify-self: start;
  }
  /* Variants without thumbs (exhibitions, home mini-timeline) stack
     vertically — there's nothing to put in the left column. */
  .timeline--plain li { grid-template-columns: 1fr; column-gap: 0; }
  .timeline--plain .year,
  .timeline--plain > li > div,
  .timeline--plain .tag { grid-column: 1; grid-row: auto; }
}

/* ---------- Pull quote ---------- */
.pullquote {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.6rem, 3vw, 2.4rem);
  line-height: 1.3;
  color: var(--ink);
  max-width: 28ch;
  position: relative;
  padding-left: 2.5rem;
}
.pullquote::before {
  content: "";
  position: absolute;
  left: 0; top: .5em;
  width: 28px; height: 1px;
  background: var(--ochre-deep);
}
.pullquote cite {
  display: block;
  margin-top: 1.2rem;
  font-style: normal;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* ---------- Forms ---------- */
.form { display: grid; gap: 1.25rem; max-width: 540px; }
.field { display: grid; gap: .35rem; }
.field label {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.field input, .field textarea {
  font-family: var(--sans);
  font-size: 15px;
  padding: .85rem 0;
  border: 0;
  border-bottom: 1px solid var(--line);
  background: transparent;
  color: var(--ink);
  outline: none;
}
.field input:focus, .field textarea:focus { border-bottom-color: var(--ochre-deep); }
.field textarea { resize: vertical; min-height: 120px; }

/* ---------- Footer ---------- */
.site-footer {
  border-top: 1px solid var(--line);
  background: var(--paper-warm);
  padding: 4.5rem 0 2.4rem;
  margin-top: 6rem;
}
.foot-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: clamp(2rem, 5vw, 4rem);
  /* Default grid `align-items: stretch` is fine, but each cell's first
     child needs to actually start at row-top. Browser default p / h4
     top margins drift the brand's signature down relative to the
     Visit/Contact h4s — explicit `margin-top: 0` on the first-of-type
     children in each cell locks them all to the same y. */
  align-items: start;
}
@media (max-width: 700px) { .foot-grid { grid-template-columns: 1fr; } }
.foot-grid h4 {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 1rem;
}
.foot-grid ul { list-style: none; padding: 0; margin: 0; line-height: 2; font-size: 14.5px; }

/* Visit column splits its 8 links into two sub-columns. grid-auto-flow:
   column with grid-template-rows: repeat(4, auto) is what makes the items
   flow top-to-bottom in column 1 first (Gallery → Workshops & Commissions)
   and only then start column 2 (Journal → Contact). column-count: 2 also
   works but is less predictable on item splitting. */
.foot-grid > div:nth-child(2) > ul {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(4, auto);
  grid-auto-flow: column;
  column-gap: clamp(.6rem, 1.5vw, 1.5rem);
}
@media (max-width: 480px) {
  /* Below tiny-mobile widths the two sub-cols become too cramped for
     "Workshops & Commissions", so revert to a single column there. */
  .foot-grid > div:nth-child(2) > ul {
    grid-template-columns: 1fr;
    grid-template-rows: none;
    grid-auto-flow: row;
  }
}
.foot-grid p { font-size: 14.5px; color: var(--ink-soft); }
.foot-mark {
  font-family: var(--serif);
  font-size: 1.6rem;
  font-style: italic;
  margin: 0 0 .9rem;          /* pin to row-top so brand-column signature aligns with Visit/Contact h4s */
  line-height: 1;
}
/* Social icons beneath the Contact column. Renders as a small horizontal
   row of brand glyphs (Instagram + Facebook), coloured ochre-deep so they
   read as a warm personal accent rather than navigation chrome. */
.social-links {
  display: flex;
  gap: .9rem;
  margin: 2rem 0 0;
  padding: 0;
  list-style: none;
  line-height: 1;
}
.social-links li { padding: 0; }
.social-links a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  color: var(--ochre-deep);
  border: 0;
  transition: color .2s var(--ease);
}
.social-links a:hover,
.social-links a:focus-visible { color: var(--ochre); border: 0; }
.social-links a:focus-visible {
  outline: 2px solid var(--ochre);
  outline-offset: 2px;
}
.social-links svg {
  width: 32px;
  height: 32px;
  display: block;
}
.foot-bottom {
  margin-top: 3.6rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--line);
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
@media (max-width: 700px) { .foot-bottom { flex-direction: column; gap: .5rem; } }

/* ---------- Reveal-on-scroll ----------
   Elements start at opacity 0 and JS adds .is-visible via IntersectionObserver
   to fade them in. The reveal-fallback animation is a safety net: if JS never
   runs (script blocked, network failure, parse error), it forces opacity to 1
   after 1.5s so content never stays permanently hidden. */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .9s var(--ease), transform .9s var(--ease);
  animation: reveal-fallback 0.001s linear 1.5s forwards;
}
.reveal.is-visible { opacity: 1; transform: none; animation: none; }
@keyframes reveal-fallback { to { opacity: 1; transform: none; } }

/* ---------- Portrait (faded-edge photograph) ----------
   Used on About for the studio portrait. The radial mask softens the
   image into whatever paper / canvas / ink background sits behind it.
   When the image file is missing, a warm tonal placeholder shows in
   its place via the .is-missing class added by the inline onerror. */
.portrait {
  margin: 0;
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 5;
  -webkit-mask-image: radial-gradient(ellipse 72% 78% at 50% 50%, #000 52%, transparent 100%);
          mask-image: radial-gradient(ellipse 72% 78% at 50% 50%, #000 52%, transparent 100%);
}
.portrait img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.portrait .placeholder {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  text-align: center;
  padding: 2rem;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1rem, 1.6vw, 1.3rem);
  color: rgba(247, 251, 253, .92);
  background:
    radial-gradient(circle at 35% 30%, var(--sky) 0%, var(--sky-deep) 50%, var(--slate) 100%);
}
.portrait .placeholder[hidden] { display: none; }
.portrait img.is-missing { display: none; }

/* About page hero: text + portrait side-by-side */
.about-head {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
}
.about-head .portrait { max-width: 360px; justify-self: end; }
@media (max-width: 880px) {
  .about-head { grid-template-columns: 1fr; }
  .about-head .portrait { justify-self: start; max-width: 280px; }
}

/* Smaller portrait used inside the biography column */
.portrait--bio { max-width: 280px; margin-bottom: 1.4rem; }

/* ---------- Utility ---------- */
.lockup-rule {
  display: block;
  width: 60px;
  height: 1px;
  background: var(--ochre-deep);
  margin: 1.6rem 0;
}
.kicker {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.05rem;
  color: var(--ochre-deep);
}

.signature {
  display: inline-block;
  width: 220px;
  height: 70px;
  max-width: 100%;
  vertical-align: middle;
  background-color: var(--ochre-deep);
  -webkit-mask-image: url('images/lynda-sig.png');
          mask-image: url('images/lynda-sig.png');
  -webkit-mask-position: left center;
          mask-position: left center;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-size: contain;
          mask-size: contain;
}
.signature--foot { width: 140px; height: 40px; }
.signature--brand {
  width: 180px;
  height: 50px;
  background-color: var(--sky-deep);
}
.signature--head {
  /* The Lynda signature PNG is 264×232 (aspect 1.14:1) and the bottom of
     the "L" sits at ~77.6% of the canvas height — the remaining ~22% is
     the "y" descender. Sizing the box to the signature's aspect ratio
     and pinning mask-position: left bottom means the visible mark fills
     the box exactly, so the trailing full-stop hugs Lynda rather than
     floating in empty mask space. height in em scales with the h1 font.
     vertical-align: -.29em pushes the box down so the L's bottom lands
     on the text baseline (0.224 × 1.3em ≈ 0.29em). */
  height: 1.3em;
  width: calc(1.3em * 1.14);
  vertical-align: -.29em;
  -webkit-mask-image: url('images/lynda-sig-2.png');
          mask-image: url('images/lynda-sig-2.png');
  -webkit-mask-position: left bottom;
          mask-position: left bottom;
}
@media (max-width: 760px) {
  /* Mask shorthand was rendering inconsistently on mobile Safari with the
     "center left" position keyword pair (mixes axes). Longhand above plus
     these scaled sizes keep the signature visible on phones. */
  .signature        { width: 170px; height: 54px; }
  .signature--foot  { width: 120px; height: 34px; }
  .signature--brand { width: 130px; height: 36px; }
  /* .signature--head intentionally not overridden here — its em-based
     sizing scales with the h1 font-size on every viewport. */

  /* On desktop .page-head and .hero pin horizontal padding to 0 so the
     eyebrow / h1 align flush with the brand portrait in the nav. On
     phones the nav restores its own gutter, so the alignment trick is
     no longer needed and the bare h1/lede sits right against the
     viewport edge — restore the gutter here. */
  .page-head,
  .hero {
    padding-left: var(--gutter);
    padding-right: var(--gutter);
  }
  /* Half-width cap is a desktop device; on phones the heading uses the full
     column. */
  .page-head h1 { max-width: none; }
}
.signature-line { line-height: 1; margin-top: 3.2rem; }

/* ==========================================================================
   STORE
   ========================================================================== */

/* ---------- Shop filters bar ---------- */
.shop-head {
  display: flex;
  justify-content: space-between;
  align-items: end;
  flex-wrap: wrap;
  gap: 1.5rem;
  margin-bottom: 2.5rem;
}

/* ---------- Shop grid ---------- */
.shop-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 3vw, 2.5rem);
  margin-top: 2rem;
}
@media (max-width: 880px) { .shop-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 540px) { .shop-grid { grid-template-columns: 1fr; } }

.product-card {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  border: 0;
  color: var(--ink);
}
.product-card .tile {
  aspect-ratio: 4 / 5;
  transition: transform .5s var(--ease);
}
.product-card:hover .tile { transform: translateY(-3px); }

.product-card-body {
  padding-top: 1rem;
  display: flex;
  flex-direction: column;
  gap: .35rem;
}
.product-card-body h3 {
  font-size: 1.15rem;
  font-style: italic;
  font-weight: 400;
  margin: 0;
}
.product-card-body .medium {
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0;
  /* Reserve a row of height even when medium + dimensions are both
     empty (admin-managed products often leave them off). Without this
     the card collapses by ~18px and breaks the grid's vertical rhythm
     against catalogue products that always carry a medium string. */
  min-height: 1.6em;
}
.product-card-body .row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: .4rem 1rem;
  margin-top: .35rem;
}
.product-card-body .price {
  font-family: var(--serif);
  font-size: 1.3rem;
}
.product-card-body .price .currency { font-size: .8em; color: var(--ink-soft); }

/* product tags */
.tag-set { display: flex; gap: .35rem; flex-wrap: wrap; margin-top: .25rem; }
.ptag {
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: .18em;
  text-transform: uppercase;
  padding: .25em .55em;
  border: 1px solid var(--line);
  color: var(--ink-soft);
  white-space: nowrap;
}
.ptag.original  { color: var(--ochre-deep); border-color: var(--ochre-deep); }
.ptag.print     { color: var(--sage-deep); border-color: var(--sage-deep); }
.ptag.book      { color: var(--rust); border-color: var(--rust); }
.ptag.card      { color: var(--slate); border-color: var(--slate); }
.ptag.sold      { color: var(--rust); border-color: var(--rust); background: rgba(138,58,44,.06); }
.ptag.lowstock  { color: var(--ochre-deep); border-color: var(--ochre-deep); }
.ptag.held      { color: var(--ochre-deep); border-color: var(--ochre-deep); background: #f5ead4; font-variant-numeric: tabular-nums; }

.card-quick {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: .5rem;
}
.card-quick-hint {
  font-family: var(--serif);
  font-style: italic;
  font-size: .95rem;
  color: var(--ochre-deep);
}
.card-quick-add {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  padding: .5em .9em;
  border: 1px solid var(--ink);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  transition: background .18s ease, color .18s ease, border-color .18s ease;
}
.card-quick-add:hover { background: var(--ink); color: var(--paper); }
.card-quick-add:disabled { cursor: default; opacity: .85; }
.card-quick-add.is-added {
  background: var(--sage-deep);
  border-color: var(--sage-deep);
  color: var(--paper);
}
.card-quick-add.is-error {
  background: var(--rust);
  border-color: var(--rust);
  color: var(--paper);
}

.product-card.is-sold .tile { filter: grayscale(.4) brightness(.95); }
.product-card.is-sold::after {
  /* a discreet diagonal "Sold" ribbon could go here */
}
.product-card.is-held .tile { filter: grayscale(.25) brightness(.97); }
.product-card.is-held .price { opacity: .55; }

/* ---------- Product detail page ----------
   Layout shape on desktop:

     [empty col 1, row 1]   |   [.head: eyebrow + title]
     [.image]               |   [.body: price + everything else]

   The head spans the full width of the right column and lives in row 1.
   The image and the body both start at the top of row 2, so the top of
   the painting visually aligns with the top of the price. */
.product-detail {
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  grid-template-rows: auto 1fr;
  column-gap: clamp(2rem, 5vw, 5rem);
  row-gap: 0;
  align-items: start;
}
.product-detail__head  { grid-column: 2; grid-row: 1; }
.product-detail__image { grid-column: 1; grid-row: 2; }
.product-detail__body  { grid-column: 2; grid-row: 2; }

.product-detail__head h1 {
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  line-height: 1.15;
  margin-bottom: 0;
}
.product-detail__head .kicker { margin-top: .5em; }

/* The product detail image is a button so it's keyboard-focusable.
   Resets it visually to the bare tile so the framing is invisible —
   the only affordance is the cursor: zoom-in and the focus outline. */
.product-detail__image .image-zoom {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: zoom-in;
}
.product-detail__image .image-zoom:focus-visible {
  outline: 2px solid var(--ochre-deep);
  outline-offset: 6px;
}

@media (max-width: 880px) {
  .product-detail {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    column-gap: 0;
    row-gap: 1.5rem;
  }
  .product-detail__head,
  .product-detail__image,
  .product-detail__body {
    grid-column: 1;
    grid-row: auto;
  }
}

.product-detail .tile {
  aspect-ratio: 4 / 5;
  box-shadow: 0 30px 60px -30px rgba(44,62,80,.28), 0 8px 24px -16px rgba(44,62,80,.15);
}
/* When the product detail tile contains a real photograph, drop the
   forced 4:5 aspect ratio (and the bottom-aligning of the image inside)
   so the tile shrinks to the painting's natural size. The drop shadow
   then wraps the painting itself instead of an empty band above it. */
.product-detail .tile:has(img) {
  aspect-ratio: auto;
}
.product-detail .tile:has(img) img {
  height: auto;
  object-fit: unset;
  object-position: unset;
}

/* The product detail container fades during in-place prev/next swap.
   Overrides the default .reveal .9s transition so the fade-out → swap →
   fade-in feels snappy. */
#product-detail {
  transition: opacity .22s var(--ease);
}
#product-detail.is-fading {
  opacity: 0;
}

/* ---------- Product navigation strip (back / prev / next) ---------- */
.product-nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem 2rem;
  margin-bottom: 2.2rem;
  font-family: var(--sans);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .22em;
  text-transform: uppercase;
}
.product-nav a {
  color: var(--ink-soft);
  border-bottom: 1px solid transparent;
  transition: border-color .25s var(--ease), color .25s var(--ease);
  text-decoration: none;
}
.product-nav a:hover {
  border-bottom-color: var(--ochre-deep);
  color: var(--ink);
}
.product-nav__arrows {
  display: flex;
  gap: 1.6rem;
}
.product-nav__arrow span[aria-hidden] {
  font-family: var(--serif);
  font-size: 1.2em;
  letter-spacing: 0;
  vertical-align: -0.05em;
}
@media (max-width: 540px) {
  .product-nav { gap: .8rem 1.2rem; }
  .product-nav__arrows { gap: 1rem; }
}

.pricing-options {
  margin-top: 1.4rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
  display: grid;
  gap: .35rem;
  font-family: var(--sans);
  font-size: 14.5px;
}
.pricing-options > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
}
.pricing-options__label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.pricing-options__value {
  font-family: var(--serif);
  font-size: 1.05rem;
  color: var(--ink);
}

/* Framed / unframed picker on the product detail page. Two-card radio: the
   selected card has an ochre border and the price-display at the top of
   the body updates as the visitor toggles. The native input is visually
   hidden but stays focusable for keyboard / screen-reader use. */
.frame-options {
  margin-top: 1.4rem;
  padding: 1rem 0 0;
  border: 0;
  border-top: 1px solid var(--line);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .6rem;
  font-family: var(--sans);
}
.frame-options__legend {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding: 0;
  margin-bottom: .25rem;
  width: 100%;
}
.frame-option {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: .35rem;
  padding: .85rem 1rem;
  border: 1px solid var(--line);
  background: var(--paper);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.frame-option input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.frame-option:hover { border-color: var(--ochre-deep); }
.frame-option:focus-within {
  outline: 2px solid var(--ochre-deep);
  outline-offset: 2px;
}
.frame-option.is-selected {
  border-color: var(--ochre-deep);
  background: var(--paper-warm);
}
.frame-option__label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.frame-option.is-selected .frame-option__label { color: var(--ochre-deep); }
.frame-option__value {
  font-family: var(--serif);
  font-size: 1.15rem;
  color: var(--ink);
}
@media (max-width: 480px) {
  .frame-options { grid-template-columns: 1fr; }
}

/* Inline frame switcher on a cart row — shows the chosen variant in
   ochre eyebrow style, with a "Switch to <other>" text-link beside it. */
.cart-row__variant {
  margin: .35rem 0 .15rem;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .6rem;
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.cart-row__variant-current {
  color: var(--ochre-deep);
  font-weight: 600;
}
.cart-row__variant-toggle {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: var(--ink-soft);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.cart-row__variant-toggle:hover { color: var(--ink); }

.product-info h1 {
  font-size: clamp(2rem, 4vw, 3rem);
  margin-bottom: .2em;
}
.product-info .price-display {
  font-family: var(--serif);
  font-size: 2.2rem;
  margin: 1.4rem 0 .4rem;
}
.product-info .specs {
  list-style: none;
  margin: 2rem 0;
  padding: 1.5rem 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.product-info .specs li {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 1.2rem;
  padding: .4rem 0;
  font-size: 14.5px;
}
.product-info .specs li strong {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* qty stepper */
.qty {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--line);
  background: var(--paper);
}
.qty button {
  width: 2.4rem; height: 2.4rem;
  border: 0; background: transparent;
  font-size: 1.1rem; cursor: pointer;
  color: var(--ink);
}
.qty button:hover { background: var(--paper-warm); }
.qty input {
  width: 3rem; text-align: center; border: 0; background: transparent;
  font-family: var(--sans); font-size: 14px;
  color: var(--ink);
  -moz-appearance: textfield;
}
.qty input::-webkit-outer-spin-button, .qty input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.add-row {
  display: flex; gap: 1rem; align-items: center;
  margin-top: 1.5rem;
  flex-wrap: wrap;
}
.btn--full {
  width: 100%;
  text-align: center;
  padding: 1.05em 1.6em;
  font-size: 13px;
}

.stock-line {
  font-size: 12.5px;
  letter-spacing: .04em;
  color: var(--ink-soft);
  margin-top: .5rem;
}
.stock-line.in    { color: var(--sage-deep); }
.stock-line.low   { color: var(--ochre-deep); }
.stock-line.sold  { color: var(--rust); }

/* ---------- Cart drawer ---------- */
.cart-toggle {
  position: relative;
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink);
  border: 0;
  background: transparent;
  cursor: pointer;
  padding: .25rem 0;
}
.cart-toggle .count {
  display: inline-block;
  min-width: 1.4em;
  height: 1.4em;
  line-height: 1.4em;
  margin-left: .35em;
  padding: 0 .4em;
  border-radius: 1em;
  background: var(--ochre-deep);
  color: var(--paper);
  font-size: 11px;
  text-align: center;
}
.cart-toggle .count[data-count="0"] { display: none; }

.drawer {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: min(420px, 100%);
  background: var(--paper);
  border-left: 1px solid var(--line);
  box-shadow: -20px 0 60px -20px rgba(44,62,80,.2);
  z-index: 100;
  transform: translateX(100%);
  transition: transform .35s var(--ease);
  display: flex;
  flex-direction: column;
}
.drawer.is-open { transform: translateX(0); }
.drawer-back {
  position: fixed; inset: 0;
  background: rgba(44,62,80,.4);
  z-index: 99;
  opacity: 0;
  pointer-events: none;
  transition: opacity 1s var(--ease);
}
.drawer-back.is-open { opacity: 1; pointer-events: auto; }
.drawer-head {
  padding: 1.4rem 1.6rem;
  border-bottom: 1px solid var(--line);
  display: flex; justify-content: space-between; align-items: center;
}
.drawer-head h3 { margin: 0; font-size: 1.4rem; }
.drawer-close {
  background: transparent; border: 0; font-size: 1.4rem; cursor: pointer;
  color: var(--ink-soft);
  line-height: 1;
}
.drawer-body { flex: 1; overflow: auto; padding: 1rem 1.6rem; }
.drawer-foot {
  border-top: 1px solid var(--line);
  padding: 1.4rem 1.6rem;
  background: var(--paper-warm);
}
.drawer-empty {
  text-align: center;
  padding: 4rem 1rem;
  color: var(--ink-soft);
  font-style: italic;
}

/* ---------- Cart line item ---------- */
.cart-row {
  display: grid;
  grid-template-columns: 70px 1fr auto;
  gap: 1rem;
  padding: 1.1rem 0;
  border-bottom: 1px solid var(--line);
  align-items: start;
}
.cart-row .thumb {
  aspect-ratio: 1 / 1;
  background: transparent;
  overflow: visible;
}
.cart-row .thumb .tile {
  background: transparent;
  box-shadow: -3px 3px 8px rgba(44, 62, 80, .18);
}
.cart-row .thumb svg { width: 100%; height: 100%; display: block; }
.cart-row h4 {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 1rem;
  margin: 0 0 .15rem;
}
.cart-row .meta {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.cart-row .row-foot {
  display: flex; justify-content: space-between; align-items: center;
  margin-top: .6rem; gap: .5rem;
}
.cart-row .price-line {
  font-family: var(--serif); font-size: 1.05rem;
}
.cart-row .remove {
  background: transparent; border: 0; cursor: pointer;
  font-family: var(--sans); font-size: 11px;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-soft);
}
.cart-row .remove:hover { color: var(--rust); }

/* ---------- Cart page (full) ---------- */
.cart-table {
  display: grid;
  gap: 0;
  margin-top: 2rem;
  border-top: 1px solid var(--line);
}
.cart-table .cart-row {
  grid-template-columns: 110px 1fr auto auto;
  padding: 1.4rem 0;
}
.cart-table .cart-row .thumb { aspect-ratio: 4/5; }

.cart-summary {
  background: var(--paper-warm);
  padding: 2rem;
  border: 1px solid var(--line);
  position: sticky;
  top: 5rem;
}
.cart-summary h3 { margin: 0 0 1.4rem; }
.cart-summary dl { display: grid; grid-template-columns: 1fr auto; gap: .6rem 1rem; margin: 0 0 1.4rem; }
.cart-summary dt {
  font-family: var(--sans); font-size: 12px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-soft);
}
.cart-summary dd { margin: 0; font-family: var(--serif); font-size: 1.05rem; text-align: right; }
.cart-summary .total dt, .cart-summary .total dd {
  font-size: 1.15rem;
  font-weight: 500;
  color: var(--ink);
  padding-top: 1rem;
  border-top: 1px solid var(--line);
  letter-spacing: .04em;
  text-transform: none;
}
.cart-summary .total dd { font-size: 1.6rem; }
.cart-summary .note {
  font-size: 12px;
  color: var(--ink-soft);
  margin-top: 1.2rem;
  line-height: 1.5;
}

.page-head h1.cart-head,
.page-head h1.contact-head,
.page-head h1.journal-head { max-width: none; white-space: nowrap; }
@media (max-width: 720px) {
  .page-head h1.cart-head,
  .page-head h1.contact-head,
  .page-head h1.journal-head { white-space: normal; }
}

.cart-lede-row {
  display: flex;
  align-items: baseline;
  gap: 2rem;
}
.cart-lede-row .lede { flex: 1; margin: 0; }
.cart-lede-row .hold-time {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 700;
  font-size: 1.5rem;
  color: var(--ochre-deep);
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
  white-space: nowrap;
  flex-shrink: 0;
}
.cart-lede-row .hold-time:empty { display: none; }
@media (max-width: 720px) {
  .cart-lede-row { flex-wrap: wrap; gap: .8rem; }
}

.cart-layout {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
@media (max-width: 880px) {
  .cart-layout { grid-template-columns: 1fr; }
  .cart-summary { position: static; }
}

/* ---------- Order confirmation ---------- */
.order-card {
  background: var(--paper-warm);
  border: 1px solid var(--line);
  padding: clamp(2rem, 5vw, 4rem);
}
.order-card h1 { margin-bottom: .4em; }
.order-meta {
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 1rem 0 2rem;
  display: flex;
  gap: 2rem;
  flex-wrap: wrap;
}
.order-status {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  padding: .35em .8em;
  border: 1px solid var(--line);
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.order-status .dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--ochre-deep);
  animation: pulse 1.5s var(--ease) infinite;
}
.order-status.confirmed { color: var(--sage-deep); border-color: var(--sage-deep); }
.order-status.confirmed .dot { background: var(--sage-deep); animation: none; }
@keyframes pulse {
  0%,100% { opacity: 1; transform: scale(1); }
  50%     { opacity: .4; transform: scale(0.85); }
}

/* ---------- Sticky add bar (mobile product page) ---------- */
@media (max-width: 700px) {
  .sticky-add {
    position: sticky;
    bottom: 0;
    background: var(--paper);
    border-top: 1px solid var(--line);
    padding: .8rem 1rem;
    margin: 1rem -1rem -1rem;
    z-index: 10;
    display: flex; gap: .8rem; align-items: center;
  }
  .sticky-add .price-display { font-size: 1.4rem; margin: 0; }
}

/* ---------- Inline errors / banners ---------- */
.banner {
  padding: 1rem 1.2rem;
  border: 1px solid var(--line);
  background: var(--paper-warm);
  font-size: 14px;
  margin: 1rem 0;
}
.banner.warn { border-color: var(--ochre-deep); color: var(--ochre-deep); }
.banner.error { border-color: var(--rust); color: var(--rust); background: rgba(138,58,44,.06); }
.banner.success { border-color: var(--sage-deep); color: var(--sage-deep); background: rgba(122,138,107,.08); }

/* ==========================================================================
   RESPONSIVE: tablet (≤960px) and phone (≤480px)
   Additive layer that softens the desktop → mobile transition.
   ========================================================================== */

/* ---------- Tablet (≤960px) ---------- */
@media (max-width: 960px) {
  .featured-grid .work,
  .featured-grid .work:nth-child(n) {
    grid-column: span 6;
    margin-top: 0;
  }

  .gallery-grid .work,
  .gallery-grid .work.span6,
  .gallery-grid .work.span8 {
    grid-column: span 6;
  }

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

  /* The footer stays single-column at all phone widths (handled by the
     ≤700px rule). A 2-column layout here can't fit "Working from
     Oxfordshire, England." on one line at any common phone size. */

  .about-head .portrait { max-width: 320px; }
}

/* ---------- Phone (≤480px) ---------- */
@media (max-width: 480px) {
  .featured-grid .work,
  .featured-grid .work:nth-child(n),
  .gallery-grid .work,
  .gallery-grid .work.span6,
  .gallery-grid .work.span8 {
    grid-column: span 12;
  }

  /* The timeline keeps the thumb-left card layout from the (max-width: 700)
     rule down to the smallest screens — overriding to single-column here
     would put the thumbnail on its own row at full width. */

  .product-info .specs li {
    grid-template-columns: 1fr;
    gap: .15rem;
    padding: .55rem 0;
  }

  .cart-row {
    grid-template-columns: 60px 1fr;
    gap: .75rem;
  }
  .cart-row .row-foot { grid-column: 1 / -1; margin-top: .8rem; }

  .cart-table .cart-row {
    grid-template-columns: 80px 1fr;
    padding: 1.1rem 0;
  }
  .cart-table .cart-row > :nth-child(n+3) { grid-column: 1 / -1; }

  .drawer { width: 100%; border-left: 0; }
  .drawer-head, .drawer-body, .drawer-foot { padding-left: 1.1rem; padding-right: 1.1rem; }

  .cart-summary { padding: 1.4rem; }

  .btn { padding: 1em 1.3em; }

  .chip { padding: .8em 1.1em; }

  .shop-head { gap: 1rem; }

  .hero-meta .btn { flex: 1 1 auto; text-align: center; }
}

/* ==========================================================================
   LIGHTBOX
   Radial blur of the page behind the image (heaviest in the centre, easing
   out toward the edges but never going fully sharp), centered photograph
   that stays put while the page scrolls behind, on-screen and keyboard
   navigation through the surrounding gallery, and a soft fade between
   images.
   ========================================================================== */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  pointer-events: none;
  opacity: 0;
  /* Open is fast (the blur should appear immediately when zooming in);
     close is the same fast value so the page doesn't linger. The image
     itself has its own .26s fade via .lightbox-img transition. */
  transition: opacity .14s linear;
}
.lightbox.is-open {
  opacity: 1;
  pointer-events: auto;
}

/* Two stacked blur layers compose the gradient blur:
   - --soft covers the whole viewport with a light blur (so the edges are
     never fully sharp).
   - --heavy adds a heavier blur, but is masked with a radial gradient so
     it's only visible in the centre and fades to nothing at the edges.
   Where both apply, the two blurs compose; where only --soft applies, the
   page is gently softened. */
.lightbox-blur {
  position: absolute;
  inset: 0;
}
/* Zoom-out cursor is shown ONLY when hovering the painting itself —
   mirroring how the page below shows zoom-in only on the painting,
   not on every empty pixel of the product detail. The blur layers
   keep the default cursor (clicks still close, just no special
   indicator). Scoped to .is-open so the cursor can't leak onto the
   page underneath when the modal is closed. */
.lightbox.is-open .lightbox-img { cursor: zoom-out; }
.lightbox-blur--soft {
  background: rgba(247, 251, 253, 0.42);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
}
.lightbox-blur--heavy {
  -webkit-backdrop-filter: blur(28px);
          backdrop-filter: blur(28px);
  -webkit-mask-image: radial-gradient(ellipse 65% 65% at 50% 50%, #000 0%, transparent 100%);
          mask-image: radial-gradient(ellipse 65% 65% at 50% 50%, #000 0%, transparent 100%);
}

/* Browsers without backdrop-filter still need the page veiled, so layer in
   a heavier translucent fallback that hides instead of blurs. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .lightbox-blur--soft  { background: rgba(247, 251, 253, .85); }
  .lightbox-blur--heavy { background: radial-gradient(ellipse 65% 65% at 50% 50%, rgba(247, 251, 253, .85), transparent 100%); }
}

.lightbox-close {
  position: fixed;
  top: 1.5rem;
  right: 1.5rem;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(247, 251, 253, .9);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
  z-index: 4;
  transition: background .2s var(--ease), transform .2s var(--ease);
}
.lightbox-close:hover {
  background: var(--paper);
  transform: scale(1.06);
}

.lightbox-stage {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 4vh 3vw;
  z-index: 2;
  pointer-events: none;
}
/* When the lightbox is open, the figure and its arrows catch clicks
   while the empty space around them falls through to the blur layers
   (which close the modal). When the lightbox is *closed*, all stage
   children are non-interactive, so the centred-but-invisible figure
   doesn't swallow clicks aimed at the page below — without this scope
   you couldn't re-open the lightbox by clicking the product image
   after closing it once. */
.lightbox.is-open .lightbox-stage > * { pointer-events: auto; }

/* The figure sizes itself to the image via inline-block + intrinsic image
   sizing. Because the figure is sized to the image, the arrows positioned
   at right:100% / left:100% always sit a constant 1.5rem outside the
   image edges regardless of how wide or tall the painting is. */
.lightbox-figure {
  position: relative;
  display: inline-block;
  margin: 0;
  filter: drop-shadow(0 30px 60px rgba(44, 62, 80, .42));
}

.lightbox-img {
  display: block;
  max-width: min(84vw, 1400px);
  max-height: 84vh;
  width: auto;
  height: auto;
  opacity: 0;
  transition: opacity .26s var(--ease);
  background: var(--canvas);
}
.lightbox-img.is-active { opacity: 1; }

.lightbox-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(247, 251, 253, .92);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 2rem;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
  z-index: 3;
  transition: background .2s var(--ease), transform .2s var(--ease);
}
.lightbox-arrow:hover {
  background: var(--paper);
  transform: translateY(-50%) scale(1.08);
}
.lightbox-arrow[hidden] { display: none; }
.lightbox-arrow--prev { right: 100%; margin-right: 1.5rem; }
.lightbox-arrow--next { left:  100%; margin-left:  1.5rem; }

.lightbox-caption {
  margin: 1.5rem 0 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .35rem;
  text-align: center;
  max-width: 84vw;
  background: rgba(247, 251, 253, .85);
  padding: .9rem 1.4rem;
  border: 1px solid var(--line);
}
.lightbox-caption:empty { display: none; }
.lightbox-title {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.15rem;
  color: var(--ink);
}
.lightbox-medium {
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.lightbox-counter {
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-top: .15rem;
}

/* Narrow viewports: fall the arrows into the viewport edges so they don't
   disappear off-screen when the image fills most of the width. */
@media (max-width: 720px) {
  .lightbox-arrow {
    position: fixed;
    top: 50%;
    margin: 0;
    background: rgba(247, 251, 253, .85);
    width: 42px;
    height: 42px;
  }
  .lightbox-arrow--prev { left:  .5rem; right: auto; }
  .lightbox-arrow--next { right: .5rem; left:  auto; }
  .lightbox-arrow:hover { transform: translateY(-50%) scale(1.04); }

  .lightbox-stage { padding: 4vh 1rem; }
  .lightbox-img   { max-width: 96vw; max-height: 78vh; }
  .lightbox-close { top: 1rem; right: 1rem; }
}

/* =============================================================================
   Journal post (single entry, e.g. journal-bird-talk.html)
   ============================================================================= */
.post-wrap {
  max-width: 760px;
  margin: 0 auto;
  padding: 4rem var(--gutter) 6rem;
}
.post-wrap > h1 {
  font-size: clamp(1.8rem, 3.4vw, 2.6rem);
  line-height: 1.2;
  margin: .8rem 0 1rem;
}
.post-meta {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 2.4rem;
}
.post-meta time { font-variant-numeric: tabular-nums; }
.post-body {
  font-family: var(--serif);
  font-size: 1.15rem;
  line-height: 1.75;
  color: var(--ink);
}
.post-body p { margin: 0 0 1.3rem; }
/* Inline images inserted from the journal admin's body editor — sit
   centred in the prose with the same soft shadow as gallery tiles. */
.post-body img {
  display: block;
  max-width: 100%;
  height: auto;
  margin: 1.8rem auto;
  border-radius: 2px;
  box-shadow: -3px 3px 14px rgba(44, 62, 80, .14);
}
.post-figure { margin: 2.6rem 0; }
.post-figure img,
.post-figure video {
  width: 100%;
  height: auto;
  display: block;
  box-shadow: -4px 4px 16px rgba(44,62,80,.18);
}
/* Hero variant: cap at medium width so it doesn't take over the read,
   centred above the body text, and clickable via the .image-zoom
   button so it opens in the lightbox (binding lives in lightbox.js). */
.post-figure--hero {
  margin: .4rem auto 2.4rem;
  max-width: 520px;
}
.post-figure--hero .image-zoom {
  display: block;
  width: 100%;
  border: 0;
  background: transparent;
  padding: 0;
  cursor: zoom-in;
}
.post-figure--hero .image-zoom:focus-visible {
  outline: 2px solid var(--ochre-deep);
  outline-offset: 4px;
}

/* Exhibition timeline thumb: reuses .timeline-thumb's 96-square paper
   backdrop. The .image-zoom button is the click target; keep its
   bounding box the size of the thumb so the cursor reads "clickable
   image" everywhere on the square. */
.exhibition-thumb .image-zoom {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  background: transparent;
  padding: 0;
  cursor: zoom-in;
}
.exhibition-thumb .image-zoom:focus-visible {
  outline: 2px solid var(--ochre-deep);
  outline-offset: 3px;
}
.exhibition-thumb .image-zoom img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.post-figure video {
  background: #000;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}
.post-figure figcaption {
  margin-top: .9rem;
  font-family: var(--serif);
  font-style: italic;
  font-size: .98rem;
  color: var(--ink-soft);
}
.post-figure--grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(.6rem, 1.2vw, 1rem);
  align-items: start;
}
@media (max-width: 520px) {
  .post-figure--grid { grid-template-columns: 1fr; }
}
.post-tags {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin: 2rem 0 0;
}
.post-tags .tag {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  padding: .35em .8em;
  border: 1px solid var(--line);
  color: var(--ink-soft);
}

/* ---------- Like button (per-IP tally) ---------- */
.post-actions {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin: 3rem 0 0;
  padding-top: 1.6rem;
  border-top: 1px solid var(--line);
}
.like {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  padding: .45rem 1rem .45rem .8rem;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
  color: var(--ink-soft);
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: .04em;
  transition: color .25s var(--ease), border-color .25s var(--ease),
              background .25s var(--ease);
}
.like:hover { border-color: var(--ink-soft); color: var(--ink); }
.like:focus-visible { outline: 2px solid var(--ochre-deep); outline-offset: 2px; }
.like .like-heart {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linejoin: round;
  transition: fill .25s var(--ease), stroke .25s var(--ease), transform .25s var(--ease);
}
.like.is-liked {
  color: #c95b53;
  border-color: #f3c8c4;
  background: #fdf1ef;
}
.like.is-liked .like-heart {
  fill: #ed8985;
  stroke: #ed8985;
}
.like.is-pulsing .like-heart { transform: scale(1.18); }
.like[disabled] { cursor: progress; opacity: .65; }
.like-count {
  font-variant-numeric: tabular-nums;
  min-width: 1ch;
  text-align: left;
}

/* ---------- Comments ---------- */
.comments {
  margin-top: 4rem;
  padding-top: 2.6rem;
  border-top: 1px solid var(--line);
}
.comments h2 {
  margin: 0 0 1.6rem;
  font-size: clamp(1.4rem, 2.4vw, 1.8rem);
}
.comments-list { margin-bottom: 2.4rem; }
.comments-list .empty {
  color: var(--ink-soft);
  font-style: italic;
  font-family: var(--serif);
}
.comment {
  margin: 0 0 1.2rem;
  padding: 1rem 1.3rem;
  background: var(--paper-warm);
  border-left: 3px solid var(--ochre-deep);
}
.comment-head {
  display: flex;
  align-items: baseline;
  gap: .8rem;
  flex-wrap: wrap;
  margin: 0 0 .4rem;
}
.comment-author {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.1rem;
  color: var(--ink);
}
.comment-date {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}
.comment-body {
  margin: 0;
  font-family: var(--serif);
  font-size: 1.02rem;
  line-height: 1.65;
}

.comment-form {
  background: var(--paper-warm);
  border: 1px solid var(--line);
  padding: 1.6rem 1.8rem;
}
.comment-form h3 {
  margin: 0 0 1.2rem;
  font-size: 1.2rem;
}
.comment-form p { margin: 0 0 1rem; }
.comment-form label {
  display: block;
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 .4rem;
}
.comment-form input[type="text"],
.comment-form input[type="email"],
.comment-form textarea {
  width: 100%;
  padding: .6rem .8rem;
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 0;
  box-sizing: border-box;
}
.comment-form textarea {
  resize: vertical;
  min-height: 6.5rem;
  font-family: var(--serif);
  font-size: 15px;
}
.comment-form input:focus,
.comment-form textarea:focus {
  outline: 2px solid var(--ochre-deep);
  outline-offset: 1px;
}
.comment-note {
  font-size: 12px;
  color: var(--ink-soft);
  font-family: var(--sans);
  margin-top: .6rem !important;
}
.comment-thanks {
  margin-top: 2rem;
  padding: 1rem 1.4rem;
  background: #e8efe2;
  border-left: 3px solid var(--sage-deep);
  font-family: var(--sans);
  font-size: 14px;
  color: var(--ink);
}

/* ---------- Comment moderation page (served by /api/moderate) ---------- */
.moderate-card {
  background: var(--paper);
  border: 1px solid var(--line);
  padding: clamp(1.6rem, 4vw, 2.6rem);
}
.moderate-card h1 {
  font-size: clamp(1.6rem, 3vw, 2.1rem);
  line-height: 1.2;
  margin: .6rem 0 .8rem;
}
.moderate-card .lede { margin-bottom: 1.6rem; }
.moderate-comment {
  margin: 1.4rem 0 2rem;
  padding: 1rem 1.3rem;
  background: var(--paper-warm);
  border-left: 3px solid var(--ochre-deep);
}
.moderate-byline {
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 .6rem;
}
.moderate-comment blockquote {
  margin: 0;
  font-family: var(--serif);
  line-height: 1.6;
  white-space: pre-wrap;
  color: var(--ink);
}
.moderate-card form { margin: 0; }
.btn--approve {
  background: var(--sage-deep);
  color: var(--paper);
  border-color: var(--sage-deep);
}
.btn--approve:hover {
  background: var(--ink);
  border-color: var(--ink);
}
.btn--reject {
  background: var(--rust);
  color: var(--paper);
  border-color: var(--rust);
}
.btn--reject:hover {
  background: var(--ink);
  border-color: var(--ink);
}
.moderate-alt {
  margin-top: 1.4rem;
  font-size: 13px;
  color: var(--ink-soft);
}
.moderate-alt a { color: var(--ink-soft); border-bottom-color: var(--line); }


/* ---------- Booking modal ----------------------------------------------- */
/* Used by workshops-and-commissions.html (workshop-booking.js). Mirrors the
   lightbox's two-layer blur but with a centred form card instead of an
   image. The HTML stays in the DOM and toggles `hidden` for fast open/close
   without layout reflow. */
/* FAQ grid on the contact page. Single column container that flows into
   two CSS columns at desktop widths — adding or removing items rebalances
   the layout automatically. Each <div class="qa"> stays whole (no
   mid-question column break). The list is content-managed via the
   `contact-faq` editable section in /admin/sections, so the markup just
   needs to stay this exact shape: a flat list of .qa children with an
   <h3> + <p> pair inside each. */
.faq-grid {
  margin-top: 2.5rem;
  column-count: 2;
  column-gap: clamp(2rem, 5vw, 5rem);
}
.faq-grid .qa {
  break-inside: avoid;
  padding-bottom: 2rem;
}
.faq-grid .qa h3 {
  font-style: italic;
  margin: 0 0 .5rem;
}
.faq-grid .qa p {
  margin: 0;
}
@media (max-width: 720px) {
  .faq-grid { column-count: 1; }
}

/* "Other upcoming dates" list under the featured workshop card.
   Hidden by default in the markup; workshop-booking.js reveals it when
   there are two or more upcoming open workshops. */
.workshop-other-list {
  list-style: none;
  padding: 0;
  margin: .6rem 0 0;
  display: grid;
  gap: .8rem;
}
.workshop-other-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .6rem 1.2rem;
  padding: .9rem 1rem;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--paper);
}
.workshop-other-list .other-date {
  font-family: var(--serif);
  font-size: 1.05rem;
  color: var(--ink);
  flex: 1 1 12rem;
}
.workshop-other-list .other-meta {
  color: var(--ink-soft);
  font-size: 13px;
  flex: 1 1 12rem;
}
.workshop-other-list .other-book {
  font-size: 12px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ochre-deep);
  background: none;
  border: 0;
  cursor: pointer;
  padding: .2rem 0;
}
.workshop-other-list .other-book:hover { color: var(--ink); }

.booking-modal {
  position: fixed; inset: 0;
  display: flex; align-items: center; justify-content: center;
  z-index: 200;
  padding: clamp(1rem, 4vw, 3rem);
  overflow-y: auto;
}
.booking-modal[hidden] { display: none; }
.booking-modal__backdrop {
  position: absolute; inset: 0;
  background: rgba(44, 62, 80, 0.32);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.booking-modal__panel {
  position: relative;
  width: 100%; max-width: 560px;
  background: var(--paper);
  border-radius: 6px;
  box-shadow: 0 30px 80px -20px rgba(44, 62, 80, .35);
  padding: clamp(1.6rem, 3vw, 2.4rem);
  padding-top: clamp(1.4rem, 3vw, 2rem);
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
}
.booking-modal__close {
  position: absolute;
  top: .6rem; right: .8rem;
  width: 36px; height: 36px;
  border: 0; background: transparent;
  font-size: 28px; line-height: 1;
  color: var(--ink-soft);
  cursor: pointer;
}
.booking-modal__close:hover { color: var(--ink); }
.booking-modal__head { margin-bottom: 1.4rem; }
.booking-modal__head h2 {
  font-family: var(--serif);
  font-size: clamp(1.6rem, 2.4vw, 2rem);
  margin: .2rem 0 .4rem;
}
.booking-modal__subtitle {
  font-size: 14px;
  color: var(--ink-soft);
  margin: 0;
}
.booking-modal__price {
  font-family: var(--sans);
  font-size: 13px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ochre-deep);
  margin: .6rem 0 0;
}

/* Booking form fields */
.booking-form__row {
  display: flex; flex-direction: column;
  margin-bottom: 1rem;
}
.booking-form__row label {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: .35rem;
}
.booking-form__row .hint {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  color: var(--ink-soft);
  font-size: 11px;
  margin-left: .4rem;
}
.booking-form__row input,
.booking-form__row textarea {
  font-family: var(--sans);
  font-size: 15px;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: .65rem .8rem;
  width: 100%;
  box-sizing: border-box;
}
.booking-form__row input:focus,
.booking-form__row textarea:focus {
  outline: none;
  border-color: var(--ochre-deep);
  box-shadow: 0 0 0 2px rgba(200, 169, 107, .25);
}
.booking-form__hp {
  position: absolute;
  left: -9999px; top: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}
.booking-form__error {
  margin: .6rem 0 1rem;
  padding: .7rem .9rem;
  border-left: 3px solid var(--rust);
  background: rgba(138, 79, 58, .07);
  color: var(--rust);
  font-size: 14px;
  line-height: 1.5;
}
.booking-form__actions {
  display: flex; gap: .8rem;
  margin-top: 1.2rem;
  flex-wrap: wrap;
}
.booking-form__actions .btn { flex: 1; min-width: 140px; }
.booking-form__fine {
  margin: 1rem 0 0;
  font-size: 12px;
  color: var(--ink-soft);
  line-height: 1.5;
}

/* ---------- Contact closing image -------------------------------------- */
/* Wider-than-.wrap container so the painting reads as a featured image
   rather than a column-bound illustration. */
.closing-image .closing-image__inner {
  max-width: 1600px;
  margin: 0 auto;
  padding: 0 clamp(1rem, 3vw, 2.5rem);
}
.closing-image .closing-image__caption {
  margin: 1rem 0 0;
  font-size: 12px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: center;
}

/* Scroll-driven fade. The image fades in as it enters the viewport,
   holds through the middle, and fades out as it leaves — symmetric, so
   scrolling back up reverses the animation cleanly.

   Gated behind @supports for `animation-timeline: view()` so browsers
   without view-timeline (currently Firefox stable) just render the
   image at full opacity all the time. */
@supports (animation-timeline: view()) {
  .closing-image .closing-image__inner {
    animation: closing-image-fade linear both;
    animation-timeline: view();
    animation-range: entry 0% exit 100%;
    will-change: opacity, transform;
  }
}
/* Long, S-curve fade. Opacity stays barely-visible while only a
   sliver of the image is in the viewport, climbs as the image rises
   into view, peaks at full opacity ONLY when the image is centered,
   then mirrors back down. The 0-100 progress spans the full lifecycle
   (entry 0% exit 100% above), so 50% corresponds to "centred in the
   viewport". The non-linear shape (almost-flat at the start, fast
   climb to the peak, fast descent, almost-flat at the end) is what
   the artist asked for: only at 100% when fully in view, barely there
   at the edges. */
/* Asymmetric: fade + scale up over the first half of the view-timeline,
   then PLATEAU at full opacity/scale through the second half. The user
   wanted the image to stay fully present once they've scrolled it into
   view, only fading + shrinking again when they scroll back UP past
   the centred peak. View-timeline maps scroll position to progress
   linearly, so the same plateau on the second half is traversed in
   reverse on scroll-up — the image stays full until progress drops
   below 50%, then mirrors back down through 40 → 20 → 0. */
@keyframes closing-image-fade {
  0%   { opacity: 0;    transform: scale(0.82); }
  20%  { opacity: 0.08; transform: scale(0.88); }
  40%  { opacity: 0.55; transform: scale(0.97); }
  50%  { opacity: 1;    transform: scale(1);    }
  100% { opacity: 1;    transform: scale(1);    }
}

/* Respect reduced-motion preferences: no transform, snap-style fade. */
@media (prefers-reduced-motion: reduce) {
  .closing-image .closing-image__inner {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

/* Google reCAPTCHA v2 Invisible — hide the floating badge; the required
   attribution text sits next to each protected form instead (see contact /
   commission / comment forms). */
.grecaptcha-badge { visibility: hidden; }
.recaptcha-note { font-size: 11px; line-height: 1.5; color: var(--ink-soft); margin-top: 1rem; }
.recaptcha-note a { color: var(--ink-soft); text-decoration: underline; }
