/* ==========================================================================
   Xander Koeppel — Tattoo Artist
   Mobile-first, fluid layout. Breakpoints only nudge arrangement, not values.
   ========================================================================== */

:root {
  --black: #000000;
  --white: #ffffff;
  --green: rgb(125, 255, 125);
  --blue-glow: #7fb2ff;
  --blue-active: #2233dd;
  --pink: #f4b8d6;
  --font: 'Anonymous Pro', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --pad-x: clamp(16px, 5vw, 48px);
  --pad-y: clamp(12px, 2.5vw, 28px);
}

/* ---- Reset ------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font-family: var(--font);
  background: var(--black);
  overflow-x: hidden;
  /* Site-wide custom cursor: a 16x16 square, hotspot centered (8 8 = half
     the image's own size) since there's no directional tip to align.
     `auto` after it is the required fallback if the image ever fails to
     load. Applies to every page automatically since they all share this
     stylesheet — no per-page CSS needed. */
  cursor: url('assets/cursor.png') 8 8, auto;
}
ul { margin: 0; padding: 0; list-style: none; }

/* Hover cursor: an inverted, 2x-larger (24x24) version of the base cursor,
   for every link and button site-wide — a plain element-selector rule, not
   a :hover rule, since the browser already swaps to whichever cursor value
   applies to the element currently under the pointer. `pointer` is the
   fallback here (rather than `auto`) so it still reads as clickable even
   if the image fails to load. Covers every <a>/<button> on every page
   (nav links, hero-menu links, the book/submit button, portfolio tiles,
   the lightbox close button, the footer social icon) without needing to
   list each one — anything added later that's an <a> or <button> picks
   this up automatically too.

   IMPORTANT: this only wins the cascade because none of the more specific
   selectors below (.nav-toggle, .submit-btn, .portfolio-item,
   .lightbox-close) set their own `cursor` anymore — a class selector beats
   a plain element selector regardless of source order, so any `cursor:
   pointer` re-added to one of those would silently override this again on
   just that element. */
a, button {
  cursor: url('assets/cursor-hover.png') 12 12, pointer;
}
a { color: inherit; text-decoration: none; }
img, svg { display: block; max-width: 100%; }

/* ---- Animated cursor ------------------------------------------------------
   Native `cursor: url()` (above) can't animate or transition — browsers only
   ever show one static image per state, no fade/grow possible. To get an
   actual grow+fade animation, the shared <script> block at the bottom of
   every page creates this div and moves it on every mousemove, and the
   static image-based cursor above is hidden (see the `html.has-custom-cursor`
   rule below). If JS is ever disabled, that class is never added, so the
   plain image cursor two rules up is what shows instead — a working
   fallback, not a broken page.
   -------------------------------------------------------------------------- */
html.has-custom-cursor,
html.has-custom-cursor * {
  /* !important because it needs to beat both the plain `body` rule and the
     more specific `a, button` rule above without touching either — those
     stay in place as the no-JS fallback. */
  cursor: none !important;
}

.custom-cursor {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 16px;
  height: 16px;
  box-sizing: border-box;
  background: var(--black);
  border: 1px solid var(--white);
  pointer-events: none;
  z-index: 9999;
  /* Centers the box on the tracked mouse coordinate — .left/.top are set to
     the raw pointer position in JS, this shifts by half the box's own
     current size so it's centered rather than corner-anchored. */
  transform: translate(-50%, -50%);
  transition: width 0.2s ease, height 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;
}
/* Shown only after the first real mousemove, so it doesn't flash at 0,0
   before the pointer has actually moved (also keeps it harmlessly inert on
   touch devices, where mousemove never fires). */
.custom-cursor.is-active { display: block; }

/* Hover state: grows from 16x16 to 24x24, the black fill fades to fully
   transparent, and the outline switches from white to black. NOTE: a black
   outline on a transparent fill is invisible over the site's black
   sections (the hero-menu links on the home page, the portfolio tiles on
   the tattoos page) — this was flagged when the color was chosen as white
   specifically to avoid that. If the cursor seems to vanish while hovering
   links there, that's why. */
.custom-cursor.is-hover {
  width: 24px;
  height: 24px;
  background: transparent;
  border-color: var(--black);
}

/* Suppresses the animated div entirely — used only for the home page's
   three hero-menu links (see .hero-menu a below), which keep the older,
   non-animated cursor instead of this one. Must come after .is-active
   above so it wins the tie when both classes are present at once (equal
   specificity — later rule wins). */
.custom-cursor.is-suppressed { display: none; }

/* The three hero-menu links (TATTOOS/ARTWORK/BOOK on the home page) keep
   the older static image-swap cursor rather than the animated one above —
   restores the native cursor.png/cursor-hover.png despite the blanket
   `cursor: none !important` further up, which this must also out-specify
   (hence !important here too — important rules ignore specificity from
   non-important ones entirely, so this can't win without it). Targets both
   the <a> itself and its child spans (.glow, .hero-label), since either
   can be the direct hover target and neither should show `none`. The
   corresponding JS (index.html) hides the animated div while hovering
   these so the two cursors never render on top of each other. */
html.has-custom-cursor .hero-menu a,
html.has-custom-cursor .hero-menu a * {
  cursor: url('assets/cursor-hover.png') 12 12, pointer !important;
}

/* ---- Header -------------------------------------------------------------
   White bar: logo/tagline left, primary nav right — pinned to opposite
   edges (space-between) at every width down to the exact point where the
   two content boxes would collide. That collision point is what the
   max-width breakpoint below is tuned to (~738px, measured empirically),
   so "aligned to the right" holds for every width above it, and the
   layout only switches to the stacked/toggle nav once the two boxes have
   genuinely run out of room to both fit on one line.
   -------------------------------------------------------------------------- */
.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: clamp(12px, 4vw, 32px);
  background: var(--white);
  color: var(--black);
  padding: var(--pad-y) var(--pad-x);
  border-bottom: 1px solid var(--black);
  /* Declared here (rather than on .logo-block) so both .logo-block and
     .site-nav — siblings — can reference it for proportional offsets.
     7.5vw (not the rounder 9vw the design started from) is what makes room
     for the nav list to sit beside the logo down to tablet widths — see
     the breakpoint comment near the bottom of this file for the exact
     fit math. Raising this back toward 9vw makes the logo bigger at most
     sizes but pushes the breakpoint back up above ~1490px, same as
     before. */
  --logo-size: clamp(28px, 7.5vw, 128px);
}

/* Groups the page's title block with the mobile nav-toggle button as one
   tight, normal-flow flex row — this is what keeps the toggle sitting
   right next to whatever title text a page actually has (this page's big
   "XANDER KOEPPEL" logo, or a subpage's .page-title), with no per-page
   measuring or magic numbers: flexbox just places it there. This is also
   why the toggle can be a plain in-flow element instead of needing
   position:absolute — see .nav-toggle below and the breakpoint at the
   bottom of this file. */
.header-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(10px, 1.5vw, 24px);
  min-width: 0;
}

.logo-block { min-width: 0; }

.logo {
  display: inline-flex;
  align-items: baseline;
  gap: 0.12em;
  margin: 0;
  font-weight: 700;
  font-size: var(--logo-size);
  line-height: 1;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.chevron { color: inherit; }

.tagline {
  /* 0.732 * --logo-size = the measured distance from the logo-block's
     left edge to the left edge of the "X" in XANDER, so "t" always
     lands under the "X" at every screen size. Tweak that multiplier
     to shift left (smaller) or right (larger). */
  margin: -0.3em 0 0 calc(var(--logo-size) * 0.732);
  font-style: italic;
  font-size: clamp(11px, 1.5vw, 20px);
  letter-spacing: 0.02em;
}
.tagline strong { font-weight: 700; font-style: italic; }

.site-nav {
  flex: 0 0 auto;
}

.site-nav ul {
  display: flex;
  flex-direction: column;
  gap: clamp(4px, 1vw, 9px);
  min-width: clamp(120px, 16vw, 170px);
}

.site-nav li {
  display: flex;
  justify-content: flex-end;
}

/* The box is nested inside the link (rather than a separate sibling) so
   clicking or tapping it activates the link too, not just the text. */
.site-nav a {
  display: inline-flex;
  align-items: center;
  gap: 0.7em;
  font-weight: 700;
  font-size: clamp(12px, 1.3vw, 16px);
  white-space: nowrap;
}
.site-nav a:hover,
.site-nav a:focus-visible { text-decoration: underline; }

.nav-box {
  /* 32px in the Figma desktop frame → 32 / 1440 * 100 ≈ 2.22vw, so it
     scales down proportionally on smaller screens instead of staying a
     fixed 32px everywhere and crowding the nav on tablet. */
  width: clamp(20px, 2.22vw, 32px);
  height: clamp(20px, 2.22vw, 32px);
  border: 1px solid var(--black);
  background: var(--white);
  flex: 0 0 auto;
}

/* Mobile menu toggle — hidden on tablet/desktop, where the full list
   already shows. Enabled inside the @media (max-width: 768px) block.
   Lives inside .header-row (see above), so its position next to the title
   text comes for free from normal flexbox layout — no positioning rules
   needed here at all. */
.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  margin: 0;
  padding: 10px;
  border: 0;
  background: none;
  -webkit-tap-highlight-color: transparent;
}

.nav-toggle-box {
  width: 26px;
  height: 26px;
  border: 1px solid var(--black);
  background: var(--white);
  transition: transform 0.3s ease;
}

/* Same box, rotated 45° into a diamond while the menu is open. */
.nav-toggle[aria-expanded="true"] .nav-toggle-box {
  transform: rotate(45deg);
}

/* ---- Aftercare badge ------------------------------------------------------
   Small link to the Aftercare page, sitting in its own band directly below
   the header — a flex sibling of .site-header/.hero/.site-footer in body's
   flex column, so it just takes its own natural height in normal flow and
   pushes .hero down slightly rather than needing any positioning rules.

   Deliberately styled as the INVERSE of the page background it sits on
   (white fill/black text here, against this page's black .hero stage) so
   it reads clearly no matter what's behind it, rather than matching or
   blending into the surrounding page like most other elements here do.
   When this gets added to a white-background page, flip background/color/
   border-color to the opposite pairing (black fill, white text) there —
   the rule is "always the opposite of the page," not "always these two
   colors" — the hover state below already demonstrates that inversion.
   -------------------------------------------------------------------------- */
.aftercare-bar {
  flex: 0 0 auto;
  /* Left AND right padding both var(--pad-x) (same as .site-header's own
     padding) is what makes the badge's right edge land exactly under the
     nav-box column's right edge below — text-align: right then just pushes
     the inline-flex badge over to that shared edge. */
  padding: clamp(10px, 2vh, 16px) var(--pad-x) 0;
  text-align: right;
}

.aftercare-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--black);
  background: var(--white);
  color: var(--black);
  padding: clamp(6px, 1vw, 10px) clamp(14px, 2vw, 20px);
  font-weight: 700;
  font-style: italic;
  font-size: clamp(12px, 1.3vw, 16px);
  letter-spacing: 0.02em;
}
.aftercare-badge:hover,
.aftercare-badge:focus-visible {
  background: var(--black);
  color: var(--white);
  border-color: var(--white);
}

/* The "always inverted" pairing flipped for the white-background pages
   (About/Book/Aftercare — see their body.*-page rules further down, which
   set background: var(--white)) — default is now black fill/white text,
   and the hover/focus state flips that again to white fill/black text, the
   mirror image of what .aftercare-badge does by default above for the
   black-background pages (Home/Tattoos/Artwork). */
body.about-page .aftercare-badge,
body.book-page .aftercare-badge,
body.aftercare-page .aftercare-badge {
  background: var(--black);
  color: var(--white);
  border-color: var(--white);
}
body.about-page .aftercare-badge:hover,
body.about-page .aftercare-badge:focus-visible,
body.book-page .aftercare-badge:hover,
body.book-page .aftercare-badge:focus-visible,
body.aftercare-page .aftercare-badge:hover,
body.aftercare-page .aftercare-badge:focus-visible {
  background: var(--white);
  color: var(--black);
  border-color: var(--black);
}

/* ---- Hero ----------------------------------------------------------------
   Black stage. Three glowing menu links vertically centered in the space
   between the header and the .site-footer below (see Footer section) —
   that space is whatever .hero doesn't take up as a flex sibling of
   .site-footer, so centering holds at every viewport size.
   -------------------------------------------------------------------------- */
.hero {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
  background: var(--black);
  padding: clamp(24px, 6vh, 56px) var(--pad-x);
}

.hero-menu {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(8px, 2vh, 16px);
}

.hero-menu a {
  display: inline-flex;
  align-items: center;
  gap: clamp(14px, 3vw, 30px);
  width: fit-content;
}

.glow {
  /* Enlarged from the original clamp(38px,6vw,68px) footprint so the
     sourced blur images read as full/round as the original CSS-gradient
     dots did, rather than looking small and padded inside the box. */
  position: relative;
  flex: 0 0 auto;
  width: clamp(80px, 7.5vw, 140px);
  height: clamp(80px, 7.5vw, 110px);
  /* Keep background-size at/under 100% — backgrounds are clipped to the
     element's own box, so scaling past 100% here pushes the soft blur
     falloff outside the box and shows up as a hard-clipped edge instead
     of a fade to transparent. The box itself (above) is what got bigger. */
  background-repeat: no-repeat;
  background-position: center;
  background-size: 100%;
}
/* Directional spread toward the label, matching the Figma reference: an
   oversized, off-center, blurred radial gradient sitting behind the crisp
   icon. Built from background + filter (not box-shadow) — box-shadow's
   blur renders with a hard-clipped edge on this page (a rendering quirk
   triggered specifically by box-shadow's blur alongside the white
   .site-header elsewhere on the page); background + filter don't hit it. */
.glow::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 70%;
  width: 340%;
  height: 180%;
  transform: translate(-50%, -50%);
  background: radial-gradient(ellipse at center, rgba(255, 255, 255, 0.55), transparent 62%);
  filter: blur(20px);
  z-index: -1;
  pointer-events: none;
}
.glow--tattoos { background-image: url('assets/glow-tattoos.png'); }
.glow--artwork { background-image: url('assets/glow-artwork.png'); }
.glow--book    { background-image: url('assets/glow-book.png'); }

.hero-label {
  font-weight: 700;
  font-style: italic;
  font-size: clamp(19px, 4.2vw, 40px);
  letter-spacing: 0.02em;
  color: var(--green);
}
.hero-menu a:hover .hero-label,
.hero-menu a:focus-visible .hero-label { text-decoration: underline; }

/* ---- Footer ----------------------------------------------------------------
   Shared across every page: a single social icon, pinned bottom-left. Lives
   as its own flex sibling of the page's main content (both direct children
   of body's flex column), so it sits at the bottom of the viewport when
   content is short, and directly below content when it overflows — the
   same rule at any page height, on every page.

   Icon color follows the page's background: white by default (for black
   stages like .hero), flipped to black on light pages via a page-level
   modifier class on <body> (see body.book-page below). Any future light
   page should add its own such class and a matching override here.
   -------------------------------------------------------------------------- */
.site-footer {
  flex: 0 0 auto;
  padding: 0 var(--pad-x) var(--pad-y);
  color: var(--white);
}
body.book-page .site-footer { color: var(--black); }

.social-link {
  display: inline-flex;
  width: fit-content;
  color: inherit;
}
.social-link:hover,
.social-link:focus-visible { opacity: 0.75; }

/* ---- Breakpoints ---------------------------------------------------------
   Fluid clamp() values handle most of the scaling; these just adjust
   arrangement at a few key widths.
   -------------------------------------------------------------------------- */

/* Condensed nav: let nav go full width so it wraps below the header row,
   and put the hero menu back to its original top-anchored spacing (not
   vertically centered like the rare very-wide desktop window) — kept
   separately by request. Threshold is 768px — the standard tablet-portrait
   cutoff — chosen so the full side-by-side nav survives across ordinary
   laptop and tablet-landscape widths, and only condenses once the screen
   is genuinely tablet/mobile-sized. With the logo's font-size scaling by
   7.5vw (see --logo-size above), "XANDER KOEPPEL" and the nav list — each
   its own tight, content-sized box, however far apart space-between
   happens to push them — only actually fit on the same line once the
   viewport is roughly 740px+ wide (measured empirically: fits at 740px,
   wraps at 738px). This fit point is specific to THIS page's title
   text/size — a page with a shorter or longer title (see .page-title on
   the Book/Tattoos/About/Artwork pages) will fit at a different width, so
   if this breakpoint is ever copied to those pages' stylesheets it should
   be re-measured against their own title, not assumed to be 768px too.
   768px gives a comfortable ~28px margin past this page's exact fit point
   so the deliberately-designed collapsed/toggle nav below — not an
   accidental flex-wrap — is what every phone/small-tablet size gets, and
   the side-by-side, right-aligned layout runs for every ordinary laptop
   and tablet-landscape width above it. */
@media (max-width: 768px) {
  /* .nav-toggle lives inside two different parents depending on the page —
     .header-row on the home page, .site-nav on every subpage (see the
     markup comments in index.html vs. the other pages) — so the two get
     handled differently below, but both land in the same visual spot:
     flush right, vertically centered against the title text beside them.

     Home page: .header-row already wraps .logo-block AND .nav-toggle as
     flex siblings, and already has align-items: center from its base
     (non-mobile) rule — so stretching it to width:100% and adding
     justify-content: space-between here is enough on its own to push the
     toggle to the far right while flexbox keeps it vertically centered
     against .logo-block's height, in NORMAL flow. Because .header-row
     never contains the dropdown <ul> (that's .site-nav, a separate sibling
     under .site-header), its own height never changes when the menu opens
     — so this centering can't drift the way a percentage-based position
     relative to the whole (growing) header would. */
  .header-row {
    width: 100%;
    justify-content: space-between;
  }
  .header-row .nav-toggle {
    /* Cancels the position: absolute (and the translateY(-50%) that goes
       with it) given to .nav-toggle generally below — on the home page it
       doesn't need either one now that .header-row's own flex layout does
       the job in normal flow. Leaving the transform in place here would
       still shift it upward by half its own height even though it's no
       longer using top/right to position itself, since transform doesn't
       care what position value an element has. */
    position: static;
    transform: none;
  }

  /* Subpages: .nav-toggle sits inside .site-nav alongside the <ul>, and
     .site-nav's own height DOES grow when that ul opens — so, unlike the
     home page above, there's no nearby unchanging flex container to lean
     on here. position: absolute (relative to .site-header, via
     position: relative below) is what pulls it out of that flow, but the
     offset it uses matters: top: 50% would recalculate against
     .site-header's live height and drift downward as the dropdown opens
     (the bug this replaces). The calc() below instead adds up the same
     clamp()s that already size .back-home and .page-title elsewhere in
     this file (see .back-home/.book-header .logo-block/.page-title), to
     land at (roughly) half of that fixed, dropdown-independent title
     block's height — a value that can never change just because a sibling
     grew, since none of its ingredients reference .site-header's height at
     all. */
  .site-header {
    position: relative;
  }
  .nav-toggle {
    display: inline-flex;
    position: absolute;
    top: calc(
      var(--pad-y) +
      (clamp(12px, 1.3vw, 16px) + clamp(6px, 1.6vw, 14px) + clamp(40px, 11vw, 140px)) / 2
    );
    right: 0;
    transform: translateY(-50%);
  }

  /* .site-nav (the ul) is the other thing that changes: forcing it to
     width:100% means it can no longer fit on the same line as the title
     block beside it, so it wraps onto its own full-width row below
     (site-header is a plain wrapping flex row — see above — nothing here
     needs to force that manually), where it can drop down as a collapsed
     dropdown instead of sitting beside the title. .nav-toggle floating on
     top of this via position:absolute (above) is unaffected by .site-nav's
     own width/position, so the toggle stays pinned top-right regardless of
     where its containing box ends up. */
  .site-nav {
    width: 100%;
  }

  /* The floating animated-cursor square (see the .custom-cursor rules and
     the shared <script> at the bottom of every page) only ever tracks
     `mousemove`, which touchscreens don't fire continuously — some mobile
     browsers still fire one synthetic mousemove on tap, which is enough to
     flip on `.is-active` and leave the square frozen at that last tap
     point for the rest of the visit. Hiding it outright below the same
     768px breakpoint the rest of mobile layout uses sidesteps that
     entirely; the JS still runs harmlessly in the background, it just
     never has anything visible to show. Desktop/tablet (where mousemove
     is continuous and the effect works as intended) is untouched. */
  .custom-cursor {
    display: none !important;
  }

  .site-nav ul {
    width: 100%;
    min-width: 0;
    margin-top: 8px;
    /* Collapsed by default: no height, invisible, not interactive. */
    max-height: 0;
    opacity: 0;
    overflow: hidden;
    visibility: hidden;
    transition: max-height 0.35s ease, opacity 0.3s ease, visibility 0s linear 0.35s;
  }
  /* Drop down + fade in together once the menu is open. */
  .site-nav.is-open ul {
    max-height: 320px;
    opacity: 1;
    visibility: visible;
    transition: max-height 0.35s ease, opacity 0.3s ease, visibility 0s linear 0s;
  }
  .site-nav li { justify-content: space-between; }
  /* The box lives inside the <a> (see markup comment above .site-nav a),
     so it's the anchor — not the <li> — that needs to actually span the
     row and split into text-left/box-right. */
  .site-nav a {
    width: 100%;
    justify-content: space-between;
  }

  .hero {
    justify-content: space-between;
    gap: clamp(32px, 10vh, 96px);
  }
  .hero-menu {
    flex: 0 1 auto;
    justify-content: flex-start;
  }
}

/* ==========================================================================
   Book page
   Same header shell as the home page (.site-header / .site-nav / .nav-box /
   .nav-toggle are shared), but the page runs on a white canvas instead of
   the hero's black stage — a plain, form-like "paper" feel for booking,
   set against the flashier black landing page. Mobile-first + clamp(),
   matching the conventions above.
   ========================================================================== */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

body.book-page {
  background: var(--white);
  color: var(--black);
}

/* ---- Book header ----------------------------------------------------------
   Reuses .site-header's white bar/flex-wrap/border-bottom. Only the left
   side changes: a small "HOME" back-link sits above a large ">BOOK" title,
   in place of the home page's logo + tagline.
   -------------------------------------------------------------------------- */
.book-header .logo-block {
  display: flex;
  flex-direction: column;
  gap: clamp(6px, 1.6vw, 14px);
}

.back-home {
  display: inline-flex;
  align-items: center;
  gap: 0.7em;
  font-weight: 700;
  font-size: clamp(12px, 1.3vw, 16px);
  letter-spacing: 0.02em;
  width: fit-content;
}
.back-home:hover,
.back-home:focus-visible { text-decoration: underline; }

.back-box {
  width: clamp(16px, 1.8vw, 22px);
  height: clamp(16px, 1.8vw, 22px);
  border: 1px solid var(--black);
  background: var(--white);
  flex: 0 0 auto;
}

.page-title {
  margin: 0;
  display: inline-flex;
  align-items: baseline;
  gap: 0.08em;
  font-weight: 700;
  font-size: clamp(40px, 11vw, 140px);
  line-height: 1;
  letter-spacing: 0.01em;
}

/* Current-page indicator: the active nav item's box fills solid instead of
   staying an outlined white square. */
.nav-box.is-active {
  background: var(--blue-active);
}

/* ---- Layout ----------------------------------------------------------------
   Two columns on wide screens (form, then the gallery/map sidebar);
   collapses to one column — sidebar below the form — on narrow screens.
   Values below are measured 1:1 off the booking-screen reference at its
   960px-wide frame (each figure written as px / 960 * 100 = vw), the same
   convention as .nav-box above — fixed pixel amounts at/above that width,
   scaling down proportionally on narrower screens.
   -------------------------------------------------------------------------- */
.book-main {
  flex: 1 0 auto;
  display: flex;
  align-items: center;
  /* The gap between the form and the gallery sidebar — the single number
     to change to move them closer/further apart. Since this is a real
     flexbox gap (not a margin trying to approximate one), the two boxes
     are structurally incapable of overlapping no matter what else is
     adjusted, the same guarantee .field-row already gives First/Last
     Name. 106 / 960 * 100 */
  --main-gap: clamp(24px, 11.04vw, 106px);
  /* 70 / 960 * 100 */
  --main-pad-x: clamp(16px, 7.29vw, 70px);
  --main-pad-top: clamp(24px, 5vh, 56px);
  gap: var(--main-gap);
  padding: var(--main-pad-top) var(--main-pad-x) clamp(40px, 8vh, 80px);
}

@media (max-width: 800px) {
  .book-main {
    flex-direction: column;
    gap: clamp(32px, 8vh, 56px);
  }
}

/* ---- Form -------------------------------------------------------------- */
.booking-form {
  /* Fluid box that fills whatever room is left beside the (fixed-width)
     gallery sidebar and the gap between them — the flex equivalent of
     the old grid column's minmax(0, 1fr). This is what gives the form's
     own margin-left below room to move without needing to know the
     gallery's width. */
  flex: 1 1 auto;
  min-width: 0;
}

.booking-form form {
  display: flex;
  flex-direction: column;
  /* Single source of truth for how wide EVERY field is — the Name row
     (First + gap + Last combined) and each standalone field (Email,
     Subject, Message) all measure themselves off this one variable, so
     they can never drift apart at any screen size. Change only this to
     resize the whole group together. 455px matches the original design;
     455 / 960 * 100 = 47.4vw. */
  --field-width: clamp(280px, 47.4vw, 600px);
  /* Bounded so this can be nudged freely but can never cross the right
     edge of .booking-form's own box (past which it would start
     overlapping the gap/sidebar). The right bound,
     calc(100% - var(--field-width)), is "whatever room is left in THIS
     box once the field group's own width is subtracted" — 100% here
     resolves to .booking-form's actual live width, recalculated by the
     browser at every screen size. The left bound is "as far as the
     page's own left padding allows". Edit the middle value in each
     clamp() — the outer two only ever kick in to stop it before it
     would overlap something. */
  margin-left: clamp(calc(-1 * var(--main-pad-x)), 60px, calc(100% - var(--field-width)));
  margin-top: clamp(calc(-1 * var(--main-pad-top)), 60px, 400px);
}

.field-row {
  display: flex;
  /* 13 / 960 * 100 */
  gap: clamp(8px, 1.35vw, 13px);
  /* Measured as a 37px box-to-box gap to the next field in the reference;
     18px of margin plus the next label's own line-height/leading lands
     there in practice. */
  margin-bottom: clamp(14px, 1.88vw, 18px);
  width: var(--field-width);
}
/* The row claims the full --field-width above; flex:1 1 0 here just
   splits THAT fixed total evenly between First and Last, with width:auto
   so this (more specific) rule overrides .field's own width below. */
.field-row .field {
  flex: 1 1 0;
  width: auto;
  min-width: 0;
  margin-bottom: 0;
}

.field {
  display: flex;
  flex-direction: column;
  /* 3px, label hugs its input closely in the reference */
  gap: 3px;
  /* Measured as a 26px box-to-box gap in the reference; 7px of margin
     plus the next label's own line-height/leading lands there in practice. */
  margin-bottom: clamp(5px, 0.73vw, 7px);
  width: var(--field-width);
}
.booking-form form > .field:last-of-type { margin-bottom: 0; }

.field label {
  font-style: italic;
  font-size: clamp(11px, 1.3vw, 14px);
  line-height: 1.15;
  letter-spacing: 0.02em;
}

.field input,
.field textarea {
  width: 100%;
  border: 1px solid var(--black);
  background: var(--white);
  color: var(--black);
  font-family: inherit;
  font-size: clamp(13px, 1.4vw, 16px);
  /* 27 / 960 * 100 */
  padding: 0 clamp(8px, 1.25vw, 12px);
}
.field input {
  height: clamp(30px, 2.81vw, 60px);
}
.field textarea {
  /* 108 / 960 * 100 */
  height: clamp(72px, 11.25vw, 108px);
  padding-top: 6px;
  padding-bottom: 6px;
  resize: vertical;
}

.field input:focus-visible,
.field textarea:focus-visible {
  outline: 2px solid var(--black);
  outline-offset: -1px;
}

.form-actions {
  /* Matches the field width so "right" means "under the message box's own
     right edge" rather than the full (wider) column's right edge. */
  width: var(--field-width);
  text-align: right;
  /* Measured as a 13px gap from the message box in the reference. */
  margin-top: clamp(1px, 0.21vw, 2px);
}

.submit-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.08em;
  border: 0;
  background: none;
  padding: 0;
  font-family: inherit;
  font-weight: 700;
  font-style: italic;
  font-size: clamp(14px, 1.6vw, 18px);
  line-height: 1.15;
  letter-spacing: 0.02em;
  color: var(--black);
}
.submit-btn:hover,
.submit-btn:focus-visible { text-decoration: underline; }

.submit-btn:disabled {
  opacity: 0.5;
  pointer-events: none;
}

/* Honeypot field: pulled fully off-screen (not display:none/visibility:hidden,
   which some bots detect and skip) so real visitors never see or reach it,
   but bots that blindly fill every input still fill this one. */
.field--honeypot {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

/* Status message under the Submit button — reuses the form's own italic
   monospace voice rather than looking like a bolted-on alert box. Empty
   by default, so it takes up no space until JS sets text after a submit. */
.form-status {
  margin: clamp(10px, 1.5vw, 14px) 0 0;
  width: var(--field-width);
  font-style: italic;
  font-size: clamp(12px, 1.3vw, 14px);
  line-height: 1.4;
}
.form-status.is-success { color: #2a8f4f; }
.form-status.is-error { color: #c23b3b; }

/* ---- Gallery / map sidebar ---------------------------------------------- */
.gallery-info {
  /* Fixed-width flex item — doesn't grow or shrink, so it always sits
     exactly var(--gallery-width) wide, --main-gap away from the form.
     Same relationship .field-row gives First/Last Name: two flex
     siblings sharing one fixed gap. That gap is what keeps this box and
     the form apart now, not a calculated margin bound, so there's no
     longer a margin-left here to nudge it sideways — the two boxes are
     structurally incapable of overlapping regardless of screen size.
     Change --gallery-width right here to resize the whole group; change
     --main-gap (on .book-main) to change the distance between it and
     the form. */
  flex: 0 0 auto;
  /* 247 / 960 * 100 */
  --gallery-width: clamp(200px, 25.73vw, 247px);
  width: var(--gallery-width);
  /* -18px (rather than 0) nudges this box up so its bottom (the map)
     lands flush with the bottom of the message box in the form beside it,
     tuned against common desktop widths (~1280-1500px). The message field
     grows with an uncapped clamp() well past where the map and this box's
     own text settle at their max size, so at very wide/ultrawide windows
     the two bottoms can drift apart by a few px again — that's a
     pre-existing mismatch between how those two clamp()s are tuned, not
     something this offset alone can fix at every possible width. */
  margin-top: clamp(calc(-1 * var(--main-pad-top)), -18px, 400px);
}

.gallery-info h2 {
  /* Measured as a 17px gap to the address in the reference. */
  margin: 0 0 clamp(8px, 1.15vw, 11px);
  font-weight: 700;
  font-style: italic;
  font-size: clamp(18px, 2.2vw, 26px);
  line-height: 1.15;
}

.gallery-info address {
  font-style: italic;
  font-size: clamp(13px, 1.5vw, 16px);
  line-height: 1.4;
}

.gallery-info .phone {
  /* Measured as an 18px gap above and 31px below (to the map) in the
     reference. */
  margin: clamp(8px, 1.25vw, 12px) 0 clamp(18px, 2.6vw, 25px);
  font-weight: 700;
  font-style: italic;
  font-size: clamp(15px, 1.8vw, 19px);
  line-height: 1.15;
}
.gallery-info .phone a:hover,
.gallery-info .phone a:focus-visible { text-decoration: underline; }

.map-frame {
  aspect-ratio: 4 / 3;
  background: #e4e4e4;
  overflow: hidden;
}

.map-frame iframe {
  width: 100%;
  height: 100%;
  border: 0;
  filter: grayscale(0.85) contrast(1.05);
}

/* Desktop-only: bigger gallery box, pulled closer to the form. Scoped to
   min-width: 801px — the exact complement of the max-width: 800px
   breakpoint below — so it can never affect the stacked mobile layout.
   Placed after the base .book-main / .gallery-info rules above so it wins
   the cascade at these widths (same specificity, later wins). Tweak the
   middle/max clamp() values here, not the base ones above, to keep this
   change desktop-only. */
@media (min-width: 801px) {
  .book-main {
    --main-gap: clamp(8px, 7vw, 272px);
    justify-content: center;
  }
  .gallery-info {
    --gallery-width: clamp(260px, 30vw, 340px);
  }
  .booking-form {
    flex: 0 1 auto;
    max-width: calc(60px + var(--field-width));
  }
}

/* Once .book-main stacks to a single column (see the 800px breakpoint
   above), the desktop margin offsets on .booking-form form (left + top)
   and .gallery-info (top) have nothing beside them to offset against —
   they'd just read as randomly shifted. Re-center both here instead.
   This block must stay AFTER the two base rules above in the file: with
   equal selector specificity, cascade order decides ties, so an earlier
   copy of this override would lose to the desktop margins even inside a
   matching @media block. */
@media (max-width: 800px) {
  .booking-form form {
    width: var(--field-width);
    max-width: 100%;
    margin: 0 auto;
  }
  .gallery-info {
    max-width: 100%;
    margin: 0 auto;
  }
}

/* ==========================================================================
   Tattoos / Portfolio page
   Same white .site-header shell as the Book page (.book-header / .page-title
   reused as-is). Body has no page class beyond `.tattoos-page`, so it falls
   back to the base black body background from the Reset section above —
   that's the "separate black box" the gallery sits in, made explicit below
   via its own background so it never depends on inheriting body's color.
   ========================================================================== */

/* ---- Gallery grid --------------------------------------------------------
   Deliberately a plain 3-column CSS Grid, not JS-driven and not
   auto-fit/auto-fill: with a fixed column count, adding or removing
   .portfolio-item buttons in the HTML is the ONLY thing ever needed to
   change the collection — the grid always wraps to a new row of 3, the
   black box (.portfolio-gallery) grows to fit its content since nothing
   here gives it a fixed height, and every section below it in normal
   document flow (the Instagram bar, "more work", footer) is pushed down
   automatically. Nothing to keep in sync by hand.
   -------------------------------------------------------------------------- */
.portfolio-gallery {
  background: var(--black);
  padding: clamp(24px, 5vh, 56px) var(--pad-x);
}

.portfolio-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* 12 / 372 * 100 — measured off the mobile reference frame; scales up
     smoothly, same convention as the rest of the page. */
  gap: clamp(8px, 3.2vw, 24px);
  max-width: 1400px;
  margin: 0 auto;
}

/* Mobile only: 1 column instead of 3, so each piece renders big enough to
   actually see instead of shrinking to fit three across a phone-width
   screen — visitors just scroll down through them one at a time instead.
   Still a plain CSS Grid with nothing else changed (same auto-flow, same
   gap), so adding a new piece later is still just pasting one more
   .portfolio-item button at the end of the markup — the grid adds a new
   row and everything below (Instagram strip, footer) gets pushed down
   automatically, on mobile exactly the same as it already does on desktop. */
@media (max-width: 768px) {
  .portfolio-grid {
    grid-template-columns: 1fr;
  }
}

.portfolio-item {
  aspect-ratio: 1 / 1;
  border: 0;
  padding: 0;
  background: #e4e4e4;
  color: #6b6b6b;
  font-family: inherit;
  font-style: italic;
  font-size: clamp(11px, 1.4vw, 15px);
  display: flex;
  align-items: center;
  justify-content: center;
}
.portfolio-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.portfolio-item:hover,
.portfolio-item:focus-visible {
  outline: 2px solid var(--white);
  outline-offset: -2px;
}

/* ---- Lightbox --------------------------------------------------------------
   One <dialog>, shared by every grid item (current and future) — see the
   click handler in tattoos.html. Native <dialog> gives Esc-to-close and
   focus trapping for free, so no extra JS is needed for either. */
.lightbox {
  border: 0;
  padding: 0;
  background: transparent;
  max-width: 92vw;
  max-height: 92vh;
}
.lightbox::backdrop {
  background: rgba(0, 0, 0, 0.9);
}
.lightbox-content {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: min(60vw, 420px);
  min-height: min(60vw, 420px);
  max-width: 92vw;
  max-height: 92vh;
  background: #111111;
  color: var(--white);
  font-style: italic;
  font-weight: 700;
  font-size: clamp(28px, 8vw, 72px);
}
.lightbox-content img {
  display: block;
  max-width: 92vw;
  max-height: 92vh;
  width: auto;
  height: auto;
  object-fit: contain;
}
.lightbox-close {
  position: absolute;
  top: clamp(8px, 1.5vw, 16px);
  right: clamp(8px, 1.5vw, 16px);
  border: 0;
  background: none;
  color: var(--white);
  font-size: clamp(24px, 3vw, 32px);
  line-height: 1;
  padding: 4px 8px;
}
.lightbox-close:hover,
.lightbox-close:focus-visible { opacity: 0.7; }

/* ---- Instagram strip + "more work" preview -------------------------------- */
.portfolio-social {
  background: var(--white);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(8px, 1.6vw, 12px);
  padding: clamp(20px, 4vh, 32px) var(--pad-x);
}

.preview-row {
  display: flex;
  gap: clamp(10px, 2.5vw, 20px);
}
.preview-thumb {
  width: clamp(36px, 6vw, 56px);
  height: clamp(36px, 6vw, 56px);
  border-radius: 50%;
  background: #e4e4e4;
  flex: 0 0 auto;
}

.social-handle {
  font-weight: 700;
  font-style: italic;
  font-size: clamp(13px, 1.8vw, 16px);
  color: var(--black);
}
.social-handle:hover,
.social-handle:focus-visible { text-decoration: underline; }

.social-bar {
  width: min(280px, 70%);
  height: 3px;
  border-radius: 2px;
  background: var(--black);
}

.more-work {
  background: var(--black);
  color: var(--white);
  padding: clamp(20px, 4vh, 32px) var(--pad-x) clamp(48px, 9vh, 88px);
}
.more-work-label {
  margin: 0 0 clamp(12px, 2vw, 18px);
  font-style: italic;
  font-size: clamp(13px, 1.8vw, 16px);
}
.instagram-preview {
  background: #e4e4e4;
  color: #6b6b6b;
  min-height: clamp(160px, 26vw, 240px);
  max-width: 1400px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(11px, 1.6vw, 14px);
  letter-spacing: 0.05em;
}

/* ==========================================================================
   About Me page
   Same white .site-header shell as the Book/Tattoos pages (.book-header /
   .page-title reused as-is). Runs on the same white canvas as the Book
   page, via the same background/color override pattern.
   ========================================================================== */
body.about-page {
  background: var(--white);
  color: var(--black);
}
body.about-page .site-footer { color: var(--black); }

.about-main {
  padding: clamp(24px, 5vh, 56px) var(--pad-x) clamp(40px, 8vh, 80px);
  display: flex;
  flex-direction: column;
  gap: clamp(40px, 8vh, 72px);
}

/* ---- Photo + bio ------------------------------------------------------
   Two flex siblings sharing one real flex `gap` (--intro-gap) — same
   technique as .book-main's form/gallery pair: the gap is what keeps them
   apart, not a margin trying to approximate one, so they're structurally
   incapable of overlapping regardless of screen size or content length.
   Kept small (--intro-gap) so the two boxes read as "stuck together"
   rather than spaced apart, while still being two genuinely separate,
   non-overlapping boxes. */
.about-intro {
  display: flex;
  /* Stretch (rather than flex-start) so .about-bio takes on the same height
     as the photo — needed for the contact button's margin-top: auto below
     to have any spare room to push into, which is what lands it flush with
     the photo's bottom edge. */
  align-items: stretch;
  /* Centers the photo+bio pair as a unit within the full-width row, rather
     than leaving them flush against the left padding edge — the row stays
     full width so `justify-content` has room to actually center something;
     photo and bio remain side by side, just centered as a group. */
  justify-content: center;
  --intro-gap: clamp(16px, 3vw, 28px);
  gap: var(--intro-gap);
}

.about-photo {
  flex: 0 0 auto;
  width: clamp(160px, 22vw, 220px);
  /* Matches the actual portrait's native 1080x1350 (4:5) proportions, so
     object-fit: cover below has nothing to crop at this box's own shape —
     it's only there as a safety net if a differently-shaped photo ever
     replaces this one. */
  aspect-ratio: 4 / 5;
  background: #e4e4e4;
  display: block;
  object-fit: cover;
}

.about-bio {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 620px;
  /* Left-aligned on desktop, where this box sits to the right of the photo
     (see the max-width: 800px override below, which re-centers everything
     once the two stack on mobile). */
  text-align: left;
  /* Column layout so the contact button (margin-top: auto, below) can be
     pushed down to the bottom of this box instead of sitting right under
     the paragraph. */
  display: flex;
  flex-direction: column;
}
.about-bio p {
  margin: 0;
  font-size: clamp(13px, 1.5vw, 16px);
  line-height: 1.6;
}

.contact-actions {
  /* auto pushes this to the bottom of .about-bio's column, which — since
     .about-intro now stretches .about-bio to the photo's full height — puts
     the button flush with the photo's bottom edge. On mobile (see the
     max-width: 800px override) .about-bio has no extra height to push
     into, so this has no visible effect there and the button just follows
     the paragraph as before. */
  margin-top: auto;
  padding-top: clamp(4px, 1vw, 8px);
  text-align: right;
}
.contact-btn {
  display: inline-block;
  border: 1px solid var(--black);
  padding: clamp(6px, 1vw, 10px) clamp(16px, 2.5vw, 24px);
  font-style: italic;
  font-size: clamp(13px, 1.5vw, 16px);
}
.contact-btn:hover,
.contact-btn:focus-visible {
  background: var(--black);
  color: var(--white);
}

/* ---- FAQ ----------------------------------------------------------------
   Its own content box, separate from .about-intro above. Two genuinely
   separate boxes (.faq-column), not one shared grid — see the markup
   comment in about.html for why: it lets the gap BETWEEN the two boxes
   (.faq-columns' gap) be set independently of the gap between items
   WITHIN a box (.faq-column's own gap), so they can be spaced apart more
   than a single grid's column-gap would allow. Adding a 4th question to
   a side is just adding another .faq-item to that .faq-column.
   -------------------------------------------------------------------------- */
.faq {
  /* Centers the heading and the two boxes below (both inherit this);
     .faq-columns additionally gets its own justify-content: center since
     centering a flex row needs that regardless of text-align on its
     container. */
  text-align: center;
}

.faq-heading {
  margin: 0 0 clamp(20px, 4vw, 32px);
  font-style: italic;
  font-size: clamp(20px, 3vw, 28px);
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

.faq-columns {
  display: flex;
  justify-content: center;
  /* The wider margin between the two boxes — independent of row-gap below,
     so this can grow on its own to match the original screenshot without
     also spacing out each box's own Q/A pairs. This is a real flex `gap`,
     not a margin trying to approximate one, so the two boxes are
     structurally incapable of overlapping regardless of how wide this
     grows or how narrow the screen gets — same guarantee .book-main's
     --main-gap gives the booking form/gallery pair. If the two columns
     ever don't have room to sit at their full max-width plus this gap,
     they shrink (flex's default behavior) rather than overlap or push
     off-screen. */
  gap: clamp(56px, 13vw, 180px);
}

.faq-column {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(20px, 4vw, 36px);
  max-width: 340px;
  /* Left-aligned within its own box, even though the pair of boxes is
     still centered as a group on the page via .faq-columns above (and the
     heading above that via .faq) — this only affects the text inside each
     box. */
  text-align: left;
}

.faq-item { min-width: 0; }

.faq-q,
.faq-a {
  margin: 0;
  /* Bumped up from the site's usual clamp(13px, 1.5vw, 16px) body-text
     scale — same ratio, just scaled by 1.5x so the max lands at 24px. */
  font-size: clamp(18px, 2.25vw, 24px);
  line-height: 1.5;
}
.faq-q { font-weight: 700; font-style: italic; }
.faq-a { margin-top: clamp(2px, 0.5vw, 4px); }
.faq-label {
  display: inline-block;
  width: 1.4em;
  font-weight: 700;
}

.book-cta-row {
  margin-top: clamp(32px, 6vw, 56px);
  text-align: center;
}
.book-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: clamp(140px, 20vw, 200px);
  padding: clamp(10px, 1.6vw, 14px) clamp(28px, 4vw, 40px);
  border-radius: 999px;
  background: var(--pink);
  color: var(--black);
  font-weight: 700;
  font-size: clamp(14px, 1.8vw, 18px);
}
.book-cta:hover,
.book-cta:focus-visible { opacity: 0.8; }

/* Mobile: photo/bio stack into one column, same 800px breakpoint .book-main
   uses for its own two-column collapse (centering itself is already the
   base behavior above, on every screen size — this just handles the
   structural stacking). The two FAQ boxes stack the same way — left box
   fully, then right box below it — rather than sitting side by side. */
@media (max-width: 800px) {
  .about-intro {
    flex-direction: column;
    align-items: center;
  }
  .about-bio { max-width: 100%; text-align: center; }
  .contact-actions { text-align: center; }

  .faq-columns {
    flex-direction: column;
    align-items: center;
  }
  .faq-column { max-width: 100%; }
}

/* ==========================================================================
   Artwork page
   Same white .site-header shell as the Book/Tattoos/About Me pages
   (.book-header / .page-title reused as-is). Gallery area reuses the same
   black-band + light-gray-box treatment as .portfolio-gallery/.portfolio-item
   on the Tattoos page, so the two "grid of pieces" pages read as one system.
   ========================================================================== */

.artwork-gallery {
  background: var(--black);
  padding: clamp(24px, 5vh, 56px) var(--pad-x) clamp(40px, 8vh, 80px);
}

/* ---- Grid -----------------------------------------------------------------
   A plain 2-column CSS Grid with `grid-auto-flow: dense`. The first item
   (.artwork-item--featured) is the only one with an explicit placement —
   pinned to column 1, spanning 3 rows. Because it's explicitly placed,
   normal auto-placement fills column 2 with the next three items (rows
   1-3), then — once column 1's spanned rows are full — wraps every
   subsequent item into new full-width rows of 2, same as a plain 2-up grid.

   To add a new piece in the future: copy one .artwork-item button and
   paste it at the end of .artwork-grid, after the last existing one.
   Nothing else needs to change — `dense` finds the next open cell on its
   own, the grid grows a new row automatically, and everything below (the
   footer) is pushed down in normal document flow — the same "just add
   another one" pattern as .portfolio-grid on the Tattoos page. */
.artwork-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-flow: dense;
  gap: clamp(8px, 3.2vw, 24px);
  max-width: 1400px;
  margin: 0 auto;
}

.artwork-item {
  aspect-ratio: 1 / 1;
  border: 0;
  padding: 0;
  background: #e4e4e4;
  color: #6b6b6b;
  font-family: inherit;
  font-style: italic;
  font-size: clamp(11px, 1.4vw, 15px);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}
.artwork-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.artwork-item:hover,
.artwork-item:focus-visible {
  outline: 2px solid var(--white);
  outline-offset: -2px;
}

/* The featured piece: pinned to column 1, spanning the same 3 rows that
   column 2 fills with its first three siblings. `aspect-ratio` is dropped
   back to `auto` here since a spanning grid item stretches to fill its
   whole grid area (3 row-tracks + 2 gaps) by default — a fixed 1/1 ratio
   would fight that stretch instead of letting it size the box. This item
   must stay the FIRST .artwork-item in the markup: dense auto-flow only
   fills gaps *around* an explicitly-placed item, so if this stops being
   first, the intended "tall piece beside a column of three" arrangement
   breaks. */
.artwork-item--featured {
  grid-column: 1;
  grid-row: span 3;
  aspect-ratio: auto;
}

/* Mobile only: same 1-column treatment as .portfolio-grid on the Tattoos
   page — each "flash tat" box gets the full width instead of squeezing two
   across a phone-width screen. The featured piece's grid-column/grid-row
   placement above only means something in the 2-column desktop layout (it
   pins the piece to column 1 and spans the 3 rows column 2's first three
   siblings fill); reset to auto/auto here so it behaves like every other
   item in a single column instead of trying to span 3 rows that no longer
   exist beside it. That reset is also what makes it read as a centered
   banner at the top of the stack — full width, own aspect ratio (still
   aspect-ratio: auto from the base rule above, untouched), everything else
   in a single square-tile column below it. Still a plain grid otherwise —
   adding a new piece later is still just pasting one more .artwork-item
   button at the end of the markup, same as the desktop layout. */
@media (max-width: 768px) {
  .artwork-grid {
    grid-template-columns: 1fr;
  }
  .artwork-item--featured {
    grid-column: auto;
    grid-row: auto;
  }
}

/* ==========================================================================
   Aftercare page
   Same white .site-header shell as the Book/Tattoos/About/Artwork pages
   (.book-header / .page-title reused as-is). Runs on the same white canvas
   as the Book/About pages, via the same background/color override pattern.
   Currently empty on purpose — .aftercare-main just needs flex: 1 0 auto so
   the footer still sits at the bottom of the viewport while it's blank,
   same as .book-main/.hero on the other pages; drop content in directly, no
   layout changes needed to fill it.
   ========================================================================== */
body.aftercare-page {
  background: var(--white);
  color: var(--black);
}
body.aftercare-page .site-footer { color: var(--black); }

/* flex + centering here is what vertically centers .aftercare-text in the
   blank space between the header and footer (same trick .hero uses for its
   hero-menu) — margin:0 auto alone only ever centers a block horizontally,
   it can't push it down into unused vertical space on its own. */
.aftercare-main {
  flex: 1 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(24px, 5vh, 56px) var(--pad-x) clamp(40px, 8vh, 80px);
}

/* Placeholder copy block: centered line-by-line (text-align) and, via the
   parent flex rules above, centered in the remaining page height too.
   max-width keeps lines readable instead of running edge-to-edge on wide
   screens — same convention as .about-bio's 620px cap. font-family isn't
   set here since it just inherits the site's --font (Anonymous Pro) from
   body already. */
.aftercare-text {
  max-width: 620px;
  text-align: center;
  font-size: 20px;
  line-height: 1.6;
}

/* Reduced motion: no animated transitions are used, but keep hover states
   simple and instant for users who prefer it. */
@media (prefers-reduced-motion: reduce) {
  * { scroll-behavior: auto !important; }
}