/* ==========================================================================
   catalog.css — the white, Futura side of the site
   Serves the catalogue (front page) and the about page.

   Deliberately standalone: it does NOT load site.css. These pages are white
   and light-only by design, where the rest of the site is warm and follows the
   system dark mode. Keeping the two apart means neither can drift into the
   other when one gets edited.

   Everything is set in Futura. It is installed on iPad and macOS, which is
   where this page gets shown; elsewhere the stack falls through to the closest
   geometric sans available.
   ========================================================================== */

:root {
  --font: Futura, "Futura PT", "Futura Std", "Century Gothic", "URW Gothic",
          Jost, "Avenir Next", Avenir, "Trebuchet MS", sans-serif;

  --paper: #ffffff;
  --tile: #fcfcfb;
  --ink: #111111;
  --ink-soft: #5c5c5a;
  --ink-faint: #8f8f8c;
  --rule: #e7e7e3;
  --sold: #c0261c;

  --gutter: clamp(1.25rem, 5vw, 4rem);
  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);

  /* The viewer fade. Kept deliberately slow, and mirrored by FADE_MS in
     catalog.js — change one and you must change the other. */
  --fade: 420ms;

  /* How long a thumbnail takes to grow under the cursor. Slow on purpose:
     the artwork should ease up, not snap. */
  --hover-ease-ms: 900ms;

  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);

  /* Light only. No dark-mode block anywhere in this file — that is the point. */
  color-scheme: light;
}

/* --- Reset ---------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  padding-left: var(--safe-l);
  padding-right: var(--safe-r);
}

h1, h2, p, dl, dd, figure { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
img { display: block; max-width: 100%; height: auto; }

a { color: inherit; }

/* Present for screen readers, absent on screen — for labels a sighted person
   gets from context but a screen reader needs spelled out. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: -9999px;
}
.skip-link:focus {
  left: var(--gutter);
  top: 0.5rem;
  z-index: 10;
  background: var(--ink);
  color: var(--paper);
  padding: 0.5rem 0.9rem;
  text-decoration: none;
}

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

.wrap {
  width: 100%;
  max-width: 78rem;
  margin: 0 auto;
  padding-inline: var(--gutter);
}

/* --- Masthead -------------------------------------------------------------
   Kept to a wordmark, one line of context, and the links off to the rest of
   the site. The artworks are the page; this is just the letterhead.
   -------------------------------------------------------------------------- */

.masthead {
  padding-top: calc(var(--safe-t) + clamp(2.5rem, 7vw, 5rem));
  padding-bottom: clamp(2rem, 5vw, 3.5rem);
}

.masthead__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem 2rem;
}

.wordmark {
  font-size: clamp(1.25rem, 3.5vw, 1.75rem);
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
}

.masthead__line {
  margin-top: 0.55rem;
  font-size: 0.8125rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* Six links need about 450px in one row, which is wider than a phone. Without
   the wrap the nav pushes the whole page sideways and every screen gets a
   horizontal scrollbar — on the auction page that means the countdown and the
   leading bidder sit half off the edge. */
.nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

@media (max-width: 30rem) {
  .nav { gap: 0.45rem 1rem; letter-spacing: 0.12em; }
}

.nav a {
  text-decoration: none;
  padding-block: 0.25rem;
  border-bottom: 1px solid transparent;
}
.nav a:hover,
.nav a[aria-current="page"] { border-bottom-color: var(--ink); }

/* --- The catalogue --------------------------------------------------------
   minmax(230px, 1fr): the source images top out around 230 px wide, so the
   columns are sized to sit close to native resolution rather than blowing the
   artwork up into mush. Replace the files in /assets/img/art/ with larger
   scans and this number can go up.
   -------------------------------------------------------------------------- */

.catalog {
  padding-bottom: clamp(3rem, 8vw, 6rem);
}

.pieces {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: clamp(2rem, 4vw, 3.25rem) clamp(1.5rem, 3vw, 2.5rem);
}

.piece__hit {
  display: block;
  text-decoration: none;
  cursor: pointer;
}

.piece__media {
  display: grid;
  place-items: center;
  height: clamp(240px, 32vw, 300px);
  padding: 1rem;
  background: var(--tile);
  border: 1px solid var(--rule);
  overflow: hidden; /* the hover scale is clipped by the tile, not the neighbours */
}

.piece__media img {
  transition: transform var(--hover-ease-ms) var(--ease);
}

.piece__hit:hover .piece__media img,
.piece__hit:focus-visible .piece__media img {
  transform: scale(1.1);
}

/* min-height/min-width 0: a grid item's automatic minimum size is its intrinsic
   size, so without these the tall pieces refuse to shrink and spill out of the
   tile over the caption below. */
.piece__media img {
  max-width: 100%;
  max-height: 100%;
  min-width: 0;
  min-height: 0;
  width: auto;
  height: auto;
  object-fit: contain;
}

/* Titles run from one word to four lines. Letting the caption fill the cell and
   pushing the specs to the bottom keeps every size/price line in a row level. */
.piece,
.piece figure {
  height: 100%;
}

.piece figure,
figcaption {
  display: flex;
  flex-direction: column;
}

figcaption {
  flex: 1;
  padding-top: 1rem;
}

.piece__spec {
  margin-top: auto;
}

.piece__title {
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: 0.01em;
}

.piece__spec {
  display: grid;
  grid-template-columns: 2.75rem 1fr;
  gap: 0.2rem 0.75rem;
  padding-top: 0.6rem;
  font-size: 0.8125rem;
}

.piece__spec dt {
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding-top: 0.2em;
}

.piece__spec dd {
  color: var(--ink-soft);
}

.piece__spec em {
  display: block;
  font-style: normal;
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  color: var(--ink-faint);
}

.is-sold s {
  text-decoration-thickness: 1px;
  color: var(--ink-faint);
}

.is-sold em {
  display: inline;
  margin-left: 0.4rem;
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sold);
  font-weight: 500;
}

/* --- Work page (films) ------------------------------------------------------
   Two columns of 16:9 players on a desktop, one on a phone. Nothing preloads
   until a visitor presses play, so the page stays light however many go here.
   -------------------------------------------------------------------------- */

.work {
  padding-bottom: clamp(3rem, 8vw, 6rem);
}

.films {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 26rem), 1fr));
  gap: clamp(2rem, 4vw, 3.25rem) clamp(1.5rem, 3vw, 2.5rem);
}

.film__frame {
  width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--tile);
  border: 1px solid var(--rule);
}

.film__frame video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
}

.film__title {
  margin: 0;
  padding-top: 0.9rem;
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* --- Workshop page ----------------------------------------------------------
   A plain gallery: no titles, no captions, nothing under the pictures. The
   photographs reuse .piece__hit and .piece__media so the hover growth and the
   viewer behave exactly as they do on the catalogue.
   -------------------------------------------------------------------------- */

.workshop {
  padding-bottom: clamp(3rem, 8vw, 6rem);
}

.call {
  margin: 0;
  font-size: clamp(0.8125rem, 2.2vw, 1rem);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1.5;
}

.call--foot {
  margin-top: clamp(2.5rem, 6vw, 4rem);
  padding-top: clamp(1.5rem, 3vw, 2rem);
  border-top: 1px solid var(--rule);
  color: var(--ink-soft);
}

/* Dials the number. Underlined rather than left bare, because uppercase
   letterspaced text gives no other clue that it can be tapped. */
.call--foot a {
  display: inline-block;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  /* Vertical padding is here for the thumb, not the look: the line itself is
     only about 20px tall, which is a mean target for the one thing on this
     page a visitor is meant to tap. */
  padding: 0.6em 0 0.4em;
  transition: border-color 0.25s var(--ease);
}

.call--foot a:hover,
.call--foot a:focus-visible {
  border-bottom-color: currentColor;
}

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
  margin-top: clamp(2rem, 5vw, 3.25rem);
}

/* Square tiles keep 50 photographs of wildly different shapes reading as one
   grid; the pictures themselves are never cropped, only letterboxed. */
.gallery .piece__media {
  height: auto;
  aspect-ratio: 1;
  padding: 0.75rem;
}

/* Albums. The first one usually has no title and sits straight under the
   call; every titled one after it opens with a small heading in the same
   voice as the film titles. An empty album is kept in the page but hidden. */
.album[hidden] { display: none; }

.album__title {
  margin: clamp(2.5rem, 6vw, 4rem) 0 0;
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.album__title + .gallery {
  margin-top: 1rem;
}

/* --- About page ------------------------------------------------------------
   Portrait beside the bio, collapsing to a single column on a phone. The
   measure is held narrower than the catalogue's grid because this is the one
   page on the white side of the site with running prose on it.
   -------------------------------------------------------------------------- */

.about {
  padding-bottom: clamp(3rem, 8vw, 6rem);
}

/* The page sits in the same .wrap as every other page, so the masthead and
   footer line up site-wide; the reading column is held in by the content
   itself rather than by a narrower wrap. */
.about__grid,
.about__contact {
  max-width: 58rem;
}

.about__grid {
  display: grid;
  grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
  gap: clamp(1.75rem, 5vw, 3.5rem);
  align-items: start;
}

@media (max-width: 46rem) {
  .about__grid { grid-template-columns: minmax(0, 1fr); }
  .about__portrait { max-width: 20rem; }
}

.about__portrait {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border: 1px solid var(--rule);
  background: var(--tile);
}

.about__bio p {
  margin: 0 0 1.1rem;
  max-width: 36rem;
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--ink-soft);
}

.about__bio p:last-child { margin-bottom: 0; }

.about__bio p:first-child {
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--ink);
}

/* --- Contact list ---------------------------------------------------------- */

.about__contact {
  margin-top: clamp(2.5rem, 6vw, 4rem);
  padding-top: clamp(1.5rem, 3vw, 2rem);
  border-top: 1px solid var(--rule);
}

.about__label {
  margin: 0 0 1rem;
  font-size: 0.625rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.contact-list {
  display: grid;
  gap: 0.1rem;
  max-width: 34rem;
}

.contact-list a,
.contact-list span.contact-row {
  display: grid;
  grid-template-columns: 7rem minmax(0, 1fr);
  gap: 0.75rem;
  align-items: baseline;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
  font-size: 0.875rem;
}

.contact-list a:hover { background: var(--tile); }

.contact-list dt,
.contact-list .contact-key {
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.contact-list .contact-val { color: var(--ink); }

/* --- The viewer -----------------------------------------------------------
   A square panel over a blurred page. The dialog fills the viewport so that
   any click that is not on the panel is a click on the backdrop, which is what
   catalog.js tests for to close it.
   -------------------------------------------------------------------------- */

.has-lightbox {
  overflow: hidden; /* no scrolling the catalogue behind the viewer */
}

.lightbox {
  width: 100%;
  max-width: 100%;
  height: 100%;
  max-height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: hidden;

  display: grid;
  place-items: center;

  opacity: 0;
  transition: opacity var(--fade) var(--ease);
}

.lightbox.is-open { opacity: 1; }

/* backdrop-filter on ::backdrop is what blurs the catalogue underneath. */
.lightbox::backdrop {
  background: rgba(255, 255, 255, 0.72);
  -webkit-backdrop-filter: blur(0px);
  backdrop-filter: blur(0px);
  opacity: 0;
  transition: opacity var(--fade) var(--ease),
              backdrop-filter var(--fade) var(--ease),
              -webkit-backdrop-filter var(--fade) var(--ease);
}

.lightbox.is-open::backdrop {
  -webkit-backdrop-filter: blur(18px) saturate(1.1);
  backdrop-filter: blur(18px) saturate(1.1);
  opacity: 1;
}

.lightbox__panel {
  position: relative;
  width: min(86vmin, 820px);
  aspect-ratio: 1;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: clamp(1.25rem, 3vmin, 2.25rem);
  background: var(--paper);
  border: 1px solid var(--rule);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.14);

  transform: scale(0.94);
  transition: transform var(--fade) var(--ease);
}

.lightbox.is-open .lightbox__panel { transform: scale(1); }

/* Focus is parked here on open; it is a container, not a control, so it must
   opt out of the global :focus-visible ring as well as plain :focus. */
.lightbox__panel:focus,
.lightbox__panel:focus-visible { outline: none; }

.lightbox__stage {
  flex: 1;
  min-height: 0;
  display: grid;
  place-items: center;
}

/* Fills the panel rather than sitting at its natural size: the point of the
   viewer is to see the work big. The source images are small, so anything
   taller than about 430px is an upscale — replace the files in
   /assets/img/art/ with full-resolution scans and this gets sharper for free. */
.lightbox__img {
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
  object-fit: contain;
}

.lightbox__caption {
  flex: none;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 1rem;
  padding-right: 2rem; /* clear of the close button */
}

.lightbox__title {
  font-size: 0.9375rem;
  font-weight: 500;
}

.lightbox__spec {
  font-size: 0.8125rem;
  color: var(--ink-soft);
}

.lightbox__close {
  position: absolute;
  top: 0.35rem;
  right: 0.5rem;
  width: 2.25rem;
  height: 2.25rem;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: none;
  font-family: inherit;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--ink-faint);
  cursor: pointer;
}

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

/* Reduced motion takes away the animation, not the feedback. The hover scale
   still happens, it just happens instantly instead of easing — cancelling it
   outright left the thumbnails looking dead to the cursor on any machine with
   Windows' animation effects switched off. */
/* The thumbnail growth is deliberately left running here. It is small, it only
   happens under the cursor, and it is the effect this site actually wants —
   cancelling it is what made the thumbnails look dead on a machine with
   Windows' animation effects switched off. The viewer's fade and zoom, which
   take over the whole screen, still go instant. */
@media (prefers-reduced-motion: reduce) {
  .lightbox,
  .lightbox::backdrop,
  .lightbox__panel {
    transition: none;
  }
}

/* --- Footer ---------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--rule);
  padding-top: 1.5rem;
  padding-bottom: calc(var(--safe-b) + 2.5rem);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.site-footer .wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 2rem;
  justify-content: space-between;
}

.site-footer a { text-decoration: none; border-bottom: 1px solid var(--rule); }
.site-footer a:hover { border-bottom-color: var(--ink); }

/* --- Offline notice --------------------------------------------------------
   site.js injects this on every page, so the catalogue has to style it too.
   -------------------------------------------------------------------------- */

.offline-note {
  position: fixed;
  left: 50%;
  bottom: calc(var(--safe-b) + 1rem);
  transform: translate(-50%, 150%);
  background: var(--ink);
  color: var(--paper);
  padding: 0.5rem 1rem;
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  transition: transform 0.3s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.offline-note.is-shown { transform: translate(-50%, 0); }

@media (prefers-reduced-motion: reduce) {
  .offline-note { transition: none; }
}

/* --- Print -----------------------------------------------------------------
   A price list gets printed and handed over. Worth the dozen lines.
   -------------------------------------------------------------------------- */

@media print {
  .nav, .offline-note, .skip-link { display: none; }

  body { font-size: 11pt; }

  .pieces {
    grid-template-columns: repeat(3, 1fr);
    gap: 1.25rem;
  }

  .piece {
    break-inside: avoid;
  }

  .piece__media {
    height: 170px;
    background: none;
  }
}

/* --- Live auction strip -----------------------------------------------------
   Sits above a page's list while an auction is running, and is removed the
   moment it closes — the page underneath is never left carrying a dead notice.
   -------------------------------------------------------------------------- */

#auction-banner[hidden] { display: none; }

.abanner {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: clamp(0.75rem, 2vw, 1.5rem);
  margin-bottom: clamp(2rem, 4vw, 3rem);
  padding: 0.75rem 1rem 0.75rem 0.75rem;
  border: 1px solid var(--ink);
  text-decoration: none;
  color: inherit;
  transition: background var(--hover-ease-ms) var(--ease);
}

.abanner:hover { background: var(--tile); }

.abanner__media {
  display: block;
  width: clamp(48px, 9vw, 72px);
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--tile);
}

.abanner__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.abanner__body { display: grid; gap: 0.15rem; min-width: 0; }

.abanner__tag {
  font-size: 0.5625rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--sold);
}

.abanner__title {
  font-size: 0.9375rem;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.abanner__facts {
  font-size: 0.75rem;
  color: var(--ink-soft);
}

.abanner__clock { display: grid; gap: 0.1rem; text-align: right; }

.abanner__label {
  font-size: 0.5625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.abanner__time {
  font-size: clamp(0.9375rem, 2.4vw, 1.25rem);
  font-weight: 500;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.abanner.is-closing .abanner__time,
.abanner.is-closing .abanner__label { color: var(--sold); }

.abanner__cta {
  padding: 0.7rem 1rem;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--paper);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
}

.abanner:hover .abanner__cta { background: var(--sold); border-color: var(--sold); }

/* On a phone the clock and the button move under the title rather than
   squeezing four columns into 360px. */
@media (max-width: 42rem) {
  .abanner {
    grid-template-columns: auto minmax(0, 1fr);
    row-gap: 0.85rem;
  }
  .abanner__clock { grid-column: 1 / 2; text-align: left; }
  .abanner__cta { grid-column: 2 / 3; text-align: center; }
}
