/* ------------------------------------------------------------------
   Nature's Diversity
   Every colour is a token defined once per theme. That is what makes
   two themes cheap: no component knows which theme is active.
   ------------------------------------------------------------------ */

:root {
  --bg: #fbfaf7;
  --bg-sunk: #f2eee5;
  --ink: #1a1a18;
  --ink-soft: #5f5b51;
  --ink-faint: #8a8578;
  --rule: #e4dfd2;
  --rule-strong: #cfc9ba;
  --accent: #b4472a;
  --mat: #f4efe4;
  --mat-edge: #e4dfd2;
  --overlay: 20, 18, 15;
  --logo-light: block;
  --logo-dark: none;

  /* Ceiling for the hero reveal. Inherited from the root so a media query can
     lower it; the source-derived --hero-zoom is set inline on a child element
     and would otherwise always win. */
  --hero-zoom-max: 1.7;
}

[data-theme="dark"] {
  --bg: #14120f;
  --bg-sunk: #1c1915;
  --ink: #f2ece1;
  --ink-soft: #b3a995;
  --ink-faint: #756b58;
  --rule: rgba(242, 236, 225, 0.12);
  --rule-strong: rgba(242, 236, 225, 0.26);
  --accent: #c89a4c;
  --mat: #f4efe4;
  --mat-edge: rgba(0, 0, 0, 0.2);
  --overlay: 10, 9, 7;
  --logo-light: none;
  --logo-dark: block;
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: "Inter", system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
}

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

a {
  color: inherit;
}

h1,
h2,
h3 {
  font-family: "Fraunces", Georgia, serif;
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.skip {
  position: absolute;
  left: -9999px;
  background: var(--ink);
  color: var(--bg);
  padding: 10px 16px;
  z-index: 100;
}
.skip:focus {
  left: 12px;
  top: 12px;
}

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

.eyebrow,
.mono {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* ---------------- header ---------------- */

.site-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 20px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--rule);
}
.mark {
  display: flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
}
/* Two files rather than swapping src with `content`, which Firefox ignores.
   The display toggle is generic so any placement of the mark inherits it. */
.for-light {
  display: var(--logo-light);
}
.for-dark {
  display: var(--logo-dark);
}
.mark-logo {
  height: 44px;
  width: auto;
}

.mark-name {
  font-family: "Fraunces", serif;
  font-size: 13px;
  letter-spacing: 0.13em;
  line-height: 1.25;
  color: var(--ink);
}
.mark-name i {
  display: block;
  font-style: italic;
  font-size: 10px;
  letter-spacing: 0.02em;
  color: var(--ink-faint);
}

.site-nav {
  display: flex;
  align-items: center;
  gap: 18px;
}
.site-nav a {
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-soft);
}
.site-nav a:hover,
.site-nav a[aria-current] {
  color: var(--ink);
}

.theme-btn,
.view-btn {
  font-family: "JetBrains Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  padding: 7px 12px;
  cursor: pointer;
  background: transparent;
  color: var(--ink-soft);
  border: 1px solid var(--rule-strong);
  border-radius: 20px;
}
.theme-btn:hover,
.view-btn:hover {
  color: var(--ink);
  border-color: var(--ink-faint);
}
.when-dark {
  display: none;
}
[data-theme="dark"] .when-light {
  display: none;
}
[data-theme="dark"] .when-dark {
  display: inline;
}

/* ---------------- home ---------------- */

/* Full-bleed banner, framed on the leopard's eyes, opening magnified and
   settling to the resting frame.
   On the resolution: the source is 1500px square, so at rest it is enlarged
   about 1.04x on a 1440 laptop and 1.28x on a 1920 display. That sits inside the
   enlargement we already accept elsewhere, and her impasto reads slight
   softening as paint. The first moments of the zoom are softer still, which the
   motion covers. */
.hero {
  position: relative;
  overflow: hidden;
  background: var(--bg-sunk);
}
.hero-img {
  display: block;
  width: 100%;
  height: 74vh;
  min-height: 420px;
  object-fit: cover;
  /* The eyes sit at roughly 35% of the square's height. */
  object-position: 50% 35%;
}

@media (prefers-reduced-motion: no-preference) {
  .hero-img {
    animation: settle 3600ms cubic-bezier(0.26, 0.64, 0.28, 1) both;
    transform-origin: 50% 35%;
  }
}
@keyframes settle {
  from {
    transform: scale(min(var(--hero-zoom, 1.4), var(--hero-zoom-max, 1.7)));
  }
  to {
    transform: scale(1);
  }
}

.hero-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(10, 9, 7, 0.24) 0%,
    rgba(10, 9, 7, 0.06) 34%,
    rgba(10, 9, 7, 0.58) 78%,
    rgba(10, 9, 7, 0.86) 100%
  );
}

.hero-copy {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 0 28px 34px;
}
.hero-copy h1 {
  font-size: clamp(38px, 7vw, 88px);
  line-height: 0.92;
  color: #f6f1e6;
}
.hero-copy h1 em {
  font-style: italic;
  font-weight: 400;
  color: #e8cfa0;
}
.hero-by {
  margin: 16px 0 20px;
  color: rgba(246, 241, 230, 0.82);
}
.hero-copy .cta {
  color: #f6f1e6;
  border-bottom-color: rgba(246, 241, 230, 0.7);
}

.hero-cap {
  position: absolute;
  right: 16px;
  top: 14px;
  z-index: 2;
  color: rgba(246, 241, 230, 0.6);
  font-size: 8.5px;
}

.statement {
  max-width: 40rem;
  margin: 0 auto;
  padding: 80px 24px 84px;
  text-align: center;
}
.statement p {
  font-family: "Fraunces", serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(19px, 2.4vw, 26px);
  line-height: 1.5;
  margin: 0;
}
.statement .attrib {
  margin-top: 18px;
  color: var(--ink-faint);
  font-style: normal;
}

.cta {
  display: inline-block;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  border-bottom: 1px solid var(--ink);
  padding-bottom: 4px;
}

/* ---------------- collection ---------------- */

.coll-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 20px;
  flex-wrap: wrap;
  padding: 30px 12px 16px;
}
.coll-head h1 {
  font-size: clamp(24px, 3vw, 36px);
}
.coll-count {
  color: var(--ink-faint);
  margin-top: 6px;
}
.coll-tools {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
.filters {
  display: flex;
  gap: 12px;
}
.filters a {
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-soft);
}
.filters a[aria-current] {
  color: var(--ink);
  border-bottom: 1px solid var(--ink);
}

.viewswitch {
  display: flex;
  border: 1px solid var(--rule-strong);
  border-radius: 20px;
  overflow: hidden;
}
.viewswitch button {
  font-family: "JetBrains Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  padding: 7px 12px;
  border: 0;
  cursor: pointer;
  background: transparent;
  color: var(--ink-soft);
}
.viewswitch button[aria-pressed="true"] {
  background: var(--ink);
  color: var(--bg);
}

/* Tile view: masonry via CSS multicolumn. No JavaScript, fully fluid, and
   aspect ratios are preserved because tiles are never given a height. */
.gallery {
  padding: 0 8px 40px;
  column-gap: 8px;
  column-count: 4;
}
@media (max-width: 1100px) {
  .gallery {
    column-count: 3;
  }
}
@media (max-width: 760px) {
  .gallery {
    column-count: 2;
  }
}
/* Two columns is kept well down the range: it halves the pixel width each tile
   demands on a high-density phone, and shows more of the collection at once. */
@media (max-width: 380px) {
  .gallery {
    column-count: 1;
  }
}

.tile {
  position: relative;
  display: block;
  break-inside: avoid;
  margin: 0 0 8px;
  text-decoration: none;
  background: var(--bg-sunk);
}
.tile img {
  display: block;
  width: 100%;
}

/* Pale works on paper need their edge defined, for opposite reasons in each
   theme: they bleed into a white page and float on a dark one. */
.tile.is-paper img,
.tile.is-wood img {
  border: 1px solid var(--mat-edge);
}
[data-theme="dark"] .tile.is-paper,
[data-theme="dark"] .tile.is-wood {
  background: var(--mat);
  padding: 6px 6px 22px;
}

.tile-meta {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 12px;
  opacity: 0;
  transition: opacity 0.2s ease;
  background: linear-gradient(
    0deg,
    rgba(var(--overlay), 0.86) 0%,
    rgba(var(--overlay), 0.26) 52%,
    rgba(var(--overlay), 0) 84%
  );
}
.tile:hover .tile-meta,
.tile:focus-visible .tile-meta {
  opacity: 1;
}
.tile-title {
  font-family: "Fraunces", serif;
  font-size: 15px;
  color: #f6f1e6;
  line-height: 1.1;
}
.tile-sub {
  font-family: "JetBrains Mono", monospace;
  font-size: 8px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #d8cdb8;
  margin-top: 5px;
}
.tile-zoom {
  position: absolute;
  top: 9px;
  right: 9px;
  opacity: 0;
  transition: opacity 0.2s;
  font-family: "JetBrains Mono", monospace;
  font-size: 8px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #14120f;
  background: rgba(246, 241, 230, 0.93);
  padding: 4px 8px;
  border-radius: 20px;
}
.tile:hover .tile-zoom {
  opacity: 1;
}

/* Touch devices have no hover, so captions become permanent rather than
   revealed, and the gradient is always present to keep them legible. */
@media (hover: none) {
  .tile-meta {
    opacity: 1;
  }
  .tile-zoom {
    display: none;
  }
}

/* Museum view: the column flow is abandoned for a uniform letterboxed grid.
   Same markup, same images. */
[data-view="museum"] .gallery {
  column-count: initial;
  display: grid;
  gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
}
[data-view="museum"] .tile {
  margin: 0;
  aspect-ratio: 1 / 1;
  background: var(--bg-sunk);
  border: 1px solid var(--rule);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
}
[data-view="museum"] .tile.is-paper,
[data-view="museum"] .tile.is-wood {
  padding: 12px;
  background: var(--mat);
}
[data-view="museum"] .tile img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
[data-view="museum"] .tile.is-paper img,
[data-view="museum"] .tile.is-wood img {
  border: 0;
}

/* ---------------- work page ---------------- */

.work {
  max-width: 1140px;
  margin: 0 auto;
  padding: 30px 20px 70px;
}
.work-figure {
  margin: 0;
}
.work-figure img {
  display: block;
  margin: 0 auto;
}
.work-figure.is-paper img,
.work-figure.is-wood img {
  border: 1px solid var(--mat-edge);
}
[data-theme="dark"] .work-figure.is-paper,
[data-theme="dark"] .work-figure.is-wood {
  background: var(--mat);
  padding: 22px 22px 30px;
  width: fit-content;
  margin: 0 auto;
}

.work-body {
  display: grid;
  grid-template-columns: 1.5fr 1fr;
  gap: 40px;
  padding-top: 28px;
  align-items: start;
}
@media (max-width: 820px) {
  .work-body {
    grid-template-columns: 1fr;
    gap: 22px;
  }
}
.work-body h1 {
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1.02;
}
.work-lede {
  color: var(--ink-soft);
  line-height: 1.7;
  margin: 14px 0 0;
}

.facts {
  list-style: none;
  margin: 0;
  padding: 0;
}
.facts li {
  display: flex;
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px solid var(--rule);
  font-size: 14px;
}
.facts dt,
.facts .k {
  font-family: "JetBrains Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-faint);
  min-width: 6.5em;
  padding-top: 3px;
}
.facts em {
  font-family: "Fraunces", serif;
  font-style: italic;
  color: var(--ink-soft);
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
  font-family: "JetBrains Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 6px 11px;
  border: 1px solid var(--accent);
  border-radius: 20px;
  color: var(--accent);
}
.pill .dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
}
.attrib-note {
  color: var(--ink-faint);
  font-size: 11px;
  margin: 10px 0 0;
  line-height: 1.5;
}

.work-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 20px;
}
.btn {
  font-family: "JetBrains Mono", monospace;
  font-size: 9.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 10px 15px;
  border: 1px solid var(--rule-strong);
  border-radius: 22px;
  color: var(--ink);
  background: transparent;
  cursor: pointer;
}
.btn.solid {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
}
.btn[hidden] {
  display: none;
}

.sold {
  color: var(--ink-faint);
}

.work-nav {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  border-top: 1px solid var(--rule);
  margin-top: 44px;
  padding-top: 18px;
}
.work-nav a {
  text-decoration: none;
  color: var(--ink-soft);
}
.work-nav a:hover {
  color: var(--ink);
}

/* ---------------- magnifier ---------------- */

.viewer {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: none;
  background: #0b0a08;
  align-items: center;
  justify-content: center;
}
.viewer[open],
.viewer.is-open {
  display: flex;
}
.viewer-stage {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  cursor: grab;
}
.viewer-stage img {
  position: absolute;
  top: 50%;
  left: 50%;
  max-width: none;
  transform: translate(-50%, -50%) scale(1);
  transition: transform 90ms linear;
}
.viewer-close {
  position: absolute;
  top: 18px;
  right: 20px;
  z-index: 3;
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #f2ece1;
  background: transparent;
  border: 1px solid rgba(242, 236, 225, 0.4);
  border-radius: 20px;
  padding: 9px 14px;
  cursor: pointer;
}
.viewer-cap {
  position: absolute;
  left: 20px;
  bottom: 18px;
  z-index: 3;
  color: rgba(242, 236, 225, 0.75);
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* ---------------- prose pages ---------------- */

.prose {
  max-width: 42rem;
  margin: 0 auto;
  padding: 50px 24px 80px;
}
.prose h1 {
  font-size: clamp(28px, 4vw, 42px);
  margin-bottom: 20px;
}
.prose p {
  line-height: 1.8;
  color: var(--ink-soft);
  margin: 0 0 18px;
}
.prose blockquote {
  margin: 26px 0;
  padding-left: 20px;
  border-left: 2px solid var(--accent);
  font-family: "Fraunces", serif;
  font-style: italic;
  color: var(--ink);
  line-height: 1.6;
}
.portrait {
  margin: 0 0 30px;
}
.portrait img {
  display: block;
  width: 100%;
}

.field {
  display: block;
  margin-bottom: 16px;
}
.field span {
  display: block;
  margin-bottom: 6px;
  font-family: "JetBrains Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.field input,
.field textarea {
  width: 100%;
  padding: 11px 13px;
  font: inherit;
  font-size: 15px;
  color: var(--ink);
  background: var(--bg-sunk);
  border: 1px solid var(--rule-strong);
  border-radius: 3px;
}
.hp {
  position: absolute;
  left: -9999px;
}
.form-note {
  color: var(--ink-faint);
  font-size: 12px;
  line-height: 1.6;
}

/* ---------------- footer ---------------- */

/* Three equal-weight columns rather than space-between, so the centre column is
   centred against the page and not pushed off by whatever sits beside it. */
.site-foot {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
  border-top: 1px solid var(--rule);
  padding: 30px 20px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
}
.site-foot a {
  text-decoration: none;
  color: var(--ink-soft);
}
.site-foot a:hover {
  color: var(--accent);
}
.foot-links {
  grid-column: 2;
  display: flex;
  gap: 20px;
}
.foot-copy {
  grid-column: 3;
  text-align: right;
}
@media (max-width: 620px) {
  .site-foot {
    grid-template-columns: 1fr;
    justify-items: center;
    text-align: center;
    gap: 12px;
  }
  .foot-links,
  .foot-copy {
    grid-column: 1;
    text-align: center;
  }
}

/* ---------------- her drawings behind the form ---------------- */

/* Her own pen and ink work from an unbuilt design of hers. Each file is a black
   ink mask whose alpha came from the original's luminance, so the grey
   watercolour wash survives as partial transparency. Dark mode inverts them to
   white, which is why one file per drawing is enough. */
.inked {
  position: relative;
  isolation: isolate;
}
.inked > * {
  position: relative;
  z-index: 1;
}
.inked::before,
.inked::after {
  content: "";
  position: absolute;
  z-index: 0;
  background-repeat: no-repeat;
  background-size: contain;
  pointer-events: none;
  opacity: 0.16;
}
[data-theme="dark"] .inked::before,
[data-theme="dark"] .inked::after {
  filter: invert(1);
  opacity: 0.2;
}

/* Seeds drift across the upper area; the cat and its @ sign sit lower right,
   which suits a contact page. */
.inked::before {
  top: -40px;
  left: -80px;
  width: 620px;
  height: 520px;
  background-image: url("art-seeds.png");
  background-position: top left;
}
.inked::after {
  right: -130px;
  bottom: -30px;
  width: 300px;
  height: 780px;
  background-image: url("art-toots.png");
  background-position: bottom right;
}

@media (max-width: 900px) {
  .inked::before {
    width: 380px;
    height: 320px;
    left: -60px;
  }
  .inked::after {
    right: -150px;
    width: 210px;
    height: 545px;
    opacity: 0.1;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .inked::before,
  .inked::after {
    animation: inkfade 1200ms ease-out both;
  }
}
@keyframes inkfade {
  from {
    opacity: 0;
  }
}

/* Email as the contact route while no form provider is configured. */
.contact-big {
  margin: 26px 0 10px;
}
.contact-big a {
  font-family: "Fraunces", serif;
  font-size: clamp(20px, 3vw, 30px);
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--accent);
  padding-bottom: 3px;
  word-break: break-word;
}
.contact-big a:hover {
  color: var(--accent);
}
.contact-sub {
  display: block;
  margin-top: 12px;
  font-size: 9px;
  color: var(--ink-faint);
}

/* Photographs of her work hung in a gallery, on the about page. They give
   physical scale that a cropped photograph of a painting cannot. */
.shot {
  margin: 34px 0;
}
.shot img {
  display: block;
  width: 100%;
  height: auto;
}
.shot figcaption {
  margin-top: 9px;
  font-size: 9px;
  color: var(--ink-faint);
}

/* ---------------- loading state ---------------- */

/* A tile reserves its shape from the image's width and height attributes, so
   this sits in a correctly proportioned box rather than a collapsed one. */
.tile[data-loading] {
  background: var(--bg-sunk);
}
.tile[data-loading]::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 22px;
  height: 22px;
  margin: -11px 0 0 -11px;
  border: 2px solid var(--rule-strong);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 700ms linear infinite;
  z-index: 0;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* Without motion the ring would sit frozen and look like a mistake, so it
   becomes a slow pulse instead. */
@media (prefers-reduced-motion: reduce) {
  .tile[data-loading]::after {
    animation: pulse 1.6s ease-in-out infinite;
    border-top-color: var(--rule-strong);
  }
  @keyframes pulse {
    50% {
      opacity: 0.25;
    }
  }
}

/* The image fades in rather than snapping, which hides the moment the spinner
   is removed. */
.tile img {
  transition: opacity 220ms ease;
}
.tile[data-loading] img {
  opacity: 0;
}

/* ---------------- keyboard hints ---------------- */

.keyhint {
  display: inline-block;
  min-width: 1.5em;
  padding: 2px 5px;
  margin: 0 2px;
  border: 1px solid var(--rule-strong);
  border-radius: 3px;
  font-size: 9px;
  line-height: 1.4;
  text-align: center;
  color: var(--ink-faint);
}
@media (hover: none) {
  .keyhint {
    display: none;
  }
}
