:root {
  --colour-bg: #fcfdff;
  --colour-neutral-200: #e8eaef;
  --colour-neutral-300: #ced2d8;
  --colour-neutral-800: #595e67;
  --colour-neutral-900: #444850;
  --colour-neutral-1000: #232529;
  --colour-brand-blue-100: #ebf4ff;
  --colour-brand-blue-200: #ddecff;
  --colour-brand-blue-1000: #0e1f33;
  --font-display: 'Fraunces', serif;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html, body {
  background: var(--colour-bg);
  color: var(--colour-neutral-1000);
  font-family: var(--font-display);
}

/* Only the homepage locks to the viewport height with no scrolling —
   every other page scrolls normally. */
body.home {
  height: 100vh;
  overflow: hidden;
}

/* Opt-in for inner pages that are short enough to leave a gap above the
   footer: keeps .site-footer pinned to the bottom of the viewport when
   there isn't enough content to reach it, while still scrolling normally
   (footer included) if the content ever grows taller than the viewport.
   Add class="sticky-footer" to <body> to use this on a page. */
body.sticky-footer {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

body.sticky-footer .page {
  flex: 1 0 auto;
}

body.sticky-footer .site-footer {
  flex-shrink: 0;
}

/* Add this class to any image (or image frame div) that has a white or
   very light background/edges, so it doesn't visually disappear against
   the page background — e.g. class="collage-img collage-img--1 bordered"
   on an <img>, or class="commission-samples__frame bordered" on a frame
   wrapper. Leave it off images that are already dark enough to contrast
   on their own. */
.bordered {
  border: 1px solid var(--colour-neutral-300);
}

a {
  color: inherit;
  text-decoration: none;
}

/* Hero / homepage layout */

.hero {
  display: flex;
  align-items: stretch;
  height: 100vh;
  overflow: hidden;
  background: var(--colour-bg);
}

.hero__collage {
  position: relative;
  flex: 0 0 auto;
  height: 100%;
  /* Width matches the original 499:810 baseline composition unless that
     would leave less than 420px for the centre content, in which case cap
     by the space actually available so the centre content never gets
     squeezed. This is also the width the art group below is judged
     against when deciding how much of it fits without cropping. */
  width: min(calc((100vw - 420px) / 2), calc(100vh * 499 / 810));
  overflow: hidden;
}

/* The full, uncropped set of images for each side, at the 499px-wide
   reference scale (matching .hero__collage's own width exactly). Only
   vertically centred/resized inside .hero__collage — horizontally each
   image sits at its true designed offset, which intentionally runs
   negative (left side) or past 100% (right side) so it bleeds off and
   gets clipped at the outer screen edge, with the inner edge (toward the
   centre content) fully rounded and visible. On a standard (wider than
   tall) viewport the collage box is shorter than this group's full
   height, so it gets cropped top and bottom, reproducing the original
   composition. On a taller viewport the collage box grows toward this
   group's full height, progressively revealing more of the images
   (never scrolling, since .hero__collage never exceeds the viewport). */
.hero__art {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 100%;
}

.hero__art--left {
  aspect-ratio: 499 / 1270;
}

.hero__art--right {
  aspect-ratio: 499 / 902.667;
}

.collage-img {
  position: absolute;
  display: block;
  object-fit: cover;
  border-radius: 12px;
  box-shadow:
    0 26px 57px rgba(0, 0, 0, 0.08),
    0 103px 103px rgba(0, 0, 0, 0.07),
    0 232px 139px rgba(0, 0, 0, 0.04),
    0 413px 165px rgba(0, 0, 0, 0.01),
    0 645px 181px rgba(0, 0, 0, 0);
}

/* Left art group: reference box 499 x 1270 */
.collage-img--1 { /* tattoo, top */
  left: -17.23%;
  top: 0%;
  width: 86.57%;
  height: 27.32%;
}
.collage-img--2 { /* cat, centre */
  left: -5.21%;
  top: 29.21%;
  width: 84.57%;
  height: 41.57%;
}
.collage-img--3 { /* flan, bottom */
  left: -26.65%;
  top: 72.68%;
  width: 86.57%;
  height: 27.32%;
}

/* Right art group: reference box 499 x 902.667 */
.collage-img--4 { /* portrait, top */
  left: 20.64%;
  top: 0%;
  width: 85.17%;
  height: 58.94%;
}
.collage-img--5 { /* dog, bottom */
  left: 28.66%;
  top: 61.56%;
  width: 86.57%;
  height: 38.44%;
}

/* Subtle floating animation for the homepage collage images. Only
   transform is animated (never top/left/width/height) so this stays on
   the compositor thread — no layout or repaint cost. Each image gets its
   own duration and a negative delay so they bob out of sync with each
   other rather than moving in unison. Skipped entirely for visitors who
   have asked their OS for reduced motion. */
@media (prefers-reduced-motion: no-preference) {
  @keyframes float {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-10px); }
  }

  .collage-img {
    animation: float 6s ease-in-out infinite;
  }

  .collage-img--1 { animation-duration: 7s; animation-delay: -0.5s; }
  .collage-img--2 { animation-duration: 5.5s; animation-delay: -1.5s; }
  .collage-img--3 { animation-duration: 6.5s; animation-delay: -3s; }
  .collage-img--4 { animation-duration: 8s; animation-delay: -2s; }
  .collage-img--5 { animation-duration: 5s; animation-delay: -4s; }
}

.hero__content {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  max-height: 100%;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 40px;
  padding: 40px 1rem;
}

.hero__intro,
.hero__nav {
  width: 378px;
  max-width: 100%;
}

.hero__intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  padding-bottom: 40px;
  border-bottom: 1px solid var(--colour-neutral-300);
}

.hero__logo {
  width: 135.8px;
  height: 149px;
}

.hero__tagline {
  font-weight: 300;
  font-size: 20px;
  line-height: 1.3;
  text-align: center;
  color: var(--colour-neutral-800);
}

.hero__nav ul {
  list-style: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

.hero__nav li {
  width: 100%;
  text-align: center;
}

.hero__nav a {
  display: block;
  padding: 12px 0;
  font-weight: 300;
  font-size: 20px;
  line-height: 1.3;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--colour-brand-blue-1000);
  transition: opacity 0.15s ease;
}

.hero__nav a:hover,
.hero__nav a:focus-visible {
  opacity: 0.6;
}

@media (max-width: 900px) {
  .hero__collage {
    display: none;
  }

  .hero {
    justify-content: center;
  }
}

/* On inner pages the footer sits in normal document flow, 60px below
   whatever content comes before it. Only the homepage overlays it as a
   fixed bar (see body.home .site-footer below), since that page is
   locked to the viewport with no scrolling and has no natural "end of
   content" to sit below. */
.site-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 34px;
  margin-top: 60px;
  padding: 0 1rem;
}

/* Homepage only: overlaid on top of the page rather than reserving its
   own row, so it never shortens the hero images above it. Fixed so it
   stays pinned to the bottom of the viewport. */
body.home .site-footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  margin-top: 0;
}

.site-footer p {
  font-size: 14px;
  font-weight: 300;
  line-height: 1.4;
  color: var(--colour-neutral-800);
  text-align: left;
}

/* ==========================================================================
   Inner pages (everything except the homepage): shared header + page title
   ========================================================================== */

.site-header {
  position: relative;
  display: flex;
  padding: 0 28px;
  justify-content: space-between;
  align-items: center;
  align-self: stretch;
  height: 98px;
}

.site-header__logo img {
  display: block;
  height: 40px;
  width: auto;
}

.site-header__nav ul {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 12px;
}

.site-header__nav a {
  display: block;
  padding: 8px 12px;
  font-weight: 300;
  font-size: 20px;
  line-height: 1.3;
  color: var(--colour-neutral-900);
  transition: opacity 0.15s ease;
}

.site-header__nav a:hover,
.site-header__nav a:focus-visible {
  opacity: 0.6;
}

/* Hamburger toggle — hidden on desktop, shown only below the mobile
   breakpoint (see media query below). */
.site-header__toggle {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  width: 40px;
  height: 40px;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
}

.site-header__toggle span {
  display: block;
  width: 22px;
  height: 2px;
  border-radius: 1px;
  background: var(--colour-brand-blue-1000);
  transition: transform 0.2s ease, opacity 0.2s ease;
}

/* Animate into an "X" while the mobile menu is open */
.site-header.is-open .site-header__toggle span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.site-header.is-open .site-header__toggle span:nth-child(2) {
  opacity: 0;
}

.site-header.is-open .site-header__toggle span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

.page-top {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  width: 100%;
}

.page-title {
  width: 100%;
  max-width: 790px;
  padding: 0 1rem;
  font-weight: 400;
  font-size: 61px;
  line-height: 1.2;
  text-align: left;
  color: var(--colour-brand-blue-1000);
}

.page-title--center {
  text-align: center;
}

@media (max-width: 600px) {
  .site-header {
    padding: 0 16px;
  }

  .site-header__toggle {
    display: flex;
  }

  /* Collapses into a dropdown panel below the header, opened by the
     hamburger button (js/nav.js toggles .is-open on .site-header). */
  .site-header__nav {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 50;
    background: var(--colour-bg);
    border-bottom: 1px solid var(--colour-neutral-300);
    box-shadow: 0 8px 16px rgba(14, 31, 51, 0.08);
  }

  .site-header.is-open .site-header__nav {
    display: block;
  }

  .site-header__nav ul {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 8px 0;
  }

  .site-header__nav a {
    padding: 12px 16px;
    font-size: 18px;
    text-align: left;
  }

  .page-title {
    font-size: 40px;
  }
}

/* ==========================================================================
   Shared inner-page typography (reusable on any inside page)
   ========================================================================== */

.heading-2 {
  width: 100%;
  font-weight: 400;
  font-size: 49px;
  line-height: 1.2;
  text-align: left;
  color: var(--colour-brand-blue-1000);
}

.text-body-lg {
  font-weight: 300;
  font-size: 20px;
  line-height: 1.3;
  color: var(--colour-neutral-900);
}

.text-body-md {
  font-weight: 300;
  font-size: 16px;
  line-height: 1.4;
  color: var(--colour-neutral-900);
}

@media (max-width: 600px) {
  .heading-2 {
    font-size: 34px;
  }
}

/* ==========================================================================
   Commissions page
   ========================================================================== */

.page-sections {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  width: 100%;
}

.commissions-top {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  width: 100%;
}

.commissions-intro {
  max-width: 790px;
  padding: 0 1rem;
  text-align: left;
}

.commissions-intro > * + * {
  margin-top: 16px;
}

.commissions-intro a {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.commission-samples {
  display: flex;
  gap: 12px;
  width: 100%;
  max-width: 790px;
  padding: 0 1rem;
}

.commission-samples__frame {
  flex: 1 1 0;
  min-width: 0;
  aspect-ratio: 4 / 5;
  border-radius: 12px;
  overflow: hidden;
}

.commission-samples__frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* "What to expect" tabs
   ----------------------
   Placeholder copy for now — replace the text inside each
   .tab-panel in commissions.html once the real content is ready.
   To add another tab: add a matching pair — a button in .tabs with a
   unique data-tab value, and a panel with the same value in
   data-tab-panel — js/tabs.js handles the rest automatically. */

.expect {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  width: calc(100% - 2rem);
  max-width: 790px;
  padding: 24px 40px;
  border: 1px solid var(--colour-neutral-300);
  border-radius: 12px;
}

@media (max-width: 600px) {
  .expect {
    padding: 24px 16px;
  }
}

.tabs {
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: flex-start;
  width: 100%;
}

.tabs button {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: 20px;
  line-height: 1.3;
  color: var(--colour-neutral-800);
  background: none;
  border: 1px solid transparent;
  border-radius: 1000px;
  padding: 8px 24px;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.tabs button:not(.is-active) {
  border-color: var(--colour-neutral-300);
}

.tabs button:hover:not(.is-active) {
  background: var(--colour-neutral-200);
  color: var(--colour-neutral-900);
}

.tabs button.is-active {
  background: var(--colour-brand-blue-200);
  color: var(--colour-brand-blue-1000);
}

/* Stacks both panels in the same grid cell so the box's height is set by
   whichever panel's content is taller, instead of jumping to whichever
   tab happens to be active. */
.tab-panels {
  display: grid;
  width: 100%;
}

.tab-panel {
  grid-column: 1;
  grid-row: 1;
  text-align: left;
  opacity: 1;
  visibility: visible;
  transition: opacity 0.2s ease, visibility 0s linear 0s;
}

/* Kept present (not display: none) so it still counts toward the grid
   row's height — just faded out and made non-interactive instead. The
   visibility switch is delayed until the fade finishes (see the
   transition below) so the two panels crossfade instead of cutting. */
.tab-panel[hidden] {
  display: block;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.2s ease, visibility 0s linear 0.2s;
}

.tab-panel > * + * {
  margin-top: 16px;
}

.pricing-box {
  width: 100%;
  padding: 24px;
  border: 1px solid var(--colour-neutral-300);
  border-radius: 12px;
}

.pricing-table {
  width: 100%;
  max-width: 480px;
  border-collapse: collapse;
  font-size: 16px;
}

.pricing-box .pricing-table {
  max-width: none;
}

.pricing-table th,
.pricing-table td {
  padding: 10px 16px;
  border-bottom: 1px solid var(--colour-neutral-300);
  text-align: left;
}

.pricing-table th {
  font-weight: 400;
  color: var(--colour-brand-blue-1000);
}

.pricing-table tbody tr:last-child td {
  border-bottom: none;
}

@media (max-width: 600px) {
  .pricing-box {
    padding: 16px;
  }

  .pricing-table thead {
    display: none;
  }

  .pricing-table tbody tr {
    display: block;
    padding: 12px 0;
    border-bottom: 1px solid var(--colour-neutral-300);
  }

  .pricing-table tbody tr:last-child {
    border-bottom: none;
    padding-bottom: 0;
  }

  .pricing-table tbody tr:first-child {
    padding-top: 0;
  }

  .pricing-table td {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 4px 0;
    border-bottom: none;
  }

  .pricing-table td:first-child {
    display: block;
    padding-bottom: 8px;
    margin-bottom: 4px;
    color: var(--colour-brand-blue-1000);
  }

  .pricing-table td:not(:first-child)::before {
    content: attr(data-label);
    color: var(--colour-neutral-800);
  }
}

/* On narrow screens the row stays side-by-side and just shrinks; any
   frame marked --hide-mobile (e.g. the 3rd of 3 on Commissions) drops out
   so only 2 images remain, matching the About page's 2-image row. */
@media (max-width: 560px) {
  .commission-samples {
    gap: 8px;
  }

  .commission-samples__frame--hide-mobile {
    display: none;
  }
}

/* ==========================================================================
   About page
   ========================================================================== */

.about-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  width: 100%;
}

.commission-samples--single {
  justify-content: flex-start;
}

.commission-samples--single .commission-samples__frame {
  flex: 0 1 calc((100% - 12px) / 2);
  max-width: 389px;
}

/* ==========================================================================
   Contact page
   ========================================================================== */

.contact-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  width: 100%;
}

.contact-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  width: calc(100% - 2rem);
  max-width: 790px;
  padding: 40px;
  background: var(--colour-brand-blue-100);
  border-radius: 12px;
}

.contact-links {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  width: 100%;
  padding: 0 1rem;
}

.contact-links a {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  font-size: 31px;
  font-weight: 400;
  line-height: 1.2;
  color: var(--colour-brand-blue-1000);
  transition: opacity 0.15s ease;
  white-space: nowrap;
}

.contact-links a:hover,
.contact-links a:focus-visible {
  opacity: 0.7;
}

.contact-links img {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
}

/* Narrow screens: scale link text (and icon) to fit inside the box. */
@media (max-width: 790px) {
  .contact-box {
    container-type: inline-size;
    padding: clamp(16px, 5vw, 40px);
  }

  .contact-links a {
    max-width: 100%;
    font-size: clamp(16px, 3.9cqw, 31px);
  }

  .contact-links img {
    width: clamp(18px, 3.9cqw, 40px);
    height: clamp(18px, 3.9cqw, 40px);
  }
}

/* ==========================================================================
   Masonry gallery
   ==========================================================================
   To add an image: copy a <figure class="gallery-item"> block in
   gallery.html and drop the file in images/gallery/. Order in the HTML is
   the order they flow into the 3 columns (top of column 1, top of column
   2, top of column 3, back to column 1, and so on).
   To remove an image: delete its whole <figure> block.
   Each image keeps its own natural proportions — just use the real image
   file, no need to crop or resize it to fit.
   Hover text: .gallery-item__title for the piece name,
   .gallery-item__subtitle for medium and substrate. */

.gallery-wrap {
  max-width: 1200px;
  margin: 40px auto 0;
  padding: 0 28px;
}

.gallery {
  column-count: 3;
  column-gap: 16px;
}

.gallery-item {
  position: relative;
  display: block;
  margin-bottom: 16px;
  border-radius: 12px;
  overflow: hidden;
  break-inside: avoid;
  cursor: pointer;
}

.gallery-item img {
  display: block;
  width: 100%;
}

/* Gradient + title shown on hover (and keyboard focus). */
.gallery-item__hover {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-start;
  padding: 24px;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%);
  opacity: 0;
  transition: opacity 0.2s ease;
  /* Let clicks pass through to the <img> underneath so the lightbox
     still opens when clicking anywhere on the image, hover state or
     not. */
  pointer-events: none;
}

.gallery-item:hover .gallery-item__hover,
.gallery-item:focus-within .gallery-item__hover {
  opacity: 1;
}

.gallery-item__title {
  color: #fff;
  font-size: 20px;
  font-weight: 400;
  line-height: 1.3;
}

.gallery-item__subtitle {
  color: #fff;
  font-size: 14px;
  font-weight: 300;
  line-height: 1.3;
  margin-top: 4px;
  opacity: 0.85;
}

@media (max-width: 900px) {
  .gallery {
    column-count: 2;
  }
}

@media (max-width: 560px) {
  .gallery {
    column-count: 1;
  }
}

/* Mobile / touch: no reliable hover, so keep title and subtitle visible. */
@media (max-width: 900px) and (hover: none) {
  .gallery-item__hover {
    opacity: 1;
  }
}

/* ==========================================================================
   Lightbox ("shadowbox"): full-image view on click
   ========================================================================== */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, 0.4);
}

.lightbox[hidden] {
  display: none;
}

.lightbox__image {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 12px;
}

.lightbox__close {
  position: absolute;
  top: 20px;
  right: 20px;
  width: 40px;
  height: 40px;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
}

.lightbox__close img {
  display: block;
  width: 100%;
  height: 100%;
}
