@font-face {
  font-family: 'Caslon Antique';
  src: url('/fonts/CaslonAntique.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Caslon Antique';
  src: url('/fonts/CaslonAntique-Italic.ttf') format('truetype');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

:root {
  --bg: #fafaf7;
  --ink: #1a1a1a;
  --muted: #6b6b66;
  --rule: #e5e2da;
  --header-h: 5.25rem;
}

@media (max-width: 600px) {
  :root { --header-h: 6.75rem; }
}

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

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 9999;
  padding: 0.5rem 1rem;
  background: var(--ink);
  color: var(--bg);
  font-family: 'Inter', sans-serif;
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-decoration: none;
  border-bottom: none;
  transform: translateY(-110%);
  transition: transform 0.15s ease;
}
.skip-link:focus,
.skip-link:focus-visible {
  transform: translateY(0);
  outline: 2px solid var(--bg);
  outline-offset: -4px;
}

/* Sticky header would otherwise hide the top of any anchor or focused
   element scrolled into view. Keep its height in sync with --header-h. */
:root {
  scroll-padding-top: calc(var(--header-h) + 1rem);
}
main:focus { outline: none; }

html { scroll-behavior: smooth; }

body {
  font-family: 'Inter', system-ui, sans-serif;
  background: var(--bg);
  color: var(--ink);
  line-height: 1.6;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

.container {
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 2.5rem;
}

/* Header */
header {
  padding: 1.75rem 0;
  border-bottom: 1px solid var(--rule);
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--bg);
}

.header-inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.header-inner > nav {
  margin-left: auto;  /* keep nav + cart grouped on the right edge */
}

.logo {
  font-family: 'Fraunces', serif;
  font-weight: 500;
  font-size: 1.1875rem;
  font-variation-settings: "opsz" 36;
  letter-spacing: 0.005em;
}

nav ul {
  list-style: none;
  display: flex;
  gap: 2.25rem;
}

nav a {
  font-size: 0.8125rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  transition: opacity 0.2s;
}

nav a:hover { opacity: 0.5; }

nav a.active {
  border-bottom: 1px solid var(--ink);
  padding-bottom: 2px;
}

/* Hero */
.hero {
  padding: 2.5rem 0 4.5rem;
}

.hero-grid {
  display: grid;
  grid-template-columns: 1fr 1.05fr;
  gap: 5rem;
  align-items: start;
}

.hero-text {
  align-self: start;
}

@media (min-width: 901px) {
  .hero-text {
    position: sticky;
    top: calc(var(--header-h) + 1rem);
  }
}

.hero-eyebrow {
  font-size: 0.75rem;
  color: var(--muted);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: 1.75rem;
}

.hero h1 {
  font-family: 'Fraunces', serif;
  font-weight: 300;
  font-size: clamp(2.5rem, 6vw, 5rem);
  line-height: 0.95;
  font-variation-settings: "opsz" 144;
  letter-spacing: -0.025em;
  margin-bottom: 1.5rem;
}

.hero h1 em {
  font-style: italic;
  font-weight: 300;
}

.hero .lead {
  font-family: 'Fraunces', serif;
  font-weight: 300;
  font-size: 1.1875rem;
  line-height: 1.5;
  max-width: 38ch;
  margin-bottom: 2.5rem;
  font-variation-settings: "opsz" 36;
}

.hero-image {
  position: relative;
  aspect-ratio: 3 / 5;
  background: linear-gradient(140deg, #d8915a 0%, #a04e2a 45%, #4d1e10 100%);
  box-shadow: 0 30px 70px -30px rgba(60, 30, 10, 0.35);
  will-change: transform;
}

.hero-image .placeholder-tag {
  position: absolute;
  top: 1rem;
  left: 1rem;
  font-size: 0.625rem;
  color: rgba(255,255,255,0.7);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.caption {
  margin-top: 1.5rem;
  font-size: 0.875rem;
  color: var(--muted);
}

.caption .title {
  font-family: 'Fraunces', serif;
  font-style: italic;
  color: var(--ink);
  font-size: 1.0625rem;
  font-weight: 400;
  margin-right: 0.5rem;
}

/* CTA link */
.arrow-link {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
  font-size: 0.875rem;
  font-weight: 400;
  border-bottom: 1px solid var(--ink);
  padding-bottom: 3px;
  transition: opacity 0.25s ease;
}

.arrow-link::after {
  content: '→';
  display: inline-block;
  transition: transform 0.45s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.arrow-link:hover { opacity: 0.6; }
.arrow-link:hover::after { transform: translateX(6px); }

/* Section */
.section {
  padding: 6rem 0;
  border-top: 1px solid var(--rule);
}

.section-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 4rem;
  gap: 2rem;
}

.section-header h2 {
  font-family: 'Fraunces', serif;
  font-weight: 300;
  font-size: clamp(2rem, 4vw, 2.75rem);
  font-variation-settings: "opsz" 144;
  letter-spacing: -0.015em;
}

.section-footer {
  display: flex;
  justify-content: center;
  margin-top: 4rem;
}

/* Page intro (used on gallery, about, etc.) */
.page-intro {
  padding: 4rem 0 3rem;
}

.page-intro h1 {
  font-family: 'Fraunces', serif;
  font-weight: 300;
  font-size: clamp(2.5rem, 5.5vw, 4.5rem);
  line-height: 1;
  font-variation-settings: "opsz" 144;
  letter-spacing: -0.02em;
  margin-bottom: 1.25rem;
}

.page-intro h1 em {
  font-style: italic;
  font-weight: 300;
}

.page-intro .lead {
  font-family: 'Fraunces', serif;
  font-weight: 300;
  font-size: 1.125rem;
  line-height: 1.5;
  max-width: 52ch;
  font-variation-settings: "opsz" 36;
  color: var(--muted);
}

/* Grid */
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 5rem 3.5rem;
}

.card {
  display: block;
  cursor: pointer;
  opacity: 0;
  transform: translateY(40px);
  transition: opacity 0.95s cubic-bezier(0.2, 0.8, 0.2, 1), transform 0.95s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.card.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.card.filter-hidden {
  display: none;
}

.card-image {
  aspect-ratio: 4 / 5;
  margin-bottom: 1.25rem;
  position: relative;
  /* Hairline frame on every card — placeholder and real images alike — so
     the grid reads as a series of framed works on a wall. */
  box-shadow: inset 0 0 0 1px rgba(45,38,32,0.15);
  background:
    radial-gradient(ellipse 65% 55% at 28% 28%, var(--c1) 0%, transparent 70%),
    radial-gradient(ellipse 75% 65% at 75% 60%, var(--c2) 0%, transparent 75%),
    radial-gradient(ellipse 55% 45% at 45% 88%, var(--c3) 0%, transparent 70%),
    linear-gradient(160deg, var(--c2) 0%, var(--c1) 100%);
  transition: box-shadow 0.5s ease;
}

/* Curatorial hover — frame deepens, image softens slightly. No translate
   (this is a gallery card, not a product card). */
.card-image img {
  transition: filter 0.5s ease;
}
.card:hover .card-image {
  box-shadow: inset 0 0 0 1px rgba(45,38,32,0.32);
}
.card:hover .card-image img {
  filter: saturate(0.94) brightness(0.97);
}

.card-image .placeholder-tag {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  font-size: 0.5625rem;
  color: rgba(255,255,255,0.6);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* Gallery-style placeholder treatment — flat parchment "wall card" inside
   a thin frame, italic statement above a tiny uppercase status label.
   Shared across catalog cards (.card-image) and the painting detail page
   (.painting-image.is-empty) so both views always match. */
.card-mystery {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 0.9rem;
  padding: 1.5rem;
}
.card-mystery-line {
  font-family: 'Fraunces', serif;
  font-style: italic;
  font-weight: 400;
  font-size: 1rem;
  color: #2d2620;
  line-height: 1.3;
  max-width: 22ch;
}
.card-mystery-note {
  font-family: 'Inter', sans-serif;
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(45,38,32,0.7);
  line-height: 1.5;
  max-width: 28ch;
}
.card-mystery-rule { display: none; }

/* Flat parchment background + hairline frame on placeholder cards. Overrides
   the per-painting gradient stack defined for cards with images. */
.card-image.is-placeholder {
  background: #ebe5d8;
  box-shadow: inset 0 0 0 1px rgba(45,38,32,0.15);
}

/* Detail page — larger scale, same vocabulary. */
.painting-image .card-mystery-line { font-size: 1.5rem; }
.painting-image .card-mystery-note { font-size: 0.75rem; letter-spacing: 0.22em; }

.card-image .print-badge {
  position: absolute;
  bottom: 0.75rem;
  right: 0.75rem;
  font-size: 0.5625rem;
  color: rgba(255,255,255,0.85);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  background: rgba(0,0,0,0.32);
  padding: 0.25rem 0.5rem;
  backdrop-filter: blur(4px);
}

.meta-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin-bottom: 0.4rem;
}

.card .title {
  font-family: 'Fraunces', serif;
  font-style: italic;
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.3;
}

.card .year {
  font-family: 'Inter', sans-serif;
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}

.card .num {
  font-family: 'Inter', sans-serif;
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Filter bar */
.filter-bar {
  position: sticky;
  top: var(--header-h);
  background: var(--bg);
  z-index: 20;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  padding: 1.25rem 0;
  transition: box-shadow 0.3s ease;
}

.filter-bar.is-stuck {
  box-shadow: 0 4px 20px -10px rgba(40, 25, 15, 0.08);
}

.filter-row {
  display: flex;
  align-items: baseline;
  gap: 1.5rem;
  flex-wrap: wrap;
  padding: 0.375rem 0;
}

.filter-row + .filter-row {
  border-top: 1px dashed var(--rule);
  margin-top: 0.25rem;
  padding-top: 0.625rem;
}

.filter-label {
  font-size: 0.6875rem;
  color: var(--muted);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 500;
  flex-shrink: 0;
  width: 6rem;
}

.filter-options {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.25rem;
}

.filter-btn {
  background: none;
  border: none;
  font-family: inherit;
  font-size: 0.875rem;
  color: var(--muted);
  cursor: pointer;
  padding: 0.125rem 0;
  transition: color 0.2s;
  position: relative;
}

.filter-btn:hover { color: var(--ink); }

.filter-btn:focus { outline: none; }
.filter-btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  color: var(--ink);
}

.filter-btn.active {
  color: var(--ink);
  font-weight: 500;
}

.filter-btn.active::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: var(--ink);
}

/* Collapsible filter section — uses <details>/<summary> with a custom
   chevron so the user gets the standard click-to-expand pattern but
   visually quiet, matching the rest of the catalog chrome. */
.filter-collapse {
  padding: 0.375rem 0;
}

.filter-row + .filter-collapse,
.filter-collapse + .filter-collapse,
.filter-collapse + .filter-row {
  border-top: 1px dashed var(--rule);
  margin-top: 0.25rem;
  padding-top: 0.625rem;
}

.filter-collapse > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.4375rem;
  user-select: none;
  width: auto;
}

.filter-collapse > summary::-webkit-details-marker {
  display: none;
}

.filter-collapse > summary::after {
  content: '›';
  font-family: 'Fraunces', serif;
  font-weight: 300;
  font-size: 1.0625rem;
  color: var(--muted);
  line-height: 1;
  margin-left: 0.0625rem;
  transition: transform 0.2s ease;
  display: inline-block;
  transform-origin: 50% 55%;
}

.filter-collapse[open] > summary::after {
  transform: rotate(90deg);
}

.filter-collapse > summary:hover::after {
  color: var(--ink);
}

.filter-collapse .filter-label-value {
  font-size: 0.6875rem;
  color: var(--muted);
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}

.filter-collapse .filter-label-value:not(:empty)::before {
  content: '· ';
}

.filter-collapse > .filter-options {
  margin-top: 0.625rem;
}

.result-row {
  padding-top: 0.5rem;
}

.filter-search {
  background: none;
  border: none;
  font-family: 'Fraunces', serif;
  font-style: italic;
  font-weight: 300;
  font-size: 1.125rem;
  font-variation-settings: "opsz" 36;
  width: 100%;
  padding: 0.125rem 0;
  color: var(--ink);
  outline: none;
}

.filter-search::placeholder {
  color: var(--muted);
  font-style: italic;
}

.filter-search:focus { outline: none; }
.filter-search:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

.search-row {
  border-bottom: 1px dashed var(--rule);
  padding: 0.125rem 0 0.625rem;
  margin-bottom: 0.5rem;
}

.filter-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  color: var(--muted);
  cursor: pointer;
  user-select: none;
}

.filter-toggle:hover { color: var(--ink); }

.filter-toggle input { accent-color: var(--ink); cursor: pointer; }

.result-count {
  margin-left: auto;
  font-size: 0.75rem;
  color: var(--muted);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

/* Empty state */
.empty-state {
  text-align: center;
  padding: 6rem 0;
  font-family: 'Fraunces', serif;
  font-style: italic;
  font-size: 1.25rem;
  color: var(--muted);
}

/* Gallery section */
.gallery-section {
  padding: 4rem 0 6rem;
}

/* Catalog: filter sidebar to the left of the painting grid. Stacks to a
   single column on tablet/mobile so the filter bar reverts to its
   original full-width sticky horizontal style. */
.catalog-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
  align-items: start;
}

@media (min-width: 901px) {
  .catalog-layout {
    grid-template-columns: minmax(11rem, 13rem) minmax(0, 1fr);
    gap: 3rem;
  }

  /* Sidebar version of .filter-bar — strip the horizontal-bar chrome and
     stick the column to the top under the header. Cap the height to the
     visible viewport so the last filter rows never get hidden behind
     the OS taskbar or browser chrome. The filter-bar element has
     data-lenis-prevent so wheel events scroll inside it instead of
     being intercepted by the page-level Lenis smooth scroller. */
  .catalog-layout > .filter-bar {
    position: sticky;
    top: calc(var(--header-h) + 1rem);
    max-height: calc(100vh - var(--header-h) - 2rem);
    overflow-y: auto;
    padding: 0 0 1rem;
    background: transparent;
    border-top: none;
    border-bottom: none;
    z-index: 5;
    /* Hide the scrollbar so the sidebar reads as a clean column.
       Internal scrolling still works via wheel/touch. */
    scrollbar-width: none;
  }
  .catalog-layout > .filter-bar::-webkit-scrollbar { display: none; }
  .catalog-layout > .filter-bar.is-stuck { box-shadow: none; }

  .catalog-layout > .filter-bar .filter-row {
    flex-direction: column;
    align-items: stretch;
    gap: 0.1875rem;
    padding: 0;
  }
  .catalog-layout > .filter-bar .filter-row + .filter-row {
    margin-top: 0.75rem;
    padding-top: 0.625rem;
    border-top: 1px dashed var(--rule);
  }
  .catalog-layout > .filter-bar .filter-row.search-row {
    border-bottom: 1px solid var(--rule);
    padding: 0 0 0.375rem;
    margin-bottom: 0.125rem;
  }
  .catalog-layout > .filter-bar .filter-collapse {
    padding: 0;
  }
  .catalog-layout > .filter-bar .filter-row + .filter-collapse,
  .catalog-layout > .filter-bar .filter-collapse + .filter-collapse,
  .catalog-layout > .filter-bar .filter-collapse + .filter-row {
    margin-top: 0.625rem;
    padding-top: 0.5rem;
    border-top: 1px dashed var(--rule);
  }
  /* Sidebar summary spans the full column width so the whole row is the
     click target, with the chevron pinned to the right. */
  .catalog-layout > .filter-bar .filter-collapse > summary {
    display: flex;
    width: auto;
    justify-content: flex-start;
    gap: 0.4375rem;
    padding: 0.125rem 0;
  }
  .catalog-layout > .filter-bar .filter-collapse > summary::after {
    margin-left: auto;
  }
  .catalog-layout > .filter-bar .filter-collapse > .filter-options {
    margin-top: 0.5rem;
  }
  .catalog-layout > .filter-bar .filter-search {
    font-size: 0.9375rem;
  }
  .catalog-layout > .filter-bar .filter-label {
    width: auto;
    margin-bottom: 0.25rem;
    font-size: 0.625rem;
  }
  .catalog-layout > .filter-bar .filter-options {
    flex-direction: column;
    gap: 0.0625rem;
  }
  .catalog-layout > .filter-bar .filter-btn {
    text-align: left;
    /* WCAG 2.2 SC 2.5.8: minimum target size 24x24 CSS px on AA. The default
       text height + padding gives us comfortably over that. */
    padding: 0.375rem 0.5rem 0.375rem 0;
    min-height: 24px;
    font-size: 0.8125rem;
    line-height: 1.45;
  }
  .catalog-layout > .filter-bar .filter-toggle {
    min-height: 24px;
    padding: 0.25rem 0;
  }
  /* Horizontal underline doesn't translate to a vertical menu — swap to a
     left tick mark instead. */
  .catalog-layout > .filter-bar .filter-btn.active::after { display: none; }
  .catalog-layout > .filter-bar .filter-btn.active {
    color: var(--ink);
    font-weight: 500;
  }
  .catalog-layout > .filter-bar .filter-btn.active::before {
    content: '';
    position: absolute;
    left: -0.75rem;
    top: 0.25rem;
    bottom: 0.25rem;
    width: 2px;
    background: var(--ink);
  }
  .catalog-layout > .filter-bar .filter-toggle {
    font-size: 0.8125rem;
    line-height: 1.4;
    gap: 0.4375rem;
  }
  .catalog-layout > .filter-bar .result-count {
    margin-left: 0;
    margin-top: 0.375rem;
    font-size: 0.6875rem;
  }

  /* Right column grid: tighter horizontal gap than the home page so 3
     cards fit comfortably in the narrower space next to the sidebar. */
  .catalog-main .grid {
    gap: 4rem 2rem;
  }
}

/* Pull quote */
.quote-section {
  padding: 8rem 0;
  border-top: 1px solid var(--rule);
  text-align: center;
}

.quote-section blockquote {
  font-family: 'Fraunces', serif;
  font-weight: 300;
  font-style: italic;
  font-size: clamp(1.5rem, 3vw, 2.25rem);
  line-height: 1.35;
  max-width: 28ch;
  margin: 0 auto 2.5rem;
  color: var(--ink);
  font-variation-settings: "opsz" 96;
}

.quote-section cite {
  display: block;
  font-family: 'Inter', sans-serif;
  font-style: normal;
  font-size: 0.75rem;
  color: var(--muted);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 2.5rem;
}

/* Footer */
footer {
  padding: 4rem 0 3rem;
  border-top: 1px solid var(--rule);
  font-size: 0.8125rem;
  color: var(--muted);
}

.footer-inner {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 2rem;
}

footer a:hover { color: var(--ink); }

.press-credit {
  font-family: 'Fraunces', serif;
  font-style: italic;
  font-weight: 400;
  font-variation-settings: "opsz" 24;
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
}

.press-amp {
  font-family: 'Caslon Antique', serif;
  font-style: italic;
  font-size: 1.15em;
  letter-spacing: 0.02em;
  vertical-align: -0.04em;
}

/* Painting images: fill the placeholder container when an <img> is present.
   Gradient stays in place underneath as a fallback / lazy-load shimmer. */
.card-image,
.hero-image,
.painting-image {
  overflow: hidden;
}
.card-image,
.hero-image {
  border-radius: 4px;
}
.painting-image {
  border-radius: 6px;
}

/* Cart icon link: lives outside nav <ul>, pulled to the right edge of the
   header by margin-left: auto on the previous sibling pair. */
.cart-icon-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  margin-left: 1.75rem;
  color: var(--ink);
  transition: opacity 0.2s;
}
.cart-icon-link:hover { opacity: 0.55; }
.cart-icon-link.active { opacity: 0.55; }
.cart-icon-link svg {
  width: 22px;
  height: 22px;
  display: block;
  stroke: currentColor;
  fill: none;
}

/* Badge: a small dot with the count, top-right of the bag.
   Hidden when cart is empty (cart.js toggles .has-items). */
.cart-icon-link #cart-count {
  position: absolute;
  top: -3px;
  right: -7px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--bg);
  font-family: 'Inter', sans-serif;
  font-size: 0.625rem;
  font-weight: 500;
  line-height: 16px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  display: none;
  letter-spacing: 0;
}
.cart-icon-link #cart-count.has-items {
  display: block;
}

/* Catalog card: "Print · from $X" line under the dimensions row */
.card .card-price {
  display: block;
  margin-top: 0.375rem;
  font-size: 0.75rem;
  color: var(--ink);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

.hero-cta-row {
  display: flex;
  gap: 2.5rem;
  flex-wrap: wrap;
  align-items: baseline;
}
/* Image fill rules. The catalog/grid pages wrap each <img> in a <picture>
   for webp/jpeg art direction, so we use descendant selectors to match
   the <img> whether it's a direct child or inside <picture>. <picture>
   itself uses display: contents so it's transparent to layout. */
.card-image > picture,
.hero-image > picture {
  display: contents;
}
.card-image img,
.hero-image img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}
/* Detail page: let the image set its own size at natural aspect ratio,
   capped by column width and viewport height. The .painting-image box
   shrinks to the image, so the shadow + frame track the painting edges
   (no letterboxing on portrait pieces in landscape columns). */
.painting-image > picture {
  display: contents;
}
.painting-image img {
  position: static;
  inset: auto;
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 85vh;
  object-fit: initial;
  cursor: zoom-in;
}
.painting-image-wrap:has(.painting-image:not(.is-empty)) {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.painting-image:has(img) {
  width: auto;
  max-width: 100%;
  aspect-ratio: auto;
  background: none;
}
.card-image:has(img) .placeholder-tag,
.hero-image:has(img) .placeholder-tag,
.painting-image:has(img) .placeholder-tag,
.card-image:has(img) .card-mystery,
.painting-image:has(img) .card-mystery {
  display: none;
}

/* Responsive */
@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; gap: 3rem; }
  .grid { grid-template-columns: repeat(2, 1fr); gap: 3.5rem 2rem; }
  .hero { padding: 4rem 0; }
  .section { padding: 4rem 0; }
  .quote-section { padding: 5rem 0; }
  .filter-row { flex-direction: column; align-items: flex-start; gap: 0.5rem; }
  .filter-label { width: auto; }
  .result-count { margin-left: 0; }
}

@media (max-width: 600px) {
  .container { padding: 0 1.5rem; }
  nav ul { gap: 1.25rem; }
  /* Two rows: logo on top by itself; nav + cart inline on the second row.
     The cart used to absolute-position to the top-right corner, which floated
     it above the nav links. margin-left: auto inside the wrapped flex pushes
     it to the end of the nav row instead. */
  .header-inner { flex-wrap: wrap; align-items: center; gap: 0.75rem 1rem; position: relative; }
  .logo { flex: 1 1 100%; }
  .header-inner > nav { margin-left: 0; }
  .cart-icon-link { position: static; margin-left: auto; }
  .grid { grid-template-columns: 1fr; gap: 3rem; }
  .section-header { flex-direction: column; gap: 0.75rem; align-items: flex-start; margin-bottom: 2.5rem; }
}

/* Scroll-driven reveal: opt-in via data-reveal. Element fades and slides up
   as it enters viewport. Stagger with data-reveal-delay="N" (milliseconds). */
[data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.9s cubic-bezier(0.2, 0.8, 0.2, 1),
              transform 0.9s cubic-bezier(0.2, 0.8, 0.2, 1);
}
[data-reveal].is-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* Catalog grid has 304 cards. Per-card fade-in transitions during scroll
   create enough paint work to fight Lenis. Show catalog cards immediately
   instead — Lenis smoothness wins over a one-time entrance animation. */
#gallery-grid .card {
  opacity: 1;
  transform: none;
  transition: none;
}

/* Thematic series (e.g. Geo Blue 1/2/3, Refreshed Lady / Sitting Pretty /
   Walking Beauty) get a `series-start` class on the first member so the
   whole group sits together on one row of the 3-column grid. The data in
   paintings.json is packed so that each series is followed by enough loose
   paintings to fill any trailing cells of its row, which prevents the
   col-3 gap that a 2-pair would otherwise leave when forced to col 1.
   Only applies above the 2-col breakpoint. */
@media (min-width: 901px) {
  #gallery-grid .card.series-start {
    grid-column-start: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Catch-all: kill animation/transition timing on every element so anything
     not explicitly listed below still respects the user's preference. */
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  /* Set the reveal targets to their final visible state so they're not stuck
     at opacity:0 / translateY when transitions are effectively disabled. */
  .card { opacity: 1; transform: none; }
  .card:hover .card-image { transform: none; box-shadow: none; }
  .card:hover .card-image img { filter: none; }
  .hero-image { transform: none !important; will-change: auto; }
  .arrow-link:hover::after { transform: none; }
  [data-reveal] { transform: translateY(0); }
  html { scroll-behavior: auto; }
}

/* Decade chart: counts of paintings per decade, click-through to filter
   the catalog. Lives at the bottom of the catalog page. */
.decade-section {
  padding: 5rem 0 6rem;
  border-top: 1px solid var(--rule);
}
.decade-section-header {
  margin-bottom: 3rem;
}
.decade-section-title {
  font-family: 'Fraunces', serif;
  font-weight: 300;
  font-size: clamp(1.75rem, 3.5vw, 2.5rem);
  font-variation-settings: "opsz" 144;
  letter-spacing: -0.015em;
  margin-bottom: 0.75rem;
}
.decade-section-title em {
  font-style: italic;
  font-weight: 300;
}
.decade-section-lead {
  font-family: 'Fraunces', serif;
  font-style: italic;
  font-weight: 300;
  font-size: 1.0625rem;
  color: var(--muted);
  max-width: 50ch;
  line-height: 1.5;
  font-variation-settings: "opsz" 36;
}
.decade-chart {
  display: grid;
  gap: 1.25rem;
  max-width: 56rem;
}
.decade-row {
  display: grid;
  grid-template-columns: 5rem minmax(0, 1fr) 7rem;
  gap: 1.25rem;
  align-items: center;
  font-size: 0.9375rem;
  color: inherit;
  transition: opacity 0.25s;
}
.decade-row:hover { opacity: 0.65; }
.decade-row-label {
  font-family: 'Inter', sans-serif;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  font-weight: 500;
  letter-spacing: 0.04em;
}
.decade-row-bar-wrap {
  height: 12px;
  position: relative;
  border-bottom: 1px dashed var(--rule);
}
.decade-row-bar {
  position: absolute;
  inset: 0 auto 0 0;
  background: var(--ink);
  width: 0;
  transition: width 1.4s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.decade-row-bar.is-visible {
  width: var(--target-width);
}
.decade-row-count {
  font-family: 'Inter', sans-serif;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  font-size: 0.8125rem;
  text-align: right;
}
@media (max-width: 700px) {
  .decade-row { grid-template-columns: 4rem 1fr 5rem; gap: 0.75rem; }
  .decade-row-count { font-size: 0.75rem; }
}
@media (prefers-reduced-motion: reduce) {
  .decade-row-bar { transition: none; }
}
