/* ---------------------------------------------------------------------------
   Tom Bell - studio site
   Layout modelled on a dense editorial photo grid: a fixed difference-blended
   nav over two interchangeable views (large feed / thumbnail index), with a
   click-to-zoom lightbox and a light/dark toggle.
   --------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

:root {
  /* Narrowest a grid thumbnail may get (width/height). Three works are far
     taller than this; they are centre-cropped in the grid only, so the rows
     stay even. The feed and lightbox always show the whole work. */
  --thumb-min-ar: 0.6;
  --page-mg: 16px;
  --row-gap: 40px;
  --grid-pd: 50px;
  --cols: 8;
}
@media screen and (min-width: 390px) {
  :root {
    --page-mg: calc(16px + (20 - 16) * (100vw - 390px) / (1920 - 390));
    --row-gap: calc(40px + (80 - 40) * (100vw - 390px) / (1920 - 390));
    --grid-pd: calc(50px + (100 - 50) * (100vw - 390px) / (1920 - 390));
  }
}

/* 1rem = 10px at 1920px wide, and again at 390px, so type scales with the page
   exactly the way the grid does. */
html {
  font-size: 0.5208333333vw;
  -webkit-tap-highlight-color: transparent;
}
@media (max-width: 768px) { html { font-size: 2.5641025641vw; } }

body {
  margin: 0;
  min-width: 360px;
  background: #fff;
  color: #000;
  overflow: hidden;
  font-family: "Source Serif 4", Georgia, "Times New Roman", serif;
  font-size: 1.6rem;
  line-height: 1.2;
  -webkit-font-smoothing: antialiased;
  transition: background-color .5s, color .5s;
}
body.dark { background: #000; color: #fff; }

p, h1, h2, h3 { margin: 0; font-size: inherit; font-weight: inherit; }
img { vertical-align: middle; user-select: none; -webkit-user-drag: none; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; margin: 0; }

.wrapper { height: 100vh; height: 100svh; overflow-x: hidden; overflow-y: scroll; }

/* Tiles carry a neutral ground so the grid holds its shape while images load. */
.tile { background: #e5e5e5; transition: background-color .5s, opacity .5s; }
body.dark .tile { background: #1a1a1a; }
.tile img { width: 100%; height: 100%; object-fit: cover; display: block; opacity: 0; transition: opacity .5s; }
.tile img.loaded { opacity: 1; }

/* --- Nav ------------------------------------------------------------------
   mix-blend-mode: difference keeps the nav legible over any image beneath it,
   in either colour mode, without a scrim. */
nav {
  position: fixed; inset: 0;
  display: flex; flex-flow: column; justify-content: space-between;
  z-index: 7; pointer-events: none;
  mix-blend-mode: difference; color: #fff;
  font-size: 1.75rem;
  opacity: 0; transition: opacity .6s;
}
nav.ready { opacity: 1; }

.nav__top, .nav__bottom {
  display: grid; grid-template-columns: repeat(16, 1fr);
  column-gap: var(--page-mg); padding: 0 var(--page-mg);
}
.nav__top { padding-top: 15px; padding-bottom: 15px; }
.nav__bottom { padding-bottom: 16px; }

.nav__top__left  { grid-column: 1 / 6; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nav__top__name  { grid-column: 6 / 11; font-weight: 600; }
/* Hidden rather than removed, so the rest of the row stays put. */
body.about-open .nav__top__name { visibility: hidden; }
.nav__top__about { grid-column: 13 / 15; }
.nav__top__view  { grid-column: 15 / 17; display: flex; justify-content: flex-end; }

/* The hyphen separates collection from title, so no extra indent here. */
.nav__top__left .dim { opacity: .45; }

.nav__bottom__modes { grid-column: -3 / -1; display: flex; justify-content: flex-end; column-gap: 10px; }
.nav__bottom__count { grid-column: 1 / 5; }
#zoomCount:empty { display: none; }

.btn { pointer-events: auto; cursor: pointer; margin: -10px; padding: 10px; transition: opacity .3s; }
@media (hover: hover) { .btn:hover { opacity: .5; } }
.mode.is-active { opacity: .3; pointer-events: none; }

@media (max-width: 768px) {
  /* Three equal slots in a 6-column grid leave too little room for the longest
     label, so the top row becomes a simple flex row on small screens. */
  .nav__top { display: flex; justify-content: space-between; align-items: baseline; column-gap: 12px; }
  .nav__bottom { grid-template-columns: repeat(6, 1fr); }
  .nav__bottom__count { grid-column: 1 / 4; }
  .nav__top__left { display: none; }
  /* No room for both on a phone, so while zoomed the collection takes the
     place of the artist name. */
  body.zooming .nav__top__left { display: block; overflow: hidden; text-overflow: ellipsis; }
  body.zooming .nav__top__name { display: none; }
  .nav__top > div { white-space: nowrap; }
  /* The colour toggle is a minor control; at nav size it took nearly a third
     of a phone screen. The tap target stays full size via .btn's padding. */
  .nav__bottom__modes { font-size: 1.05rem; column-gap: 6px; }
}

/* --- Index view (dense grid) ---------------------------------------------- */
.index {
  display: grid;
  grid-template-columns: repeat(var(--cols), 1fr);
  column-gap: var(--page-mg);
  row-gap: var(--row-gap);
  align-items: flex-start;        /* rows share a top baseline, heights vary */
  padding: var(--grid-pd) var(--page-mg);
}
@media (max-width: 1440px) { :root { --cols: 7; } }
@media (max-width: 1024px) { :root { --cols: 6; } }
@media (max-width: 768px)  { :root { --cols: 4; } }
@media (max-width: 544px)  { :root { --cols: 3; } }

.index__thumb { cursor: pointer; width: 100%; }
.index__thumb .tile {
  position: relative; width: 100%;
  aspect-ratio: var(--ar, 1);                         /* fallback */
  aspect-ratio: max(var(--ar, 1), var(--thumb-min-ar));
}

/* --- Feed view (large sequential) -----------------------------------------
   Each work is sized from its own aspect ratio - capped at 75vh tall and at the
   page width - so landscape and portrait works both sit snugly in the column
   with an even gap and no overlap. */
.feed { display: flex; flex-flow: column; align-items: center; padding: var(--grid-pd) 0 15vh; }

.feed__item { position: relative; width: 100%; display: flex; justify-content: center; }
.feed__item + .feed__item { margin-top: var(--feed-gap); }

/* --ar is the work's width/height, set on the item in main.js. */
.feed__figure {
  width: min(calc(100% - 2 * var(--page-mg)), calc(var(--feed-h) * var(--ar, 1)));
  margin: 0;
}
.feed__figure .tile { width: 100%; height: auto; aspect-ratio: var(--ar, 1); background: none; cursor: pointer; }
.feed__figure .tile img { width: 100%; height: 100%; object-fit: contain; }

:root { --feed-h: 75vh; --feed-gap: 12vh; }
@media (max-width: 768px) { :root { --feed-h: 62vh; --feed-gap: 7vh; } }
/* On a short or wide window 75vh leaves no room to breathe between works. */
@media (max-aspect-ratio: 4/3) and (min-width: 769px) { :root { --feed-h: 68vh; } }

.caption {
  display: flex; flex-flow: column; row-gap: 2px;
  margin: 14px 0 0;
  font-size: 1.4rem; line-height: 1.4;
  max-width: 46em;
}
.caption:empty { display: none; }
.caption__line { opacity: .45; }
.caption a { text-decoration: underline; text-underline-offset: 2px; transition: opacity .3s; }
@media (hover: hover) { .caption a:hover { opacity: .6; } }
.zoom__caption a { pointer-events: auto; }

/* --- About overlay -------------------------------------------------------- */
.about { position: fixed; inset: 0; z-index: 4; visibility: hidden; overflow-y: auto; }
.about.open { visibility: visible; }
.about__bg {
  position: fixed; inset: 0;
  background: rgba(255,255,255,.9);
  backdrop-filter: blur(17px); -webkit-backdrop-filter: blur(17px);
  opacity: 0; transition: opacity .4s;
}
body.dark .about__bg { background: rgba(0,0,0,.9); }
.about.open .about__bg { opacity: 1; }

.about__inner {
  position: relative;
  display: grid; grid-template-columns: repeat(16, 1fr);
  column-gap: var(--page-mg); padding: 0 var(--page-mg);
  min-height: 100%;
  opacity: 0; transition: opacity .4s .1s;
}
.about.open .about__inner { opacity: 1; }

.about__col { grid-column: 4 / 11; padding-top: 63px; padding-bottom: 40px; }
.about__heading {
  margin: 0 0 24px;
  font-size: 2.4rem; line-height: 1.4; font-weight: 400;
  display: flex; flex-flow: column;
}
.about__dates { opacity: .45; }
.about__text { font-size: 2.4rem; line-height: 1.5; text-indent: 2.5em; max-width: 34em; }
.about__contact { grid-column: 14 / 17; padding-top: 63px; }
.about__contact__links { flex-flow: column; row-gap: 4px; }
.about__header { font-family: Inter, Helvetica, Arial, sans-serif; font-size: 1.5rem; opacity: .4; }
.about__contact__links { display: flex; margin-top: 8px; font-family: Inter, Helvetica, Arial, sans-serif; font-size: 1.5rem; }
.about__contact__links a { transition: opacity .3s; }
@media (hover: hover) { .about__contact__links a:hover { opacity: .5; } }

.about__lists {
  grid-column: 4 / 15;
  align-self: start;
  columns: 2; column-gap: var(--page-mg);
  margin-top: 56px; padding-bottom: 80px;
  font-family: Inter, Helvetica, Arial, sans-serif; font-size: 1.5rem;
}
.about__list { break-inside: avoid; margin-bottom: 32px; }
.about__list h3 { opacity: .4; margin-bottom: 10px; }
.about__list ul { list-style: none; margin: 0; padding: 0; }
.about__list li { line-height: 1.85; }
.about__list a { text-decoration: underline; text-underline-offset: 2px; transition: opacity .3s; }
@media (hover: hover) { .about__list a:hover { opacity: .5; } }
.about__list li.paired { display: grid; grid-template-columns: 7em 1fr; column-gap: var(--page-mg); }

@media (max-width: 1024px) {
  .about__inner { grid-template-columns: repeat(6, 1fr); }
  .about__col, .about__lists, .about__contact { grid-column: 1 / -1; }
  .about__contact { padding-top: 0; margin-top: 40px; margin-bottom: 40px; }
  .about__lists { columns: 1; margin-top: 36px; padding-bottom: 48px; }
  .about__contact { margin-top: 40px; padding-top: 0; }
  .about__heading, .about__text { font-size: 2.6rem; }
}

/* --- Zoom / lightbox ------------------------------------------------------ */
.zoom { position: fixed; inset: 0; z-index: 5; visibility: hidden; }
.zoom.open { visibility: visible; }
.zoom__bg { position: absolute; inset: 0; background: #fff; opacity: 0; transition: opacity .3s; }
body.dark .zoom__bg { background: #000; }
.zoom.open .zoom__bg { opacity: 1; }

.zoom__figure {
  position: absolute; inset: 0; margin: 0;
  display: flex; flex-flow: column; align-items: center; justify-content: center;
  padding: 7vh var(--page-mg);
  opacity: 0; transition: opacity .3s;
}
.zoom.open .zoom__figure { opacity: 1; }
/* With a w-descriptor srcset the intrinsic size is density-corrected, so the
   image must be sized explicitly or it lays out at a fraction of its size.
   --zar is the work's width/height, set in main.js. */
.zoom__figure img {
  height: min(74vh, calc(92vw / var(--zar, 1)));
  width: auto; max-width: 92vw;
  display: block;
}
.zoom__caption { align-items: center; text-align: center; }

.zoom__cursor {
  position: absolute; top: 0; left: 0; margin-left: 19px;
  font-size: 1.4rem; pointer-events: none;
  mix-blend-mode: difference; color: #fff;
  transform: translate(-200px, -200px); opacity: 0;
}
.zoom.open .zoom__cursor { opacity: 1; }
.zoom[data-at="first"] .zoom__cursor[data-dir="prev"],
.zoom[data-at="last"]  .zoom__cursor[data-dir="next"] { opacity: 0; }
@media (hover: none) { .zoom__cursor { display: none; } }

/* --- Intro splash --------------------------------------------------------- */
.intro {
  position: fixed; inset: 0; z-index: 8;
  display: flex; align-items: center; justify-content: center;
  background: #fff;
  transition: opacity .7s, visibility .7s;
}
body.dark .intro { background: #000; }
.intro.done { opacity: 0; visibility: hidden; }
.intro__title {
  display: flex; flex-flow: column; align-items: center; row-gap: 14px;
  font-size: 30px; line-height: 1.2; white-space: nowrap; text-align: center;
}
.intro__name { font-weight: 600; }
.intro__dates { font-size: .62em; letter-spacing: .14em; opacity: .5; }
@media (max-width: 768px) {
  .intro__title { font-size: 24px; row-gap: 11px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .01ms !important; }
}
