/* caricaburu.com
 *
 * One stylesheet, replacing Bootstrap, the inherited theme's style.css, animsition, magnific
 * popup, simpletextrotator and the rest. The grid that Isotope used to compute in JavaScript
 * after every image loaded is now plain CSS, because the server knows each painting's
 * proportions and writes them into the markup.
 */

:root {
  --ink: #1a1a1a;
  --ink-soft: #5a5a5a;
  --ink-faint: #8a8a8a;
  --paper: #ffffff;
  --rule: #e4e4e4;
  --accent: #1a1a1a;

  --measure: 34rem;
  --gutter: clamp(1rem, 3vw, 2.5rem);
  --header-height: 4.5rem;

  --sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
  --serif: Georgia, "Times New Roman", serif;
}

/* The site commits to a light presentation: these are paintings, and a dark canvas would
   change how every one of them reads. Only the chrome softens in dark mode. */
@media (prefers-color-scheme: dark) {
  :root {
    --ink: #f0f0f0;
    --ink-soft: #b4b4b4;
    --ink-faint: #8a8a8a;
    --paper: #141414;
    --rule: #2e2e2e;
    --accent: #ffffff;
  }
}

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

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

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

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

a { color: inherit; }

/* Cross-document view transitions bring back the page fade that Animsition provided, without
   the library or the single-page app it depended on. Browsers that do not support it simply
   navigate normally. */
@view-transition { navigation: auto; }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--paper);
  color: var(--ink);
  padding: 0.75rem 1rem;
  z-index: 100;
}
.skip-link:focus { left: 0; }

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

.container {
  max-width: 78rem;
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* --- Header ------------------------------------------------------------------------------ */

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0 var(--gutter);
  height: var(--header-height);
  border-bottom: 1px solid var(--rule);
  position: sticky;
  top: 0;
  background: var(--paper);
  z-index: 20;
}

.logo a {
  font-family: var(--serif);
  font-size: 1.25rem;
  letter-spacing: 0.02em;
  text-decoration: none;
}

.site-nav ul {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 3vw, 2.25rem);
  list-style: none;
  margin: 0;
  padding: 0;
}

.site-nav a {
  text-decoration: none;
  font-size: 0.8125rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding: 0.5rem 0;
  border-bottom: 1px solid transparent;
}

.site-nav a:hover { color: var(--ink); }
.site-nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--ink); }

.site-nav .instagram a { display: flex; align-items: center; gap: 0.4rem; }
.site-nav .instagram .label { display: none; }

/* The menu button and its checkbox exist only below the breakpoint. */
.menu-toggle, .menu-button { display: none; }

@media (max-width: 46rem) {
  .menu-button {
    display: block;
    width: 2rem;
    height: 2rem;
    position: relative;
    cursor: pointer;
  }
  .menu-button span,
  .menu-button span::before,
  .menu-button span::after {
    content: "";
    position: absolute;
    left: 0;
    width: 100%;
    height: 1px;
    background: var(--ink);
    transition: transform 0.2s ease;
  }
  .menu-button span { top: 50%; }
  .menu-button span::before { top: -7px; }
  .menu-button span::after { top: 7px; }

  .site-nav {
    position: absolute;
    top: var(--header-height);
    left: 0;
    right: 0;
    background: var(--paper);
    border-bottom: 1px solid var(--rule);
    display: none;
  }
  .site-nav ul { flex-direction: column; align-items: flex-start; gap: 0; padding: 0.5rem var(--gutter) 1.25rem; }
  .site-nav li { width: 100%; }
  .site-nav a { display: block; padding: 0.7rem 0; }

  .menu-toggle:checked ~ .site-nav { display: block; }
  .menu-toggle:checked ~ .menu-button span { background: transparent; }
  .menu-toggle:checked ~ .menu-button span::before { transform: translateY(7px) rotate(45deg); }
  .menu-toggle:checked ~ .menu-button span::after { transform: translateY(-7px) rotate(-45deg); }

  .site-nav .instagram .label { display: inline; }
}

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

/* The hero appears on the landing page only. On the works pages it used to remain in the flow
   while hidden, which is where the roughly 250px of dead space above the gallery filters came
   from; those pages no longer render it at all. */
.hero {
  margin-bottom: clamp(2rem, 5vw, 3.5rem);
}

/* The anchor has to be a block, or it takes the line height of the text it is not made of and
   leaves a gap under the image. */
.hero-link {
  display: block;
}

.hero img {
  display: block;
  width: 100%;
  height: clamp(20rem, 62vh, 40rem);
  object-fit: cover;

  /* The band is far wider than a canvas, so most of a painting's height is cropped away. This
     is where that crop sits when nothing says otherwise; a chosen hero overrides it inline with
     its own focal point, since where the subject sits differs from work to work. */
  object-position: center 40%;
}

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

.gallery-heading {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.5rem, 3.5vw, 2.25rem);
  margin: 0 0 0.35rem;
}

.gallery-intro {
  margin: 0 0 1.5rem;
  color: var(--ink-soft);
  max-width: var(--measure);
}

/* The galleries are the way into the collection, and they used to be set the way the site sets
 * metadata: 13px, uppercase, letterspaced, in --ink-faint. That is the treatment on captions, the
 * Sold tag and the painting facts, so the navigation read as a footnote to the page it was
 * supposed to be steering.
 *
 * The promotion is made in the site's own vocabulary rather than with a new device. The serif is
 * otherwise reserved for the wordmark and the headings, so moving to it is legible as a rise in
 * rank, and there is nothing else in the type system to confuse it with. The count stays in the
 * sans, small and faint, because it is a fact about the gallery rather than part of its name.
 */
.gallery-nav ul {
  display: flex;
  flex-wrap: wrap;

  /* The row gap only comes into play on a narrow screen, where the list wraps. It has to clear
     the underline under the current gallery, which hangs below its text and would otherwise sit
     almost against the row beneath it. */
  gap: 0.5rem 2rem;
  list-style: none;
  margin: 0 0 clamp(1.5rem, 4vw, 2.5rem);
  padding: 0 0 0.9rem;
  border-bottom: 1px solid var(--rule);
}

.gallery-nav a {
  display: inline-block;
  text-decoration: none;
  font-family: var(--serif);
  font-size: 1.125rem;
  color: var(--ink-soft);
  white-space: nowrap;

  /* The current gallery is marked twice over, in weight of color and with a rule under it.
     Color alone was the only signal before, and a shade apart is a poor way to say "you are
     here" to anyone reading it at a glance or with the contrast turned down. */
  padding-bottom: 0.55rem;
  border-bottom: 2px solid transparent;
}

.gallery-nav a:hover { color: var(--ink); }
.gallery-nav a.current { color: var(--ink); border-bottom-color: var(--ink); }

/* A count per gallery, which the old filter buttons never showed. Raised off the baseline rather
   than set as a superscript, which at this size read as a footnote marker. */
.gallery-nav .count {
  font-family: var(--sans);
  font-size: 0.75rem;
  vertical-align: 0.35em;
  color: var(--ink-faint);
  margin-left: 0.15rem;
}

/* --- Works grid -------------------------------------------------------------------------- */

/* A grid rather than a masonry library, and specifically a grid rather than CSS columns.
 *
 * Columns would give the masonry look, but they fill top-to-bottom before moving right: with 24
 * works in two columns the reader sees item 1 beside item 13, while the previous/next links on
 * each painting follow the curated order. The eye and the links would disagree.
 *
 * Masonry costs little here anyway. Most of the collection is photographed square, so the grid
 * reads as a square one with a handful of exceptions, and those keep their own proportions while
 * the row grows to fit them.
 *
 * Each tile reserves the shape of its photograph, not of its canvas. object-fit: cover below
 * therefore has nothing to crop, which is the point: the two agree for a straight shot of a
 * painting and have nothing to do with each other for a photograph of one hanging in a room.
 */
.works-grid {
  list-style: none;
  margin: 0 0 4rem;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: start;
  gap: clamp(1.25rem, 2.5vw, 2.25rem) clamp(0.75rem, 2vw, 1.75rem);
}

.works-grid a {
  text-decoration: none;
  display: block;
}

.work-frame {
  display: block;
  width: 100%;
  background: var(--rule);
  overflow: hidden;
}

.work-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity 0.25s ease;
}

.works-grid a:hover .work-frame img { opacity: 0.82; }

/* Titles used to live in a hover overlay, which meant the grid was completely untitled on any
   touch device. They are part of the tile now. */
.work-caption {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 0.1rem 0;
}

.work-name {
  font-size: 0.875rem;
  color: var(--ink);
}

.work-sold,
.painting-facts .sold {
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  white-space: nowrap;
}

@media (max-width: 62rem) {
  .works-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Two columns on a phone rather than one. The default gallery holds 24 works, which at one
   per row was 24 screens of scrolling. */
@media (max-width: 30rem) {
  .works-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem 0.6rem;
  }
  .work-name { font-size: 0.75rem; }
}

.empty { color: var(--ink-faint); margin: 2rem 0 4rem; }

/* --- Painting page ----------------------------------------------------------------------- */

.painting-layout {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  grid-template-areas:
    "breadcrumb breadcrumb"
    "figure     details"
    "pager      pager";
  gap: clamp(1.25rem, 3vw, 2.5rem);
  padding-top: 1.5rem;
  padding-bottom: 4rem;
}

.breadcrumb { grid-area: breadcrumb; font-size: 0.8125rem; color: var(--ink-faint); }
.breadcrumb a { text-decoration: none; }
.breadcrumb a:hover { color: var(--ink); }
.breadcrumb span { margin: 0 0.4rem; }

.painting-figure { grid-area: figure; margin: 0; }
.painting-frame { display: block; width: 100%; background: var(--rule); }
.painting-frame img { width: 100%; height: 100%; object-fit: contain; }

.painting-details { grid-area: details; }

.painting-name {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.35rem, 3vw, 1.9rem);
  margin: 0 0 0.75rem;
}

.painting-description { color: var(--ink-soft); max-width: var(--measure); }

.painting-facts {
  margin: 1.5rem 0 0;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.4rem 1.25rem;
  font-size: 0.9375rem;
}

.painting-facts dt {
  color: var(--ink-faint);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  align-self: baseline;
}

.painting-facts dd { margin: 0; }

.painting-enquire { margin-top: 1.75rem; }

.painting-enquire a {
  display: inline-block;
  padding: 0.7rem 1.4rem;
  border: 1px solid var(--ink);
  text-decoration: none;
  font-size: 0.8125rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.painting-enquire a:hover { background: var(--ink); color: var(--paper); }

.painting-pager {
  grid-area: pager;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
}

.painting-pager a, .painting-pager .disabled {
  text-decoration: none;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  max-width: 45%;
}

.painting-pager .next { text-align: right; align-items: flex-end; }

.painting-pager .direction {
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.painting-pager .title {
  font-size: 0.9375rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Kept in the layout rather than removed, so the remaining control does not jump sides at the
   ends of a gallery. */
.painting-pager .disabled { opacity: 0.3; }

@media (max-width: 52rem) {
  .painting-layout {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "breadcrumb" "figure" "details" "pager";
  }
}

/* --- Prose pages ------------------------------------------------------------------------- */

.prose-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
  padding-top: clamp(2rem, 5vw, 3.5rem);
  padding-bottom: 4rem;
}

@media (max-width: 52rem) {
  .prose-layout { grid-template-columns: minmax(0, 1fr); }
  .prose-layout .portrait { order: -1; max-width: 22rem; }
}

.prose { max-width: var(--measure); padding-top: clamp(2rem, 5vw, 3rem); }
.prose-layout .prose { padding-top: 0; }

.prose h1 {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.5rem, 3.5vw, 2.25rem);
  margin: 0 0 1rem;
}

.prose p { margin: 0 0 1.1rem; color: var(--ink-soft); }

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

/* The work an enquiry is about, shown above the form. It matches the form's width so the two
   read as one column rather than a card sitting beside a form. */
.about-work {
  display: flex;
  align-items: center;
  gap: 1rem;
  max-width: 32rem;
  margin: 1.5rem 0 0;
  padding: 0.75rem;
  border: 1px solid var(--rule);
  color: inherit;
  text-decoration: none;
}

.about-work:hover { border-color: var(--ink); }

.about-work-frame {
  flex: none;
  width: 120px;
  overflow: hidden;
  background: var(--rule);
}

.about-work-frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.about-work-text { display: grid; gap: 0.15rem; min-width: 0; }

.about-work-label {
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.about-work-name { font-family: var(--serif); font-size: 1.0625rem; }
.about-work-gallery { font-size: 0.8125rem; color: var(--ink-soft); }

/* The honeypot. Off-screen rather than display:none or hidden, because a bot worth catching
   skips fields it can tell are unrenderable, and because a field with no layout box is one some
   browsers decline to submit at all. It is out of the tab order and aria-hidden in the markup,
   so nobody using the page can reach it by keyboard or hear it announced. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.contact-form {
  display: grid;
  gap: 0.35rem;
  max-width: 32rem;
  margin: 2rem 0 4rem;
}

.contact-form label {
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-top: 0.75rem;
}

.contact-form input,
.contact-form textarea {
  font: inherit;
  color: inherit;
  background: transparent;
  border: 1px solid var(--rule);
  padding: 0.65rem 0.75rem;
  width: 100%;
}

.contact-form input:focus,
.contact-form textarea:focus { border-color: var(--ink); outline: none; }

.contact-form textarea { resize: vertical; }

.contact-form button {
  font: inherit;
  font-size: 0.8125rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-top: 1.25rem;
  padding: 0.75rem 1.5rem;
  background: var(--ink);
  color: var(--paper);
  border: 1px solid var(--ink);
  cursor: pointer;
  justify-self: start;
}

.contact-form button:hover { background: transparent; color: var(--ink); }

.notice {
  max-width: 32rem;
  margin: 1.5rem 0 0;
  padding: 0.85rem 1rem;
  border-left: 2px solid var(--ink);
  background: color-mix(in srgb, var(--ink) 4%, transparent);
}

.notice.error { border-left-color: #b3261e; }

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

.site-footer {
  border-top: 1px solid var(--rule);
  padding: 2rem var(--gutter);
  text-align: center;
}

.site-footer p {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--ink-faint);
}

/* --- Lightbox ---------------------------------------------------------------------------- */

/* Created by site.js on painting pages. A <dialog> handles the backdrop, focus trapping and
   Escape for free, which is what Magnific Popup was carried for. */
.painting-frame.zoomable { cursor: zoom-in; }

.lightbox {
  border: none;
  padding: 0;
  max-width: 100vw;
  max-height: 100vh;
  width: 100%;
  height: 100%;
  background: transparent;
  overscroll-behavior: contain;
}

.lightbox::backdrop { background: rgba(0, 0, 0, 0.92); }

.lightbox img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  cursor: zoom-out;
}

.lightbox-close {
  position: fixed;
  top: 1rem;
  right: 1.25rem;
  z-index: 1;
  width: 2.75rem;
  height: 2.75rem;
  font-size: 2rem;
  line-height: 1;
  color: #fff;
  background: transparent;
  border: none;
  cursor: pointer;
}

/* Available to screen readers and to a search engine, absent from the visual design. Used for
   the home page's h1, where the artist's name is the subject of the page but the hero image is
   what should be seen. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
