/* ---------- font: Sora, served from this site (not Google's servers, so
   no visitor IP reaches Google; see the privacy policy). It's a variable
   font, one file per character range covers both weights. SIL OFL, see
   fonts/Sora-OFL.txt ---------- */
@font-face {
  font-family: 'Sora';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../fonts/sora-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Sora';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../fonts/sora-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- reset ---------- */
* { box-sizing: border-box; }
html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  background: #f2e7e6; /* HSB(5, 5, 95) */
  color: #000000;
  overflow: hidden;
}
body {
  font-family: 'Sora', sans-serif;
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  cursor: none; /* replaced by the custom pen cursor, except over nav chrome */
  user-select: none;
}
/* Works has no drawing tools, so it uses the plain system cursor instead
   of the custom pen (see setupPenCursor in main.js) */
body.is-native-cursor, body.is-native-cursor * { cursor: default !important; }
/* anything clickable (links and buttons anywhere: nav, back, tools,
   swatches, zoom, the contact form) always wins over is-native-cursor and
   gets the standard "clickable" hand — this rule must come after
   is-native-cursor to win the tie on specificity */
body.is-nav-hover, body.is-nav-hover * { cursor: pointer !important; }
/* the book is a physical object on the desk: native open hand to show it
   can be picked up, closed hand while it's held */
body.is-book-hover, body.is-book-hover * { cursor: grab !important; }
body.is-grabbing, body.is-grabbing * { cursor: grabbing !important; }
/* every clickable image (works, piles, sketchbook tile) gets the standard
   pointing hand; must come after is-native-cursor to win the tie */
body.is-pointer-hover, body.is-pointer-hover * { cursor: pointer !important; }
/* the rest of the nav chrome and the floating controls (the space
   between tools, swatches, zoom) gets the plain arrow, whatever lies
   underneath; last, so it wins every tie */
body.is-ui-hover, body.is-ui-hover * { cursor: default !important; }
.stage-body__text { user-select: text; }
/* there for search engines and screen readers, not shown */
.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;
}
a { color: inherit; text-decoration: none; }
ul { list-style: none; margin: 0; padding: 0; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: none; }
img { -webkit-user-drag: none; user-select: none; }

/* ============================================================
   SITE TRACK — three stacked full-viewport stages (main /
   about / legal). The track only ever moves via nav clicks
   (see js/main.js initStages), so about/legal read as "another
   page" you scroll PAST into, not a slide-in panel.
   ============================================================ */
.site-track {
  width: 100%;
  will-change: transform;
}
.stage {
  height: 100vh;
  height: 100dvh; /* the visible window: phones' browser bars don't cover the bottom */
  width: 100%;
  position: relative;
}
.stage--main { overflow: hidden; }

/* ---------- navbar: [Works|Publications|Sketches] ... logo ... [About|Legal]
   A frosted glass bar over the page: what scrolls under it shows through
   blurred. It flies out to the top while the page scrolls down and comes
   back when it scrolls up (navScroll in main.js). The active page is bold;
   on hover and on the active page the letters are pushed and tilted at
   random (jumble). ---------- */
:root { --nav-h: 48px; }
.navbar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  height: var(--nav-h);
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  border-bottom: 0.5px solid #000000;
  font-size: 11.2px; /* 20% smaller than the base 14px */
  background: rgba(242, 231, 230, 0.55);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  backdrop-filter: blur(14px) saturate(1.3);
  transition: transform 0.5s cubic-bezier(0.3, 0, 0.2, 1);
}
/* far enough to take the logo hanging below the bar along */
.navbar.is-hidden { transform: translateY(calc(-100% - 40px)); }
/* above the open phone menu, so the logo hanging over it stays in front */
.navbar.is-menu-open { z-index: 910; }
.navbar-group { display: flex; align-items: stretch; }
.nav-link {
  display: flex;
  align-items: center;
  padding: 0 20px;
  white-space: nowrap;
}
.section-trigger, .navbar-group--right .nav-link { border-right: 0.5px solid #000000; }
.navbar-group--right .nav-link:last-child { border-right: none; }
/* centred on the window, not on the space between the two link groups
   (they differ in width, so flex centring would sit off-centre); taller
   than the bar, it hangs over its line into the page. The page under the
   overhang stays clickable */
.navbar-logo {
  position: absolute;
  top: 7px;
  left: 50%;
  transform: translateX(-50%);
  display: block;
  height: 66px;
  width: auto;
  pointer-events: none;
}
.nav-word { position: relative; display: inline-block; }
.nav-ch {
  display: inline-block;
  white-space: pre;
  transition: transform 0.45s cubic-bezier(0.3, 1.6, 0.5, 1);
}
/* the word keeps its bold width either way (see buildNavbar), so a link
   turning bold never pushes its neighbours */
.is-active > .nav-word, .nav-word.is-measuring { font-weight: 700; }
/* the active page's letters drift about like little clouds, hopping
   0.8px at a time up to 1.6px any way, choppy like the active tool's
   bob; each takes one of three paths at its own pace and phase (set per
   letter in buildNavbar). It moves the letter with `translate`, so the
   jumble's `transform` stays as it is. Hover only jumbles, no drift */
.is-active > .nav-word .nav-ch {
  animation: var(--drift, drift-a) var(--drift-dur, 2.2s) steps(1, end) var(--drift-delay, 0s) infinite;
}
@keyframes drift-a {
  0%, 100% { translate: 0 0; }
  12.5% { translate: 0.8px -0.8px; }
  25% { translate: 1.6px -0.8px; }
  37.5% { translate: 0.8px -1.6px; }
  50% { translate: 0 -1.6px; }
  62.5% { translate: -0.8px -0.8px; }
  75% { translate: -1.6px 0; }
  87.5% { translate: -0.8px 0.8px; }
}
@keyframes drift-b {
  0%, 100% { translate: 0 0; }
  12.5% { translate: -0.8px 0.8px; }
  25% { translate: -0.8px 1.6px; }
  37.5% { translate: 0.8px 1.6px; }
  50% { translate: 1.6px 0.8px; }
  62.5% { translate: 0.8px 0; }
  75% { translate: 0.8px -0.8px; }
  87.5% { translate: 0 -0.8px; }
}
@keyframes drift-c {
  0%, 100% { translate: 0 0; }
  12.5% { translate: -0.8px -0.8px; }
  25% { translate: -1.6px -0.8px; }
  37.5% { translate: -0.8px 0; }
  50% { translate: 0 0.8px; }
  62.5% { translate: 0.8px 1.6px; }
  75% { translate: 1.6px 0.8px; }
  87.5% { translate: 0.8px 0; }
}
@media (prefers-reduced-motion: reduce) {
  .is-active > .nav-word .nav-ch { animation: none; }
}

/* ---------- burger + mobile menu (≤780px) ---------- */
.navbar-burger {
  display: none;
  width: 48px;
  margin-left: auto;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border-left: 0.5px solid #000000;
}
.navbar-burger span {
  display: block;
  width: 18px;
  height: 1px;
  background: #000000;
  transition: transform 0.2s ease;
}
.navbar-burger.is-open span:first-child { transform: translateY(3.5px) rotate(45deg); }
.navbar-burger.is-open span:last-child { transform: translateY(-3.5px) rotate(-45deg); }
.mobile-menu {
  position: absolute;
  top: var(--nav-h);
  left: 0;
  right: 0;
  z-index: 900;
  background: #f2e7e6;
  border-bottom: 0.5px solid #000000;
}
.mobile-menu[hidden] { display: none; }
.mobile-menu__item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 16px 20px;
  font-size: 14px;
  border-bottom: 0.5px solid #000000;
}
.mobile-menu__item:last-child { border-bottom: none; }

@media (max-width: 780px) {
  .navbar-group { display: none; }
  .navbar-burger { display: flex; }
}

/* ---------- about / legal stage head — same bar as .navbar ---------- */
.stage-head {
  height: 48px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 20px;
  border-bottom: 0.5px solid #000000;
  font-size: 11.2px;
}
.stage-title { font-weight: 700; text-transform: capitalize; }
/* "back" jumbles on hover like the navbar's links */

/* ---------- sections (Works / Publications / Sketches) ---------- */
.section {
  position: absolute;
  top: var(--nav-h);
  left: 0;
  right: 0;
  bottom: 0;
  display: none;
  /* its own stacking context: a work or page brought to the front stays
     under the navbar */
  z-index: 0;
}
.section.is-active { display: block; }
/* Works and Publications run under the navbar; their content starts below it */
.section--works, .section--publications { top: 0; }

/* ---------- Works: a real masonry grid, each row-span computed in
   JS from the image's own rendered height (see layoutMasonry in
   main.js) so wide/tall/square images all pack together with no
   gaps and no per-image configuration. ---------- */
.section--works { overflow-y: auto; overflow-x: hidden; }
.works-grid {
  padding: 56px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 8px;
  --works-vgap: 80px;
  column-gap: 80px;
  row-gap: 0;
  align-content: start;
}
/* compact mode's sketchbook list uses the same columns as Works */
.sketchbook-list {
  display: none;
  padding: 56px;
  grid-template-columns: repeat(4, 1fr);
  gap: 40px;
  align-content: start;
}
.sketchbook-tile { display: block; width: 100%; text-align: left; }
.sketchbook-tile img { display: block; width: 100%; height: auto; }
.sketchbook-tile .works-caption { display: block; }
@media (max-width: 1100px) { .works-grid, .sketchbook-list { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 800px) { .works-grid, .sketchbook-list { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) {
  .works-grid, .sketchbook-list { grid-template-columns: 1fr; padding: 24px 16px; gap: 32px; }
  .works-grid { --works-vgap: 32px; row-gap: 0; }
}
.works-grid, .section--publications .sketchbook-list { padding-top: calc(var(--nav-h) + 56px); }
@media (max-width: 520px) {
  .works-grid, .section--publications .sketchbook-list { padding-top: calc(var(--nav-h) + 24px); }
}
.works-item { position: relative; }
.works-item, .pub-item, .pub-tile {
  transition: opacity 0.7s ease-out, transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* not shown yet: waits a little lower, invisible, until it scrolls into
   view and its image has loaded (see revealOnView in main.js); the
   publications come in the same way */
.works-item.is-waiting, .pub-item.is-waiting, .pub-tile.is-waiting { opacity: 0; transform: translateY(32px); }
@media (prefers-reduced-motion: reduce) {
  .works-item.is-waiting, .pub-item.is-waiting, .pub-tile.is-waiting { transform: none; }
}
/* "featured" projects (a quarter, picked at random on every load, none
   touching another; see arrangeLarge in main.js) take two columns;
   dense packing back-fills the gap
   the wider item would otherwise leave in the row above */
.works-grid { grid-auto-flow: dense; }
.works-item.is-featured { grid-column: span 2; }
@media (max-width: 520px) { .works-item.is-featured { grid-column: auto; } }
.works-media { position: relative; will-change: transform; }
.works-item img {
  display: block;
  width: 100%;
  height: auto;
  position: relative;
  z-index: 1;
}
.works-caption {
  margin-top: 10px;
  font-size: 12px;
  line-height: 1.4;
}
.works-caption .works-year { opacity: 0.6; }

/* multi-image projects: a tilted pile, like papers left on a desk. Each
   sheet keeps its own natural aspect ratio (matching a plain, non-pile
   image) instead of being force-cropped to the last image's box — that
   forced object-fit:cover made mismatched-ratio images zoom in and crop
   heavily. */
.works-item.is-pile img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: auto;
  transition: transform 0.25s ease;
}
.works-item.is-pile img:last-of-type { position: relative; }
/* a tilted back sheet's corner can reach below the pile; keep the caption on top */
.works-item.is-pile .works-caption { position: relative; z-index: 2; }

/* ---------- Publications: the printed pages scattered on a desk that
   runs on below the window (buildPublications in main.js places them).
   The desk is the section's zoom layer: the wheel pans it, so there is
   no scrollbar; neither has the list on a phone ---------- */
.section--publications { overflow: hidden; scrollbar-width: none; }
/* on a tablet's screen every touch here is ours: drawing, dragging, the
   two-finger pan and pinch (setupTouch); compact mode scrolls them again */
.section--sketches, .section--publications { touch-action: none; }
.tool-pill, .zoom-control, .color-popover { touch-action: manipulation; }
.section--publications::-webkit-scrollbar { display: none; }
.pub-desk { z-index: 0; }
.pub-item { position: absolute; display: block; touch-action: none; }

/* ---------- Sketches: the book on its own free stage ---------- */
/* graph paper, modelled on a scanned notebook page: a 25px square grid of
   soft ~2px lines that only darken the paper slightly — verticals ~10%,
   horizontals just ~3% — so it reads as printed, not as a drawn grid */
.section--sketches {
  overflow: hidden;
  background-image:
    linear-gradient(to right, rgba(0, 0, 0, 0.095) 0 var(--grid-line, 2px), transparent var(--grid-line, 2px)),
    linear-gradient(to bottom, rgba(0, 0, 0, 0.03) 0 var(--grid-line, 2px), transparent var(--grid-line, 2px));
  background-size: 25px 25px;
  background-position: 12px 12px;
}
/* its own stacking context: however high the books' z-index climbs as they
   are picked up, they stay under the drawing canvas */
.sketches-stage { position: relative; z-index: 0; width: 100%; height: 100%; }

/* ---------- zoom: Sketches and Publications scale everything inside
   their .zoom-layer (JS sets translate + scale from the top-left) ---------- */
.zoom-layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transform-origin: 0 0;
}
.zoom-control {
  position: fixed;
  left: 50%;
  bottom: 24px;
  z-index: 850;
  display: none; /* JS shows it on Sketches and Publications */
  align-items: center;
  gap: 8px;
  font-size: 11.2px;
}
/* the label, then Lisa's drawn + and − (each a little circle of its own,
   31px across); hover grows them 10% */
.zoom-btn {
  width: 31px;
  height: 31px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #000000;
  transition: transform 0.15s ease, opacity 0.15s ease;
}
.zoom-btn svg { flex: none; overflow: visible; }
@media (hover: hover) { .zoom-btn:hover { transform: scale(1.1); } }
.zoom-btn:disabled, .zoom-btn:disabled:hover { opacity: 0.25; transform: none; }
.zoom-label {
  min-width: 34px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  transition: opacity 0.15s ease;
}
.zoom-label:hover { opacity: 0.6; }

/* ---------- book (StPageFlip — a real turn.js-style page curl,
   MIT licensed; see js/main.js for why not turn.js itself) ---------- */
/* only the visible cover/pages take the pointer — the closed book sits in
   the right half of its box, and the empty half shouldn't show a grab hand
   or swallow drawing strokes */
.book-item { position: absolute; touch-action: none; pointer-events: none; }
.book-frame { position: absolute; inset: 0; padding: 14px; }
.book-cover-static { position: absolute; top: 14px; bottom: 14px; left: 50%; right: 14px; pointer-events: auto; }
.book-cover-static img { width: 100%; height: 100%; object-fit: contain; pointer-events: none; display: block; }
.book-flipbook { width: 100%; height: 100%; }
.book-flipbook .stpf-page { pointer-events: auto; }
.book-flipbook.is-preparing { visibility: hidden; }
.stpf-page { background: transparent; overflow: hidden; }
.stpf-page img { width: 100%; height: 100%; object-fit: contain; display: block; pointer-events: none; }

/* ---------- lightbox: one image at a time. The backdrop is tinted with
   the image's median colour (set inline from JS, along with --lb-ink, black
   or white, whichever reads on it). Left/right half of the screen show a
   back/forward arrow cursor and step through the project. ---------- */
.lightbox {
  --lb-ink: #000000;
  position: fixed;
  inset: 0;
  z-index: 900;
  background: #f2e7e6;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--lb-ink);
  cursor: default;
  transition: background-color 0.4s ease, color 0.4s ease;
}
.lightbox[hidden] { display: none; }
/* thin arrows with a shaft, drawn in the same ink as the caption (black on
   light backdrops, white on dark ones, see .is-ink-light) */
.lightbox.is-multi.is-left { cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cpath d='M27 16H5M12 9l-7 7 7 7' fill='none' stroke='%23000' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 5 16, w-resize; }
.lightbox.is-multi.is-right { cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cpath d='M5 16h22M20 9l7 7-7 7' fill='none' stroke='%23000' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 27 16, e-resize; }
.lightbox.is-multi.is-ink-light.is-left { cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cpath d='M27 16H5M12 9l-7 7 7 7' fill='none' stroke='%23fff' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 5 16, w-resize; }
.lightbox.is-multi.is-ink-light.is-right { cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cpath d='M5 16h22M20 9l7 7-7 7' fill='none' stroke='%23fff' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 27 16, e-resize; }
.lightbox-inner {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  pointer-events: none;
}
.lightbox-img { display: block; max-width: 80vw; max-height: 78vh; width: auto; height: auto; }
.lightbox-caption .works-year { opacity: 0.6; }
.lightbox-close {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--lb-ink);
  cursor: pointer !important;
  transition: opacity 0.15s ease;
}
.lightbox-close:hover { opacity: 0.6; }
/* page dots: only in compact mode (see below). Five fit the window; the
   track slides so the current dot stays in the middle, and the outer two
   fade when there are more beyond them */
.lightbox-dots {
  --dot: 6px;
  --dot-gap: 8px;
  position: absolute;
  left: 50%;
  bottom: calc(24px + env(safe-area-inset-bottom, 0px));
  width: calc(5 * var(--dot) + 4 * var(--dot-gap));
  transform: translateX(-50%);
  overflow: hidden;
  display: none;
  pointer-events: none;
}
.lightbox-dots__track {
  display: flex;
  gap: var(--dot-gap);
  transition: transform 0.3s ease;
}
.lightbox-dot {
  flex: none;
  width: var(--dot);
  height: var(--dot);
  border-radius: 50%;
  background: var(--lb-ink);
  opacity: 0.35;
  transition: opacity 0.3s ease, transform 0.3s ease, background-color 0.4s ease;
}
.lightbox-dot.is-active { opacity: 1; }
.lightbox-dot.is-edge { opacity: 0.15; transform: scale(0.7); }
@media (max-width: 780px), (hover: none) and (pointer: coarse) {
  .lightbox-img { max-width: calc(100vw - 32px); max-height: 72vh; }
  /* no arrow cursors on a phone; horizontal swipes belong to the lightbox */
  /* pan-y first: browsers that don't know pinch-zoom (Safari) keep it */
  .lightbox.is-multi { cursor: auto !important; touch-action: pan-y; touch-action: pan-y pinch-zoom; }
  .lightbox.is-multi .lightbox-dots { display: block; }
}

/* ============================================================
   COMPACT MODE — phones and narrow windows (below 744px, or a touch
   screen under 500px tall). Keep the query in sync with compactMQ in
   main.js. No drawing, no tool pill, no custom cursor; the sketchbook
   becomes a tile that opens in the lightbox. Tablets get the full site.
   ============================================================ */
@media (max-width: 743px), (hover: none) and (pointer: coarse) and (max-height: 500px) {
  body { cursor: auto; }
  button, a, .works-item, .sketchbook-tile { cursor: pointer; }
  .tool-pill, .color-popover, .tool-tip, .pen-cursor,
  .draw-layer, .sketches-stage, .zoom-control { display: none !important; }
  .zoom-layer { display: none !important; }
  .section--sketches, .section--publications { overflow-y: auto; touch-action: auto; }
  .sketchbook-list { display: grid; }
  /* the sketchbook list runs under the navbar too, like Works */
  .section--sketches { top: 0; }
  .section--sketches .sketchbook-list { padding-top: calc(var(--nav-h) + 56px); }
}
@media (max-width: 520px) {
  .section--sketches .sketchbook-list { padding-top: calc(var(--nav-h) + 24px); }
}

/* ============================================================
   ABOUT / LEGAL body — ported from the "portfolio-gsap" project
   ============================================================ */
.stage-body {
  max-width: 640px;
  padding: 48px 40px 40px;
  display: flex;
  flex-direction: column;
  gap: 40px;
  overflow-y: auto;
  height: calc(100vh - 48px);
  height: calc(100dvh - 48px);
}
.stage-body__text { font-size: 13px; line-height: 1.75; white-space: pre-line; }
.stage-body__block { display: flex; flex-direction: column; gap: 10px; }
.stage-body__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em; opacity: 0.55; }
/* running text with headings (the privacy policy): normal wrapping */
.stage-body__text--flow { white-space: normal; }
.stage-body__text--flow h3 { font-size: 13px; font-weight: 700; margin: 22px 0 4px; }
.stage-body__text--flow h3:first-child { margin-top: 0; }
.stage-body__text--flow p { margin: 0; }
.stage-body__text--flow p + p { margin-top: 8px; }
.stage-body__text--flow a { text-decoration: underline; text-underline-offset: 2px; }
.stage-body__note { margin-top: 22px !important; opacity: 0.55; }

/* Legal is long: the whole page scrolls (scrollbar at the window's edge),
   not a box inside it; its bar stays put at the top */
.stage--legal { overflow-y: auto; }
.stage--legal .stage-body { height: auto; overflow: visible; }
.stage--legal .stage-head { position: sticky; top: 0; z-index: 1; background: #f2e7e6; }

.stage-body--about { max-width: 1100px; }
.about-grid {
  display: flex;
  align-items: stretch;
  flex: 1;
  margin: -48px -40px -40px;
}
.about-col--text {
  width: 40%; padding: 48px 40px; border-right: 0.5px solid #000000;
  display: flex; flex-direction: column; gap: 28px;
}
/* the portrait takes whatever height the column has left above the
   text; the img is absolutely placed so it never adds height of its
   own, i.e. the section keeps its size and the photo scales to fit */
.about-portrait { position: relative; flex: 1 1 0; min-height: 160px; }
.about-portrait img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; object-position: left top;
}
.about-col--contact { width: 60%; padding: 48px 40px; }

.contact-box { border: 0.5px solid #000000; }
.contact-form { display: flex; flex-direction: column; }
.contact-form__field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px 20px;
  border-bottom: 0.5px solid #000000;
}
.contact-form__field span { font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.55; }
.contact-form__field input,
.contact-form__field textarea {
  font-family: inherit;
  font-size: 13px;
  color: inherit;
  background: transparent;
  border: none;
  padding: 0;
  outline: none;
  cursor: text;
}
.contact-form__field textarea { resize: vertical; min-height: 70px; }
.contact-form__footer { padding: 0; }
.contact-form__send {
  display: block;
  width: 100%;
  text-align: center;
  padding: 14px 20px;
  font-size: 13px;
  font-weight: 500;
  cursor: none;
  transition: background 0.2s ease, color 0.2s ease;
}
.contact-form__send:hover { background: #000000; color: #f2e7e6; }
.contact-form__send:disabled { background: none; color: inherit; opacity: 0.55; }
.contact-form__error { margin: 0; padding: 14px 20px; font-size: 12px; border-bottom: 0.5px solid #000000; }
.contact-form__error a { text-decoration: underline; text-underline-offset: 2px; }
.contact-done { display: flex; align-items: center; justify-content: space-between; padding: 14px 20px; }
/* display:flex above would otherwise override the hidden attribute */
.contact-form[hidden], .contact-done[hidden] { display: none; }
.contact-done__reset { font-weight: 500; transition: opacity 0.15s ease; }
.contact-done__reset:hover { opacity: 0.7; }
.contact-alt { margin-top: 18px; font-size: 12px; }
.contact-alt__link { border-bottom: 0.5px solid #000000; padding-bottom: 1px; transition: opacity 0.15s ease; }
.contact-alt__link:hover { opacity: 0.7; }
.panel-list { margin-top: 20px; }
.panel-list li + li { margin-top: 6px; }
.panel-list a { transition: opacity 0.15s ease; }
.panel-list a:hover { opacity: 0.7; }

@media (max-width: 780px) {
  .about-grid { flex-direction: column; }
  .about-col--text, .about-col--contact { width: 100%; }
  .about-col--text { border-right: none; border-bottom: 0.5px solid #000000; }
  .about-portrait { flex: none; height: 50vh; min-height: 0; }
}

/* ---------- freehand drawing layers (one per drawable section) ----------
   canvas is a "replaced element": position:fixed/absolute + inset alone
   does NOT stretch it the way it would a div, so width/height must be
   set explicitly or it silently stays at the 300x150 default. */
.draw-layer {
  position: absolute;
  top: 0;
  left: 0;
  /* JS sets the real px size (it only ever grows, see setupDrawingFor);
     100% is just the starting size */
  width: 100%;
  height: 100%;
  z-index: 800;
  pointer-events: none;
}

/* ============================================================
   TOOL PILL — a column of Lisa's drawn tools, no circles: pencil,
   brush, marker, color (a circle filled with the drawing colour),
   eraser, clear-canvas. A hovered one grows 10% with an easy ease; the
   active tool bobs up and down a pixel at a time, choppy like an 8-bit
   game.
   ============================================================ */
.tool-pill {
  --easy-ease: cubic-bezier(0.33, 0, 0.67, 1);
  position: fixed;
  top: 50%;
  right: 24px;
  transform: translateY(-50%);
  z-index: 850;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.tool-btn {
  position: relative;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #000000;
  transition: transform 0.3s var(--easy-ease), background-color 0.3s var(--easy-ease);
}
/* the drawings share one artboard, 35px wide (the eraser's drawing is
   smaller on it, so it gets a bigger one to look as big as the rest);
   they hang over the 32px buttons */
.tool-btn svg { width: 35.2px; height: auto; flex: none; }
.tool-btn[data-tool="eraser"] svg { width: 41.6px; }
/* hover only where there is one: a tapped tool on a tablet doesn't stay big */
@media (hover: hover) { .tool-btn:hover { transform: scale(1.1); } }
.tool-btn.is-open { transform: scale(1.1); }
/* the bob moves the drawing, the hover grows the button: they add up */
.tool-btn.is-active svg { animation: tool-bob 0.8s steps(1, end) infinite; }
@keyframes tool-bob {
  0% { transform: translateY(0); }
  25% { transform: translateY(-1px); }
  50% { transform: translateY(-2px); }
  75% { transform: translateY(-1px); }
}
@media (prefers-reduced-motion: reduce) {
  .tool-btn.is-active svg { animation: none; }
}
.tool-color { width: 25.6px; height: 25.6px; border-radius: 50%; background: var(--tool-bg); }
/* the drawings fill their boxes unevenly, so the 8px gap alone leaves
   uneven space between what you see; these even it out to ~13.5px of
   paper between neighbours (measured on the rendered pill) */
.tool-btn[data-tool="marker"] { margin-top: 2px; }
.tool-color { margin-top: 3px; }
.tool-btn[data-tool="eraser"] { margin-top: 4px; }
#tool-refresh-btn { margin-top: -1px; }
/* ---------- color swatches: a cloud of circles that shoots out from
   behind the color button (JS places and animates them); the popover
   itself is a point at the button's centre, under the pill ---------- */
.color-popover {
  position: fixed;
  z-index: 840;
  width: 0;
  height: 0;
}
/* just the colour itself: no hover or active look */
.swatch {
  position: absolute;
  left: -12.8px;
  top: -12.8px;
  width: 25.6px;
  height: 25.6px;
  border-radius: 50%;
  background: var(--sw);
  cursor: none;
  pointer-events: none;
}
.color-popover.is-open .swatch { pointer-events: auto; }

/* ---------- tooltip ---------- */
.tool-tip {
  position: fixed;
  z-index: 870;
  background: #000000;
  color: #ffffff;
  font-size: 11px;
  padding: 4px 8px;
  white-space: nowrap;
  pointer-events: none;
}

/* ---------- custom pen cursor ---------- */
.pen-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 999;
  pointer-events: none;
  transform: translate(-2px, -20px);
  display: flex;
  align-items: flex-end;
  gap: 6px;
}
.pen-cursor__icon { display: block; }
.pen-cursor.is-hidden { display: none; }
