/* ------------------------------------------------------------------
   Finn Dickens — one-page editorial layout
   Fixed left sidebar nav, light gray ground, black type, blue links
------------------------------------------------------------------- */

/* Geist (variable, sans) stands in for Neue Montreal; Instrument Serif for
   the display headings. Both self-hosted under fonts/, OFL licensed. */
@font-face {
  font-family: 'Geist';
  src: url('../fonts/geist.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Instrument Serif';
  src: url('../fonts/instrument-serif.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Instrument Serif';
  src: url('../fonts/instrument-serif-italic.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

:root {
  --bg: #e9e9e7;          /* light warm gray ground */
  --ink: #141414;         /* near-black headings & nav */
  --body: #3c3c3c;        /* body copy */
  --muted: #9d9d9b;       /* grayed active nav item / captions */
  --link: #2f93c8;        /* event-link blue */
  --rule: #c6c6c3;        /* hairline rules */

  --side-w: 240px;        /* fixed sidebar width */
  --content-max: 1240px;
  --gutter: clamp(24px, 4vw, 64px);
}

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

html { scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--body);
  font-family: 'Geist', system-ui, sans-serif;
  font-weight: 400;
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

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

/* ---------------- Sidebar ---------------- */

.side {
  position: fixed;
  top: 0; left: 0; bottom: 0;
  width: var(--side-w);
  padding: 56px 24px 40px 48px;
  display: flex;
  flex-direction: column;
  z-index: 10;
}

.side__brand { text-decoration: none; color: var(--ink); }

.side__name {
  font-family: 'Instrument Serif', Georgia, serif;
  font-weight: 400;
  font-size: 30px;
  line-height: 1.05;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  display: block;
}

.side__tag {
  display: block;
  margin-top: 10px;
  font-size: 12.5px;
  letter-spacing: 0.06em;
  color: var(--muted);
  text-transform: uppercase;
}

.side__nav {
  margin-top: 36px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.side__nav a {
  color: var(--ink);
  text-decoration: none;
  font-size: 19px;
  font-weight: 500;
  line-height: 1.3;
  width: fit-content;
  transition: color 0.25s ease;
}

.side__nav a:hover { color: var(--muted); }
.side__nav a.is-active { color: var(--muted); }

.side__nav .side__nav-small {
  margin-top: 16px;
  font-size: 15px;
  font-weight: 400;
}

/* ---------------- Page column ---------------- */

/* Caps the column and centers it in the space right of the sidebar, so on
   wide windows the content pulls in from the right edge instead of hugging it. */
.page {
  max-width: var(--content-max);
  padding: 0 var(--gutter);
  margin-left: max(var(--side-w), calc((100% + var(--side-w) - var(--content-max)) / 2));
}

/* ---------------- Hero ---------------- */

.hero { padding-top: 48px; }

.hero__figure {
  position: relative;
  overflow: hidden;
}

.hero__figure img {
  width: 100%;
  max-height: 88vh;
  object-fit: cover;
  display: block;
}

.hero__grain {
  position: absolute;
  inset: -50%;
  width: 200%;
  height: 200%;
  pointer-events: none;
  opacity: 0.10;
  mix-blend-mode: overlay;
  /* One fine monochrome grain tile, pinned to 140px so specks render at
     1px and stay crisp instead of stretching into blobs. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 140px 140px;
  animation: hero-grain-shift 1.1s steps(4) infinite;
}

@keyframes hero-grain-shift {
  0% { transform: translate(0, 0); }
  25% { transform: translate(-2%, 1.5%); }
  50% { transform: translate(1.5%, -2%); }
  75% { transform: translate(-1%, -1%); }
  100% { transform: translate(2%, 2%); }
}

@media (prefers-reduced-motion: reduce) {
  .hero__grain { animation: none; }
}

.hero__caption {
  margin-top: 14px;
  font-size: 13px;
  letter-spacing: 0.05em;
  color: var(--muted);
  text-transform: uppercase;
}

/* ---------------- Sections ---------------- */

.section { padding-top: clamp(90px, 12vh, 150px); }

.section__title {
  font-family: 'Instrument Serif', Georgia, serif;
  font-weight: 400;
  font-size: clamp(30px, 3.4vw, 44px);
  line-height: 1.1;
  color: var(--ink);
  margin-bottom: clamp(32px, 4vh, 52px);
}

/* ---------------- About ---------------- */

.about__cols {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: clamp(32px, 4vw, 72px);
  align-items: start;
}

.about__text p { margin-bottom: 1.35em; }

.about__lede {
  font-size: 17px;
  line-height: 1.65;
  color: var(--ink);
  font-weight: 400;
}

.about__text strong { color: var(--ink); font-weight: 600; }

.text-link {
  color: var(--link);
  text-decoration: none;
  font-weight: 500;
}
.text-link:hover { text-decoration: underline; }

.about__photos {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.about__photos-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
}
.about__photos-pair img { aspect-ratio: 1 / 1.15; object-fit: cover; }
.about__photos img.img-brighten { filter: grayscale(1) brightness(2.4) contrast(1.05); }

/* ---------------- Work ---------------- */

.work { --work-gap: clamp(24px, 3vw, 48px); --work-per-view: 3; }

.work__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: clamp(32px, 4vh, 52px);
}
.work__head .section__title { margin-bottom: 0; }

.work__arrows { display: flex; gap: 10px; flex-shrink: 0; }

.work__arrow {
  width: 42px;
  height: 42px;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: none;
  color: var(--ink);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  transition: border-color 0.25s ease, color 0.25s ease, opacity 0.25s ease;
}
.work__arrow:hover:not(:disabled) { border-color: var(--ink); }
.work__arrow:disabled { opacity: 0.3; cursor: default; }

/* Horizontal scroll-snap track: native touch swiping on mobile */
.work__track {
  display: flex;
  gap: var(--work-gap);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.work__track::-webkit-scrollbar { display: none; }
.work__track:focus-visible { outline: 1px solid var(--ink); outline-offset: 6px; }

.work__item {
  flex: 0 0 calc((100% - (var(--work-per-view) - 1) * var(--work-gap)) / var(--work-per-view));
  scroll-snap-align: start;
}

.work__dots {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-top: 28px;
}

.work__dot {
  width: 7px;
  height: 7px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--rule);
  cursor: pointer;
  transition: background-color 0.25s ease;
}
.work__dot.is-active { background: var(--ink); }

.work__item h3 {
  color: var(--ink);
  font-size: 20px;
  font-weight: 600;
  line-height: 1.25;
  margin-bottom: 16px;
}

.work__item figure { margin-bottom: 18px; }
.work__item figure img { aspect-ratio: 4 / 3; object-fit: cover; }

/* Tall portraits in a landscape frame only reveal a 50% band of the source,
   so each is aimed to catch Finn's face and the keys together rather than
   defaulting to the centre. */
.work__item figure img.work__img--low { object-position: center 70%; }
.work__item figure img.work__img--high { object-position: center 34%; }

.work__item p { font-size: 15.5px; }

.work__tags {
  list-style: none;
  margin-top: 14px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
}

.work__tags li {
  font-size: 12.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---------------- Shows ---------------- */

.shows__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(28px, 3vw, 56px);
}

.show h3 {
  color: var(--ink);
  font-size: 19px;
  font-weight: 600;
  line-height: 1.3;
  margin-bottom: 12px;
}

.show__date { font-size: 15.5px; margin-bottom: 6px; }

.show__link {
  color: var(--link);
  text-decoration: none;
  font-size: 15.5px;
  word-break: break-word;
}
.show__link:hover { text-decoration: underline; }

.shows__rule {
  border: none;
  border-top: 1px solid var(--rule);
  margin: clamp(48px, 6vh, 72px) 0 clamp(32px, 4vh, 48px);
}

.shows__past-title {
  font-family: 'Instrument Serif', Georgia, serif;
  font-weight: 400;
  font-size: 22px;
  color: var(--ink);
  margin-bottom: 24px;
}

.shows__year {
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 12px;
}

/* Scrollable window over the archive: roughly ten entries (five per column)
   show at once; the rest scroll within the box. The bottom fade hints that
   there is more below without drawing a visible border. */
.shows__past {
  position: relative;
  max-height: 292px;
  overflow-y: auto;
  padding-right: 14px;
  scrollbar-width: thin;
  scrollbar-color: var(--rule) transparent;
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 56px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 56px), transparent);
}
.shows__past::-webkit-scrollbar { width: 4px; }
.shows__past::-webkit-scrollbar-thumb { background: var(--rule); border-radius: 2px; }
.shows__past::-webkit-scrollbar-track { background: transparent; }

/* Lift the fade once the list is scrolled to its end (set from site.js). */
.shows__past.is-at-end {
  -webkit-mask-image: none;
  mask-image: none;
}

.shows__list {
  list-style: none;
  columns: 2;
  column-gap: clamp(32px, 4vw, 64px);
  font-size: 15.5px;
}

/* Two explicit columns, height-balanced by site.js so both sides scroll
   together with the box. */
.shows__cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 clamp(32px, 4vw, 64px);
  align-items: start;
}

.shows__col { list-style: none; font-size: 15.5px; }

.shows__col li {
  margin-bottom: 8px;
}

.shows__list li {
  margin-bottom: 8px;
  break-inside: avoid;
}

/* ---------------- Gallery ---------------- */

.gallery__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(18px, 2.5vw, 36px);
}

/* Anchors the caption overlay. The caption is absolutely positioned, so the
   figure's box is exactly the image's box. */
.gallery__grid figure { position: relative; }

.gallery__frame {
  display: block;
  overflow: hidden;
}

/* Sits slightly overscaled at rest and eases back to a natural fit on hover,
   so the photo pulls away from the viewer without ever uncovering the frame. */
.gallery__grid img {
  aspect-ratio: 1 / 1;
  object-fit: cover;
  transform: scale(1.06);
  transition: transform 0.9s cubic-bezier(0.4, 0, 0.2, 1);
}

.gallery__grid figure:hover img,
.gallery__grid figure:focus-within img {
  transform: scale(1);
}

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

/* Caption rides over the photo on a sheer black wash instead of sitting below it. */
.gallery__grid figcaption {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-end;
  padding: clamp(14px, 1.6vw, 22px);
  background: rgba(0, 0, 0, 0.45);
  color: #fff;
  font-size: 12.5px;
  line-height: 1.4;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  opacity: 0;
  transition: opacity 0.5s ease;
}

.gallery__grid figure:hover figcaption,
.gallery__grid figure:focus-within figcaption {
  opacity: 1;
}

/* Touch devices never hover, so keep the caption legible below the photo. */
@media (hover: none) {
  .gallery__grid figcaption {
    position: static;
    opacity: 1;
    padding: 0;
    margin-top: 8px;
    background: none;
    color: var(--muted);
  }
}

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

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

.contact__lede {
  font-size: clamp(22px, 2.2vw, 30px);
  color: var(--ink);
  font-weight: 500;
  margin-bottom: 20px;
}

.contact__sub { color: var(--muted); font-size: 15px; }

.contact__form {
  max-width: 640px;
  margin-top: clamp(32px, 4vh, 48px);
}

.contact__botcheck {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.contact__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 clamp(24px, 3vw, 40px);
}

.contact__field { margin-bottom: 28px; }

.contact__field label {
  display: block;
  font-size: 12.5px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}

.contact__field input,
.contact__field select,
.contact__field textarea {
  width: 100%;
  border: none;
  border-bottom: 1px solid var(--rule);
  border-radius: 0;
  background: transparent;
  padding: 6px 0 10px;
  font-family: 'Geist', system-ui, sans-serif;
  font-size: 16px;
  color: var(--ink);
  transition: border-color 0.25s ease;
  -webkit-appearance: none;
  appearance: none;
}

.contact__field select {
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='7' fill='none'%3E%3Cpath d='M1 1l4.5 4.5L10 1' stroke='%23141414' stroke-width='1.2'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 2px center;
  padding-right: 22px;
}

.contact__field textarea { resize: vertical; min-height: 120px; }

.contact__field input::placeholder,
.contact__field textarea::placeholder { color: var(--muted); opacity: 0.7; }

.contact__field input:focus,
.contact__field select:focus,
.contact__field textarea:focus {
  outline: none;
  border-bottom-color: var(--ink);
}

.contact__actions {
  display: flex;
  align-items: center;
  gap: 24px;
  flex-wrap: wrap;
}

.contact__submit {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  border: 1px solid var(--ink);
  border-radius: 999px;
  background: none;
  color: var(--ink);
  font-family: 'Geist', system-ui, sans-serif;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0.03em;
  padding: 12px 28px;
  cursor: pointer;
  transition: background-color 0.25s ease, color 0.25s ease, opacity 0.25s ease;
}
.contact__submit:hover:not(:disabled) { background: var(--ink); color: var(--bg); }
.contact__submit:disabled { opacity: 0.45; cursor: default; }
.contact__submit i { font-style: normal; }

.contact__status { font-size: 15px; color: var(--muted); }
.contact__status.is-error { color: #a4482f; }
.contact__status.is-sent { color: var(--ink); }

.contact__alt {
  margin-top: clamp(32px, 4vh, 44px);
  font-size: 15px;
  color: var(--muted);
}

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

.footer {
  display: flex;
  justify-content: space-between;
  border-top: 1px solid var(--rule);
  margin-top: clamp(90px, 12vh, 150px);
  padding: 24px 0 40px;
  font-size: 13px;
  color: var(--muted);
}

/* ---------------- Swipe hint (mobile only) ---------------- */

/* Small nudging "Swipe →" cue on the mobile carousels; site.js hides it
   after the visitor's first swipe of that track. */
.swipe-hint {
  display: none;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  transition: opacity 0.4s ease;
}
.swipe-hint i { font-style: normal; display: inline-block; }
.swipe-hint.is-hidden { opacity: 0; }

@media (max-width: 620px) {
  .swipe-hint { display: inline-flex; }
  .swipe-hint--gallery { margin: -18px 0 18px; }
  .swipe-hint i { animation: hint-nudge 1.4s ease-in-out infinite; }
}

@keyframes hint-nudge {
  0%, 100% { transform: translateX(0); }
  50% { transform: translateX(5px); }
}

@media (prefers-reduced-motion: reduce) {
  .swipe-hint i { animation: none; }
}

/* ---------------- Reveal on scroll ---------------- */

.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}
.reveal.is-in {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* ---------------- Responsive ---------------- */

@media (max-width: 1080px) {
  .work { --work-per-view: 2; }
  .shows__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .gallery__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  .side {
    position: static;
    width: auto;
    padding: 40px var(--gutter) 0;
  }
  .side__nav {
    margin-top: 32px;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 10px 22px;
  }
  .side__nav .side__nav-small {
    margin-top: 0;
    font-size: 19px;
    font-weight: 500;
  }

  .page { margin-left: 0; }
  .hero { padding-top: 40px; }

  .about__cols { grid-template-columns: 1fr; }
  .shows__list { columns: 1; }
  /* Single column on mobile; site.js also drops the counter-scroll here. */
  .shows__cols { grid-template-columns: 1fr; }
}

@media (max-width: 620px) {
  .shows__grid { grid-template-columns: 1fr; }

  /* One card at a time; swipe the track instead of tapping arrows */
  .work { --work-per-view: 1; }
  .work__arrows { display: none; }
  .work__head { margin-bottom: 28px; }

  .contact__row { grid-template-columns: 1fr; gap: 0; }

  /* Work cards peek the next one in from the edge so the swipe is obvious. */
  .work__item { flex-basis: 86%; }

  /* Gallery becomes a center-snapping swipe carousel that bleeds to the
     screen edges; neighbors peek in from both sides. site.js drifts each
     card's scale/lift by its distance from center for the floaty feel.
     Mandatory snapping so a swipe can never settle between photos. */
  .gallery__grid {
    display: flex;
    gap: 18px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    margin: 0 calc(-1 * var(--gutter));
    padding: 10px calc((100vw - 74vw) / 2) 4px;
  }
  .gallery__grid::-webkit-scrollbar { display: none; }

  .gallery__grid figure {
    flex: 0 0 74vw;
    scroll-snap-align: center;
  }

  /* The float transform lands on the frame. No CSS transition here: site.js
     animates it every frame with its own damping, and a transition on top
     of that reads as stutter. */
  .gallery__frame {
    will-change: transform;
  }
}
