/* ============================================================
   Leyla Mozayen — Catalogue, v2 "the workshop catalogue"
   Palette: her materials — ochre of the yellow piece, fur browns,
   madder rust, bone — over the umber ground of her painting.
   Shell + Studio machinery: the proven v1 base, re-tokened.
   Public surface: the workshop language (threads, tags, register).
   ============================================================ */
/* ============================================================
   v2 — the workshop catalogue
   ------------------------------------------------------------
   Palette: her materials, not a designer's palette. The ochre of
   the yellow piece (#f0c018/#d89000), fur browns (#604830,
   #907860), madder rust (#783030), bone (#a89078) — over the
   umber ground of her painting. Accent = the yellow piece,
   because that object is the most "her" thing on the page.

   The language: everything hangs, tags swing, threads connect,
   the register numbers things deadpan. Assembled, not designed.
   ============================================================ */

:root {
  /* ground — umber black from her painting's darks */
  --ink:        #0e0a07;
  --ink-raised: #191009;
  --ink-line:   rgba(237, 226, 203, 0.13);

  /* type — bone, from the mannequin */
  --paper:      #ede2cb;
  --paper-dim:  #c7b699;
  --paper-faint:#97876c;

  /* accents — her materials */
  --ember:      #e6b41e;   /* the yellow piece */
  --ember-lift: #f3cf53;
  --copper:     #8a6f52;   /* fur brown */
  --madder:     #b0512e;   /* rust red — marks, live dots */

  --font-display: 'Instrument Serif', Georgia, serif;
  --font-body:    'Inter', system-ui, sans-serif;
  --font-script:  'La Belle Aurore', cursive;
  --font-mono:    'IBM Plex Mono', ui-monospace, 'SFMono-Regular', monospace;

  --bar-h: 62px;
  --pad: clamp(1.25rem, 5vw, 5rem);
  --measure: 62ch;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}


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

/* The `hidden` attribute is only enforced by the UA sheet's [hidden]{display:none},
   which ANY author rule setting display silently beats. That is not a theoretical
   risk here: `.gd__panel{display:flex}` left the guide panel permanently open over
   the page, and `.btn{display:inline-flex}` did the same to every button that is
   supposed to start hidden. This makes the attribute mean what it says. */
[hidden] { display: none !important; }

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

body {
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-body);
  font-weight: 300;
  line-height: 1.6;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  min-height: 100svh;
}

body[data-booting] .stage { opacity: 0; }

img { max-width: 100%; display: block; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
a { color: inherit; text-decoration: none; }

::selection { background: var(--ember); color: var(--ink); }

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

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--ember); color: var(--ink); padding: .75rem 1.25rem;
}
.skip-link:focus { left: 0; }

/* ---------- atmosphere: her artwork, heavily restrained ---------- */

.atmosphere {
  position: fixed; inset: 0; z-index: -2;
  overflow: hidden; pointer-events: none;
  background: var(--ink);
}
.atmosphere__img {
  position: absolute; inset: -8%;
  background: url('assets/mainphoto.jpeg') center/cover no-repeat;
  /* pushed well back so type always wins */
  filter: brightness(.34) saturate(.9) contrast(1.05);
  transform: scale(1.04);
  animation: drift 48s ease-in-out infinite alternate;
}
.atmosphere::after {
  content: ''; position: absolute; inset: 0;
  background:
    radial-gradient(120% 90% at 50% 18%, rgba(10,8,7,0) 0%, rgba(10,8,7,.72) 58%, var(--ink) 100%),
    linear-gradient(to bottom, rgba(10,8,7,.55) 0%, rgba(10,8,7,.2) 30%, rgba(10,8,7,.9) 100%);
}
@keyframes drift {
  from { transform: scale(1.04) translate3d(0,0,0); }
  to   { transform: scale(1.12) translate3d(-1.5%, -2%, 0); }
}

.grain {
  position: fixed; inset: 0; z-index: 60; pointer-events: none;
  opacity: .05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- top bar ---------- */

.topbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 70;
  height: var(--bar-h);
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 var(--pad);
  /* NOTE: no backdrop-filter / transform / filter on this element.
     Any of them would make .topbar the containing block for its own
     position:fixed children, which collapses the mobile nav overlay to the
     height of the bar. The blur lives on ::before instead. */
}
.topbar::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  /* a plain scrim, no backdrop-filter: the frosted strip read as a glass
     band framing the page, and it blurred the tops of the hanging pieces */
  background: linear-gradient(to bottom, rgba(14,10,7,.88), rgba(14,10,7,0));
  pointer-events: none;
}

.mark { display: flex; align-items: baseline; gap: .6rem; min-width: 0; }
.mark__script {
  font-family: var(--font-script);
  font-size: 1.75rem; line-height: 1; color: var(--paper);
  white-space: nowrap;
}
.mark__sub {
  font-size: .62rem; letter-spacing: .28em; text-transform: uppercase;
  color: var(--paper-faint); white-space: nowrap;
}

.nav { display: flex; align-items: center; gap: clamp(1rem, 2.5vw, 2.25rem); }
.nav a, .nav__studio {
  font-size: .68rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--paper-dim); padding: .5rem 0;
  border-bottom: 1px solid transparent;
  transition: color .3s, border-color .3s;
  white-space: nowrap;
}
.nav a:hover, .nav__studio:hover { color: var(--paper); }
.nav a[aria-current="page"] { color: var(--paper); border-bottom-color: var(--ember); }
.nav__studio { color: var(--paper-faint); }

.burger { display: none; width: 34px; height: 34px; position: relative; flex: 0 0 auto; }
.burger span {
  position: absolute; left: 6px; right: 6px; height: 1px; background: var(--paper);
  transition: transform .34s var(--ease), opacity .2s;
}
.burger span:first-child { top: 13px; }
.burger span:last-child  { top: 20px; }

/* ---------- stage / views ---------- */

.stage {
  position: relative; z-index: 1;
  padding: calc(var(--bar-h) + 2rem) var(--pad) 6rem;
  min-height: 100svh;
  transition: opacity .5s var(--ease);
  outline: none;
}

.view { animation: rise .7s var(--ease) both; }
@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- section heading ---------- */

.sec-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1.5rem; flex-wrap: wrap;
  padding-bottom: 1.25rem; margin-bottom: 2.5rem;
  border-bottom: 1px solid var(--ink-line);
}
.sec-head h2 {
  font-family: var(--font-display); font-weight: 300;
  font-size: clamp(1.6rem, 4vw, 2.6rem); letter-spacing: -.01em;
}
.sec-head__count {
  font-size: .68rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--paper-faint);
}

/* ---------- back link ---------- */

.back {
  display: inline-flex; align-items: center; gap: .6rem;
  font-size: .68rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--paper-faint); margin-bottom: 2.25rem;
  transition: color .3s, gap .3s var(--ease);
}
.back:hover { color: var(--ember); gap: 1rem; }

/* ---------- empty state ---------- */

.empty {
  border: 1px dashed var(--ink-line); padding: clamp(2rem, 6vw, 4rem);
  text-align: center; color: var(--paper-faint);
}
.empty h3 {
  font-family: var(--font-display); font-weight: 300; font-size: 1.35rem;
  color: var(--paper-dim); margin-bottom: .75rem;
}
.empty p { font-size: .9rem; max-width: 42ch; margin: 0 auto; }

/* ---------- prose page (about / contact) ---------- */

.page { max-width: var(--measure); }
.page h1 {
  font-family: var(--font-display); font-weight: 300;
  font-size: clamp(2rem, 6vw, 3.4rem); line-height: 1.05;
  margin-bottom: 2rem; letter-spacing: -.015em;
}
.page a[href^="mailto"], .page a[href^="http"] {
  color: var(--ember); border-bottom: 1px solid rgba(216,120,74,.4);
}

.contact-list { display: grid; gap: 1rem; margin-top: 2.5rem; }
.contact-list a {
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  padding: 1.1rem 0; border-bottom: 1px solid var(--ink-line);
  font-size: .72rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--paper-dim); transition: color .3s;
}
.contact-list a:hover { color: var(--ember); }
.contact-list span:last-child { color: var(--paper-faint); text-transform: none; letter-spacing: normal; }

/* ============================================================
   STUDIO (admin)
   ============================================================ */

.studio { max-width: 900px; }
.studio__bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  padding-bottom: 1.25rem; margin-bottom: 2rem;
  border-bottom: 1px solid var(--ink-line);
}
.studio__bar h1 {
  font-family: var(--font-display); font-weight: 300; font-size: 1.75rem;
}
.studio__tag {
  font-size: .6rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--ink); background: var(--ember); padding: .3rem .6rem;
}

.panel {
  background: rgba(20,16,16,.72); border: 1px solid var(--ink-line);
  padding: clamp(1.25rem, 3vw, 2rem); margin-bottom: 1.5rem;
}
.panel > h2 {
  font-family: var(--font-display); font-weight: 300; font-size: 1.2rem;
  margin-bottom: 1.25rem;
}

.field { display: grid; gap: .45rem; margin-bottom: 1.1rem; }
.field > label {
  font-size: .64rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--paper-faint);
}
/* Type-agnostic on purpose. Enumerating input types meant adding type="email"
   for the sign-in form silently fell through to the browser default, painting a
   white box on a black page. Anything that is not a checkbox or radio is a text
   field here. */
.field input:not([type="checkbox"]):not([type="radio"]),
.field textarea,
.field select {
  width: 100%; background: #0d0a09; border: 1px solid var(--ink-line);
  color: var(--paper); padding: .8rem .9rem; font-family: var(--font-body);
  font-size: .95rem; border-radius: 0;
}
.field textarea { min-height: 150px; resize: vertical; line-height: 1.7; }
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-color: var(--ember);
}
.field__hint { font-size: .72rem; color: var(--paper-faint); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  padding: .85rem 1.5rem; background: var(--ember); color: var(--ink);
  font-size: .68rem; letter-spacing: .18em; text-transform: uppercase;
  font-weight: 500; transition: background .3s, opacity .3s;
}
.btn:hover { background: var(--ember-lift); }
.btn[disabled] { opacity: .45; cursor: not-allowed; }
.btn--ghost {
  background: none; border: 1px solid var(--ink-line); color: var(--paper-dim);
}
.btn--ghost:hover { background: none; border-color: var(--ember); color: var(--ember); }
.btn--danger { background: none; border: 1px solid #6b2a22; color: #c9705c; }
.btn--danger:hover { background: #6b2a22; color: var(--paper); }

.row { display: flex; gap: .75rem; flex-wrap: wrap; align-items: center; }

/* drop zone */
.drop {
  border: 1px dashed var(--ink-line); padding: 2rem 1rem; text-align: center;
  color: var(--paper-faint); transition: border-color .3s, background .3s;
  cursor: pointer;
}
.drop[data-over] { border-color: var(--ember); background: rgba(216,120,74,.06); }
.drop strong { display: block; color: var(--paper-dim); font-weight: 400; margin-bottom: .35rem; }
.drop small { font-size: .72rem; }

.thumbs { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: .6rem; margin-top: 1rem; }
.thumb { position: relative; aspect-ratio: 1; background: var(--ink-raised); }
.thumb img { width: 100%; height: 100%; object-fit: cover; }
.thumb button {
  position: absolute; top: 3px; right: 3px; width: 22px; height: 22px;
  background: rgba(10,8,7,.85); color: var(--paper); font-size: .8rem; line-height: 1;
}
.thumb button:hover { background: #6b2a22; }

/* admin list rows */
.admin-row {
  display: flex; align-items: center; gap: 1rem;
  padding: .85rem 0; border-bottom: 1px solid var(--ink-line);
}
.admin-row__thumb { width: 46px; height: 46px; object-fit: cover; background: var(--ink-raised); flex: 0 0 auto; }
.admin-row__main { flex: 1; min-width: 0; }
.admin-row__main strong { display: block; font-weight: 400; font-size: .95rem; }
.admin-row__main small { color: var(--paper-faint); font-size: .72rem; }
.admin-row__acts { display: flex; gap: .4rem; flex: 0 0 auto; }
.admin-row__acts button {
  font-size: .62rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--paper-faint); padding: .4rem .6rem; border: 1px solid var(--ink-line);
}
.admin-row__acts button:hover { color: var(--ember); border-color: var(--ember); }

.storage-note {
  font-size: .72rem; color: var(--paper-faint); line-height: 1.7;
  border-left: 2px solid var(--copper); padding-left: .9rem; margin-top: 1rem;
}

/* toast */
.toast {
  position: fixed; left: 50%; bottom: 1.5rem; transform: translate(-50%, 250%);
  background: var(--ink-raised); border: 1px solid var(--ink-line);
  border-left: 2px solid var(--ember);
  padding: .85rem 1.25rem; font-size: .82rem; z-index: 120;
  transition: transform .4s var(--ease); max-width: calc(100vw - 2rem);
}
.toast[data-on] { transform: translate(-50%, 0); }
.toast[data-kind="error"] { border-left-color: #c9705c; }

/* ============================================================
   MOBILE — the thing that was broken
   ============================================================ */

@media (max-width: 820px) {
  .burger { display: block; z-index: 80; }

  .nav {
    position: fixed; inset: 0;
    flex-direction: column; align-items: flex-start; justify-content: center;
    gap: 1.75rem;
    padding: 0 var(--pad);
    background: rgba(10,8,7,.97);
    backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    transform: translateY(-100%);
    transition: transform .5s var(--ease);
    z-index: 75;
  }
  .nav[data-open] { transform: none; }
  .nav a, .nav__studio {
    font-family: var(--font-display); font-size: 2rem; letter-spacing: 0;
    text-transform: none; color: var(--paper-dim); border: none; padding: 0;
  }
  .nav a[aria-current="page"] { color: var(--ember); }

  .burger[aria-expanded="true"] span:first-child { transform: translateY(3.5px) rotate(45deg); }
  .burger[aria-expanded="true"] span:last-child  { transform: translateY(-3.5px) rotate(-45deg); }

  /* the mark must never collide with the nav again */
  .mark__sub { display: none; }

  .index-row {
    grid-template-columns: 2.25rem 1fr;
    gap: .9rem;
  }
  .index-row__n { grid-column: 2; margin-top: .1rem; }
  .index-row:hover, .index-row:focus-visible { padding-left: .25rem; }
}

@media (max-width: 420px) {
  .mark__script { font-size: 1.45rem; }
}

/* reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .atmosphere__img { animation: none; }
}

/* example-content notice — removed with the demo data */

/* ============================================================
   Archive-scale Studio + lightbox (wave 2)
   ============================================================ */

.statgrid {
  display: flex; flex-wrap: wrap; gap: .75rem 2rem;
  font-size: .78rem; color: var(--paper-faint);
}
.statgrid b { color: var(--paper); font-weight: 400; }
.statgrid .stat--flag b { color: var(--ember); }

.panel--intake { border-color: rgba(216,120,74,.32); }

.drop--lg { padding: 3rem 1rem; }

.intake-progress {
  margin-top: 1rem; font-size: .78rem; color: var(--ember);
  font-variant-numeric: tabular-nums;
}

/* toolbar: search + filter tabs */
.toolbar {
  display: flex; flex-wrap: wrap; gap: .75rem; align-items: center;
  justify-content: space-between; margin-bottom: 1.25rem;
}
.toolbar input[type="search"] {
  flex: 1 1 220px; min-width: 0;
  background: #0d0a09; border: 1px solid var(--ink-line); color: var(--paper);
  padding: .7rem .85rem; font-family: var(--font-body); font-size: .9rem;
}
.toolbar input[type="search"]:focus { outline: none; border-color: var(--ember); }

.tabs { display: flex; flex-wrap: wrap; gap: .35rem; }
.tabs button {
  font-size: .62rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--paper-faint); padding: .5rem .7rem;
  border: 1px solid var(--ink-line); white-space: nowrap;
  transition: color .25s, border-color .25s;
}
.tabs button:hover { color: var(--paper-dim); }
.tabs button[aria-selected="true"] {
  color: var(--ink); background: var(--ember); border-color: var(--ember);
}

.pill {
  display: inline-block; margin-left: .45rem; padding: .1rem .4rem;
  font-size: .58rem; letter-spacing: .12em; text-transform: uppercase;
  border: 1px solid var(--ink-line); color: var(--paper-faint);
}

/* inline series editor */
.inline-edit {
  border-left: 2px solid var(--ember);
  padding: 1.25rem 0 1.25rem 1.25rem;
  margin: 0 0 1rem;
  background: rgba(216,120,74,.04);
}

.newseries { margin-top: 1.5rem; border-top: 1px solid var(--ink-line); padding-top: 1.25rem; }
.newseries > summary {
  cursor: pointer; list-style: none;
  font-size: .66rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--ember); padding: .35rem 0;
}
.newseries > summary::-webkit-details-marker { display: none; }
.newseries > summary::before { content: '+ '; }
.newseries[open] > summary::before { content: '– '; }

/* thumbs gain a caption field */
.thumb { display: flex; flex-direction: column; aspect-ratio: auto; }
.thumb img { aspect-ratio: 1; object-fit: cover; }
.thumb__cap {
  width: 100%; background: #0d0a09; border: 1px solid var(--ink-line);
  border-top: none; color: var(--paper-dim);
  padding: .4rem .5rem; font-family: var(--font-body); font-size: .68rem;
}
.thumb__cap:focus { outline: none; border-color: var(--ember); }


/* zoomable plate */

/* ---------------- lightbox ---------------- */

.lb {
  position: fixed; inset: 0; z-index: 200;
  display: none; align-items: center; justify-content: center;
  background: rgba(6,5,4,.97);
  padding: clamp(1rem, 4vw, 3rem);
}
.lb[data-on] { display: flex; }

.lb__stage {
  max-width: 100%; max-height: 100%;
  display: flex; flex-direction: column; align-items: center; gap: 1rem;
}
.lb__img {
  max-width: 100%; max-height: calc(100svh - 8rem);
  width: auto; height: auto; object-fit: contain;
}
.lb__cap {
  font-size: .78rem; color: var(--paper-dim); text-align: center;
  max-width: 60ch;
}

.lb__close, .lb__prev, .lb__next {
  position: absolute; color: var(--paper-dim);
  width: 56px; height: 56px; display: grid; place-items: center;
  font-size: 2rem; line-height: 1; transition: color .25s;
}
.lb__close:hover, .lb__prev:hover, .lb__next:hover { color: var(--ember); }
.lb__close { top: .5rem; right: .75rem; font-size: 2.4rem; }
.lb__prev { left: .25rem; top: 50%; transform: translateY(-50%); font-size: 3rem; }
.lb__next { right: .25rem; top: 50%; transform: translateY(-50%); font-size: 3rem; }
.lb__count {
  position: absolute; bottom: 1rem; left: 50%; transform: translateX(-50%);
  font-size: .68rem; letter-spacing: .18em; color: var(--paper-faint);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 820px) {
  .toolbar { flex-direction: column; align-items: stretch; }
  /* flex-basis becomes the HEIGHT once the toolbar stacks — without this the
     search field renders 220px tall. */
  .toolbar input[type="search"] { flex: 0 0 auto; }
  .tabs { justify-content: flex-start; }
  /* Admin rows: thumb + title on one line, actions on the next. Four buttons
     beside the text at 390px squeezed titles into four-line wraps. */
  .admin-row { flex-wrap: wrap; }
  .admin-row__main { flex: 1 1 auto; min-width: 0; }
  .admin-row__acts {
    flex: 1 1 100%; justify-content: flex-start; margin-top: .6rem;
  }
  .admin-row__acts button { padding: .5rem .7rem; }
  .lb__prev, .lb__next { width: 44px; font-size: 2.2rem; }
}

/* ============================================================
   Server backend: sign-in, notes inbox, feedback widget
   ============================================================ */

.btn--sm { padding: .55rem .9rem; font-size: .62rem; }

.studio__bar { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.studio__bar h1 { margin-right: auto; }

/* ---------------- sign-in ---------------- */

.panel--signin { max-width: 30rem; }
.signin__msg {
  border-left: 2px solid var(--ember);
  background: rgba(216,120,74,.06);
  padding: .75rem 1rem; margin-bottom: 1.25rem;
  font-size: .82rem; color: var(--paper-dim);
}

/* ---------------- notes inbox ---------------- */

.note {
  display: flex; gap: 1rem; align-items: flex-start;
  padding: 1rem 0; border-bottom: 1px solid var(--ink-line);
}
.note__body { flex: 1; min-width: 0; }
.note__body p { font-size: .88rem; color: var(--paper); white-space: pre-wrap; }
.note__body small {
  display: block; margin-top: .4rem;
  font-size: .68rem; color: var(--paper-faint);
}
.note__body small a { color: var(--ember); }
.note__acts { display: flex; gap: .35rem; flex: 0 0 auto; }
.note__acts button {
  font-size: .6rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--paper-faint); border: 1px solid var(--ink-line);
  padding: .4rem .6rem; transition: color .25s, border-color .25s;
}
.note__acts button:hover { color: var(--ember); border-color: var(--ember); }
.note--done { opacity: .45; }
.note--done .note__body p { text-decoration: line-through; }

/* ---------------- feedback widget ---------------- */

.fb {
  position: fixed; right: clamp(1rem, 3vw, 2rem); bottom: clamp(1rem, 3vw, 2rem);
  z-index: 120; display: flex; flex-direction: column; align-items: flex-end; gap: .75rem;
}

.fb__btn {
  display: inline-flex; align-items: center; gap: .5rem;
  background: var(--ink-raised); border: 1px solid var(--ink-line);
  color: var(--paper-dim);
  padding: .7rem 1.05rem;
  font-size: .64rem; letter-spacing: .18em; text-transform: uppercase;
  transition: color .3s, border-color .3s, background-color .3s;
  box-shadow: 0 10px 30px rgba(0,0,0,.4);
}
.fb__btn:hover { color: var(--paper); border-color: var(--ember); }
.fb__dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--ember);
  flex: 0 0 auto;
}
.fb--hint .fb__dot { animation: fbpulse 2.4s ease-in-out infinite; }
@keyframes fbpulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(216,120,74,.55); }
  50%      { box-shadow: 0 0 0 7px rgba(216,120,74,0); }
}

.fb__panel {
  width: min(24rem, calc(100vw - 2rem));
  background: var(--ink-raised);
  border: 1px solid var(--ink-line);
  padding: 1.1rem;
  box-shadow: 0 20px 60px rgba(0,0,0,.55);
  animation: rise .3s var(--ease) both;
}
.fb__head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: .5rem;
}
.fb__head strong {
  font-size: .68rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--paper);
}
.fb__x { font-size: 1.5rem; line-height: 1; color: var(--paper-faint); padding: 0 .25rem; }
.fb__x:hover { color: var(--ember); }

.fb__ctx { font-size: .68rem; color: var(--paper-faint); margin-bottom: .75rem; }
.fb__ctx span { color: var(--ember); }

.fb__panel textarea {
  width: 100%; background: #0d0a09; border: 1px solid var(--ink-line);
  color: var(--paper); padding: .7rem .8rem; resize: vertical;
  font-family: var(--font-body); font-size: .85rem; line-height: 1.55;
}
.fb__panel textarea:focus { outline: none; border-color: var(--ember); }

.fb__foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: .75rem; margin-top: .75rem;
}
.fb__count { font-size: .66rem; color: var(--paper-faint); }
.fb__note { margin-top: .6rem; font-size: .64rem; color: var(--paper-faint); line-height: 1.5; }
.fb__err {
  margin-top: .6rem; font-size: .7rem; color: var(--ember-lift);
}
.fb__done { text-align: center; padding: 1rem .5rem; }
.fb__done strong {
  display: block; font-size: .7rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--ember); margin-bottom: .5rem;
}
.fb__done p { font-size: .8rem; color: var(--paper-dim); margin-bottom: 1rem; }

@media (max-width: 620px) {
  .fb { right: 1rem; bottom: 1rem; left: 1rem; align-items: stretch; }
  .fb__btn { align-self: flex-end; }
  .fb__panel { width: 100%; }
  .note { flex-wrap: wrap; }
  .note__acts { flex: 1 1 100%; margin-top: .5rem; }
}

.hb { display: block; margin-top: .5rem; color: var(--paper-faint); font-weight: 400; }
.hb--stale { color: var(--ember); }

/* Chrome paints autofilled inputs white, which broke the sign-in form against
   the dark ground. There is no way to set the background directly — the inset
   shadow trick is the only reliable override. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--paper);
  -webkit-box-shadow: 0 0 0 1000px #0d0a09 inset;
  box-shadow: 0 0 0 1000px #0d0a09 inset;
  caret-color: var(--paper);
  transition: background-color 9999s ease-in-out 0s;
}

/* ============================================================
   Wave 4 — built from Leyla's own notes (20 Aug)
   ============================================================ */

/* ---------- work page: horizontal gallery, writing beneath ---------- */

.wk__head { margin-bottom: 2rem; }
.wk__title {
  font-family: var(--font-display); font-weight: 300;
  font-size: clamp(1.9rem, 4.2vw, 3.2rem); line-height: 1.05;
  letter-spacing: -.015em; color: var(--paper);
}

.reel { position: relative; margin: 0 calc(var(--pad) * -1); }

.reel__track {
  display: flex; gap: 1.25rem;
  overflow-x: auto; overflow-y: hidden;
  /* NO scroll-behavior:smooth here. Any animated scroll (CSS smooth, native
     scrollBy smooth, or a rAF tween) is suspended while the tab is not
     visible, which left the arrows dead. Instant paging always lands. */
  scroll-behavior: auto;
  /* No scroll-snap. With it enabled, EVERY programmatic scroll was re-snapped
     back to 64px (the track's left padding) regardless of method: raw
     assignment, scrollBy instant, scrollBy smooth, and an rAF tween all lost.
     Free scrolling plus arrow paging behaves correctly. */
  padding: 0 var(--pad) 1rem;
  scrollbar-width: thin;
  outline: none;
  /* the pointer-drag handler owns horizontal panning */
  touch-action: pan-x pan-y;
}
.reel__track::-webkit-scrollbar { height: 3px; }
.reel__track::-webkit-scrollbar-thumb { background: var(--ink-line); }

.reel__item {
  flex: 0 0 auto;
  max-width: min(86vw, 1100px);
  display: flex; flex-direction: column;
}
/* A lazy image has NO intrinsic size until it loads, so `width:auto` collapses
   the item to zero and every un-loaded plate stacks at the same x. The stored
   dimensions are emitted as an inline aspect-ratio, which lets the browser
   reserve the correct width before a single byte arrives. */
.reel__item img, .reel__item video {
  height: min(66vh, 620px); width: auto; max-width: 86vw;
  object-fit: contain; background: #070505;
  user-select: none; -webkit-user-drag: none;
}
.reel__item img:not([style*="aspect-ratio"]),
.reel__item video:not([style*="aspect-ratio"]) { aspect-ratio: 4 / 3; }
.reel__item figcaption {
  margin-top: .7rem; font-size: .72rem; color: var(--paper-faint);
  max-width: 60ch;
}

.reel__nav {
  position: absolute; top: calc(min(66vh, 620px) / 2); transform: translateY(-50%);
  z-index: 3; width: 46px; height: 46px;
  display: grid; place-items: center;
  font-size: 2rem; line-height: 1;
  color: var(--paper-dim); background: rgba(10,8,7,.78);
  border: 1px solid var(--ink-line);
  transition: color .25s, border-color .25s, opacity .25s;
}
.reel__nav:hover { color: var(--ember); border-color: var(--ember); }
.reel__nav:disabled { opacity: .2; pointer-events: none; }
.reel__nav--prev { left: calc(var(--pad) - 23px); }
.reel__nav--next { right: calc(var(--pad) - 23px); }

.reel__count {
  margin: .9rem var(--pad) 0;
  font-size: .68rem; letter-spacing: .2em; color: var(--paper-faint);
  font-variant-numeric: tabular-nums;
}
.reel__count b { color: var(--ember); font-weight: 400; }

/* writing sits under the gallery, quieter than the work itself */
.wk__writing {
  margin-top: 3.5rem; padding-top: 2rem;
  border-top: 1px solid var(--ink-line);
  max-width: var(--measure);
}
.wk__writing .prose { font-size: .95rem; color: var(--paper-dim); }

@media (max-width: 820px) {
  .reel__item img, .reel__item video { height: min(52vh, 440px); max-width: 88vw; }
  .reel__nav { display: none; }   /* swipe is the gesture on touch */
  .reel__item { max-width: 88vw; }
}

/* ---------- categories: nesting + search ---------- */

.cat-search {
  flex: 0 1 22rem; min-width: 0;
  background: #0d0a09; border: 1px solid var(--ink-line); color: var(--paper);
  padding: .6rem .8rem; font-family: var(--font-body); font-size: .82rem;
}
.cat-search:focus { outline: none; border-color: var(--ember); }

.index-row--sub { padding-left: 2.5rem; }
.index-row--sub .index-row__title { font-size: .92em; color: var(--paper-dim); }
.index-row--sub::before {
  content: '↳'; position: absolute; left: 1rem;
  color: var(--paper-faint); font-size: .8rem;
}
.index-row { position: relative; }

.srch__lead {
  font-size: .64rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--ember); margin: 1.75rem 0 .75rem;
}

.nest { color: var(--ember); }

/* ---------- Studio: draggable plates + video thumbs ---------- */

.thumb { position: relative; cursor: default; }
.thumb__grip {
  position: absolute; top: 4px; left: 4px; z-index: 2;
  font-size: .8rem; line-height: 1; color: var(--paper-dim);
  background: rgba(10,8,7,.7); padding: 3px 5px;
  cursor: grab; user-select: none;
}
.thumb:active .thumb__grip { cursor: grabbing; }
.thumb--dragging { opacity: .35; }

.thumb__vid { position: relative; }
.thumb__vid img { aspect-ratio: 1; object-fit: cover; width: 100%; }
.thumb__novid { aspect-ratio: 1; background: #131010; }
.thumb__vid span {
  position: absolute; bottom: 4px; right: 4px;
  font-size: .55rem; letter-spacing: .14em; text-transform: uppercase;
  background: rgba(216,120,74,.9); color: var(--ink); padding: 2px 5px;
}

@media (max-width: 620px) {
  .sec-head { flex-wrap: wrap; gap: .75rem; }
  .cat-search { flex: 1 1 100%; }
}

/* ---------- studio: paste-a-link row ---------- */

.linkrow { display: flex; gap: .6rem; margin-top: .75rem; flex-wrap: wrap; }
.linkrow input[type="url"] {
  flex: 1 1 18rem; min-width: 0;
  background: #0d0a09; border: 1px solid var(--ink-line); color: var(--paper);
  padding: .65rem .8rem; font-family: var(--font-body); font-size: .82rem;
}
.linkrow input[type="url"]:focus { outline: none; border-color: var(--ember); }

/* ============================================================
   Wave 6 — intake that matches how she actually works
   ------------------------------------------------------------
   Her pieces carry 20-35 photographs each. The old intake silently made one
   piece per photo, so documenting a single installation produced 29 unusable
   drafts with no way to merge them. Now the grouping is asked before anything
   is written, and either answer is undoable.
   ============================================================ */

.stage-box {
  margin-top: 1.25rem; padding: 1.25rem;
  border: 1px solid var(--ember); background: rgba(216,120,74,.05);
}

.stage-count { font-size: .82rem; color: var(--paper); margin-bottom: .9rem; }
.stage-count b { color: var(--ember); }
.stage-warn {
  display: inline-block; margin-left: .6rem;
  font-size: .7rem; color: var(--ember-lift);
}
.stage-msg { font-size: .82rem; color: var(--paper-dim); line-height: 1.65; }
.stage-msg strong { color: var(--ember); }

.stage-thumbs {
  display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: 1.1rem;
}
.stage-thumb {
  position: relative; width: 54px; height: 54px;
  border: 1px solid var(--ink-line); overflow: hidden; flex: 0 0 auto;
}
.stage-thumb img, .stage-thumb video { width: 100%; height: 100%; object-fit: cover; }
.stage-thumb span {
  position: absolute; bottom: 0; right: 0;
  font-size: .5rem; letter-spacing: .08em; text-transform: uppercase;
  background: rgba(216,120,74,.92); color: var(--ink); padding: 1px 3px;
}
.stage-more {
  width: 54px; height: 54px; display: grid; place-items: center;
  border: 1px dashed var(--ink-line); color: var(--paper-faint); font-size: .7rem;
}

.stage-choice { display: flex; flex-wrap: wrap; gap: .6rem; margin-bottom: 1rem; }
.choice {
  flex: 1 1 15rem; display: flex; gap: .6rem; align-items: flex-start;
  padding: .8rem .9rem; border: 1px solid var(--ink-line); cursor: pointer;
  transition: border-color .2s, background-color .2s;
}
.choice:hover { border-color: var(--paper-faint); }
.choice:has(input:checked) { border-color: var(--ember); background: rgba(216,120,74,.07); }
.choice input { margin-top: .25rem; accent-color: var(--ember); flex: 0 0 auto; }
.choice span { font-size: .82rem; color: var(--paper-dim); line-height: 1.45; }
.choice b { color: var(--paper); font-weight: 400; }
.choice small { color: var(--paper-faint); font-size: .7rem; }

.intake-result {
  margin-top: 1.25rem; padding: 1rem 1.25rem;
  border-left: 2px solid var(--ember); background: rgba(216,120,74,.04);
}
.intake-result .btn { margin-top: .75rem; margin-right: .5rem; }

.failed-list {
  list-style: none; margin: .5rem 0 0; padding: 0;
  font-size: .76rem; color: var(--paper-dim);
}
.failed-list li { padding: .3rem 0; border-bottom: 1px solid var(--ink-line); }
.failed-list small { color: var(--paper-faint); margin-left: .5rem; }

@media (max-width: 620px) {
  .stage-choice { flex-direction: column; }
  .choice { flex: 1 1 auto; }
}

/* ---------- works list: find it, judge it, act on it ---------- */

.w-cat {
  flex: 0 1 12rem; min-width: 0;
  background: #0d0a09; border: 1px solid var(--ink-line); color: var(--paper-dim);
  padding: .65rem .7rem; font-family: var(--font-body); font-size: .78rem;
}
.w-cat:focus { outline: none; border-color: var(--ember); }

.bulkbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: .6rem;
  padding: .6rem 0 1rem; margin-bottom: .5rem;
  border-bottom: 1px solid var(--ink-line);
}
.bulkbar[data-on] { border-bottom-color: var(--ember); }
.bulk-all {
  display: inline-flex; align-items: center; gap: .45rem;
  font-size: .68rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--paper-dim); cursor: pointer;
}
.bulk-all input { accent-color: var(--ember); }
.bulk-hint { font-size: .68rem; color: var(--paper-faint); margin-left: auto; }
.bulkbar select {
  background: #0d0a09; border: 1px solid var(--ink-line); color: var(--paper-dim);
  padding: .5rem .6rem; font-family: var(--font-body); font-size: .76rem;
}
.bulkbar select:focus { outline: none; border-color: var(--ember); }

.admin-row--work { align-items: center; }
.row-tick { accent-color: var(--ember); flex: 0 0 auto; margin-right: .2rem; }

.admin-row__thumb--empty {
  display: grid; place-items: center;
  font-size: .55rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--paper-faint); background: #131010;
}

/* draft / live toggle, readable at a glance */
.admin-row__acts button[data-act="pub"] { min-width: 3.6rem; }
.admin-row__acts button.is-live { color: var(--ember); border-color: rgba(216,120,74,.45); }

/* film tiles on public cards */
.card__frame { position: relative; }
.card__empty--film { color: var(--ember); }
.card__film {
  position: absolute; bottom: .5rem; right: .5rem;
  font-size: .55rem; letter-spacing: .14em; text-transform: uppercase;
  background: rgba(10,8,7,.82); color: var(--paper-dim);
  border: 1px solid var(--ink-line); padding: .15rem .35rem;
}

@media (max-width: 620px) {
  .w-cat { flex: 1 1 100%; }
  .bulk-hint { margin-left: 0; }
}


/* ---------- reordering photos: drag anywhere, or nudge with the arrows ---------- */

.thumb { touch-action: pan-y; }        /* let a vertical page scroll through */
.thumb img, .thumb video, .thumb__vid { pointer-events: none; }  /* the tile drags, not the media */
.thumb__x { position: absolute; top: 4px; right: 4px; z-index: 3; }

.thumb__move {
  position: absolute; left: 4px; bottom: 30px; z-index: 3;
  display: flex; gap: 2px; opacity: 0; transition: opacity .2s;
}
.thumb:hover .thumb__move,
.thumb:focus-within .thumb__move { opacity: 1; }
.thumb__move button {
  width: 20px; height: 20px; display: grid; place-items: center;
  font-size: .85rem; line-height: 1;
  background: rgba(10,8,7,.85); border: 1px solid var(--ink-line);
  color: var(--paper-dim);
}
.thumb__move button:hover { color: var(--ember); border-color: var(--ember); }

/* On touch there is no hover, so the arrows are always visible. */
@media (hover: none) {
  .thumb__move { opacity: 1; }
  .thumb__move button { width: 26px; height: 26px; }
}

/* ============================================================
   The guide — opt-in, never in the way
   ------------------------------------------------------------
   Sits beside the Feedback button and shares its switch (REVIEW_MODE in
   js/config.js). It is a slide-in panel rather than an overlay tour: nothing
   is blocked, nothing auto-opens, and it can be closed at any point.
   ============================================================ */

.gd {
  position: fixed; right: clamp(1rem, 3vw, 2rem);
  bottom: calc(clamp(1rem, 3vw, 2rem) + 3.1rem);
  z-index: 121;
}

.gd__btn {
  display: inline-flex; align-items: center; gap: .5rem;
  background: var(--ink-raised); border: 1px solid var(--ink-line);
  color: var(--paper-dim);
  padding: .7rem 1.05rem;
  font-size: .64rem; letter-spacing: .18em; text-transform: uppercase;
  box-shadow: 0 10px 30px rgba(0,0,0,.4);
  transition: color .3s, border-color .3s;
}
.gd__btn:hover { color: var(--paper); border-color: var(--ember); }
.gd__mark {
  width: 15px; height: 15px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid currentColor; font-size: .58rem; letter-spacing: 0;
  flex: 0 0 auto;
}
.gd--new .gd__mark {
  background: var(--ember); border-color: var(--ember); color: var(--ink);
  animation: gdpulse 2.6s ease-in-out infinite;
}
@keyframes gdpulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(216,120,74,.5); }
  50%      { box-shadow: 0 0 0 6px rgba(216,120,74,0); }
}

/* the panel */
.gd__panel {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: min(25rem, 100vw);
  background: var(--ink-raised);
  border-left: 1px solid var(--ink-line);
  box-shadow: -24px 0 60px rgba(0,0,0,.5);
  display: flex; flex-direction: column;
  animation: gdslide .32s var(--ease) both;
}
@keyframes gdslide { from { transform: translateX(14px); opacity: 0; } to { transform: none; opacity: 1; } }

.gd__head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem; padding: 1.15rem 1.25rem 1rem;
  border-bottom: 1px solid var(--ink-line);
}
.gd__head strong {
  display: block;
  font-size: .68rem; letter-spacing: .18em; text-transform: uppercase; color: var(--paper);
}
.gd__sub {
  display: block; margin-top: .3rem;
  font-family: var(--font-spec, monospace);
  font-size: .62rem; letter-spacing: .12em; color: var(--ember);
}
.gd__x { font-size: 1.6rem; line-height: 1; color: var(--paper-faint); padding: 0 .25rem; }
.gd__x:hover { color: var(--ember); }

.gd__body { flex: 1; overflow-y: auto; padding: .5rem 1.25rem 1.25rem; }

.gd__sec { margin-top: 1.35rem; }
.gd__sec h3 {
  font-family: var(--font-spec, monospace);
  font-size: .6rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--paper-faint); font-weight: 400;
  padding-bottom: .5rem; border-bottom: 1px solid var(--ink-line);
}

.gd__item { border-bottom: 1px solid rgba(42,34,32,.6); }
.gd__item > summary {
  cursor: pointer; list-style: none; padding: .7rem 0;
  font-size: .84rem; color: var(--paper-dim); line-height: 1.45;
  display: flex; gap: .55rem;
  transition: color .2s;
}
.gd__item > summary::-webkit-details-marker { display: none; }
.gd__item > summary::before { content: '+'; color: var(--ember); flex: 0 0 auto; }
.gd__item[open] > summary { color: var(--paper); }
.gd__item[open] > summary::before { content: '–'; }
.gd__item:hover > summary { color: var(--paper); }
.gd__item p {
  font-size: .8rem; line-height: 1.65; color: var(--paper-faint);
  padding: 0 0 .75rem 1.1rem;
}

.gd__show {
  margin: 0 0 .85rem 1.1rem; padding: .35rem .7rem;
  font-size: .6rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ember); border: 1px solid rgba(216,120,74,.4);
  transition: background-color .2s;
}
.gd__show:hover { background: rgba(216,120,74,.12); }
.gd__away {
  display: block; margin: 0 0 .85rem 1.1rem;
  font-size: .64rem; letter-spacing: .1em; color: var(--paper-faint);
  font-style: italic;
}

.gd__foot {
  display: flex; align-items: center; justify-content: space-between; gap: .75rem;
  padding: .85rem 1.25rem; border-top: 1px solid var(--ink-line);
  font-size: .64rem; color: var(--paper-faint);
}
.gd__dismiss {
  font-size: .6rem; letter-spacing: .1em; color: var(--paper-faint);
  text-decoration: underline; text-underline-offset: 3px;
}
.gd__dismiss:hover { color: var(--ember); }

/* "Show me" outlines the real control rather than describing it */
.gd-spot {
  outline: 2px solid var(--ember) !important;
  outline-offset: 4px;
  animation: gdspot 2.6s ease-out both;
  border-radius: 2px;
}
@keyframes gdspot {
  0%, 70% { box-shadow: 0 0 0 6px rgba(216,120,74,.16); }
  100%    { box-shadow: 0 0 0 0 rgba(216,120,74,0); }
}

@media (max-width: 620px) {
  .gd { right: 1rem; bottom: calc(1rem + 3.1rem); }
  .gd__label { display: none; }          /* just the ? on a phone */
  .gd__btn { padding: .7rem .8rem; }
  .gd__panel { width: 100vw; }
}

@media (prefers-reduced-motion: reduce) {
  .gd__panel { animation: none; }
  .gd--new .gd__mark, .gd-spot { animation: none; }
}

/* ============================================================
   HOMEPAGE — built to her sketch and design document (21 Aug)
   ------------------------------------------------------------
   "use image and crop fading to black ... Add the moving stars / glimmers only
   from that design. Scrap the rest. ... Upper left corner should be my name
   large. ... one of my sculptures 'cut out' against the background. It will be
   'behind' the large oval. ... The large oval will be a default image unless the
   categories beneath are being toggled over."
   ============================================================ */

/* One composition, one screen.
   The oval only means anything while the categories are visible with it: the
   aperture previews whichever one you are on. With the categories below the
   fold that interaction cannot happen, so the whole block is sized to the
   viewport and the portal takes whatever height is left over. */
.home {
  position: relative;
  /* A DEFINITE height, not a minimum. With min-height the stage could only
     grow, so shrinking the portal never pulled the category row back up and it
     stayed 30px below the fold. Given a real height, flex hands the stage
     exactly what is left and the portal sizes itself to that.
     The subtractions are the page shell's own padding: bar-height + 2rem above,
     1.25rem below. */
  height: calc(100svh - var(--bar-h) - 2rem - 1.25rem);
  min-height: 30rem;             /* below this it may scroll, which is fine */
  display: flex; flex-direction: column;
  padding-bottom: 0;
}

/* the homepage is a fixed composition, so it does not want the tall footer gap */
body[data-home] .stage { padding-bottom: 1.25rem; }

/* her artwork, cropped at the top, faded to black downward */
.home__bg {
  position: absolute; top: calc(var(--bar-h) * -1); left: calc(var(--pad) * -1);
  right: calc(var(--pad) * -1); height: min(72svh, 620px);
  background: url('assets/mainphoto.jpeg') center 22% / cover no-repeat;
  z-index: 0; pointer-events: none;
}
.home__bg::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(to bottom,
    rgba(10,8,7,.15) 0%,
    rgba(10,8,7,.45) 45%,
    rgba(10,8,7,.92) 82%,
    var(--ink) 100%);
}

.home__stars {
  position: fixed; inset: 0;
  width: 100%; height: 100%;
  z-index: 1; pointer-events: none;
}

/* name, upper left, large */
.home__top { position: relative; z-index: 3; padding-top: clamp(.5rem, 2.5vh, 2rem); flex: 0 0 auto; }

/* Her name is set in the hand from the site she liked: La Belle Aurore, the
   same face, spacing and weight as `.signature-text` there, so the mark reads
   the same on the homepage as it does in the bar. */
.home__name {
  font-family: var(--font-script);
  font-weight: 400; text-transform: none;
  font-size: clamp(2.6rem, min(9vw, 12vh), 6.5rem);
  line-height: 1.05; letter-spacing: 2px;
  color: var(--paper);
  text-shadow: 0 2px 30px rgba(10,8,7,.75);
}

.home__intro {
  margin-top: clamp(.85rem, 2.4vh, 1.75rem);
  max-width: 52ch;
  font-size: clamp(.88rem, 1.1vw, 1rem); line-height: 1.7;
  color: var(--paper);
  text-shadow: 0 1px 16px rgba(10,8,7,.85);
}

/* the stage: sculpture behind, oval in front */
.home__stage {
  position: relative; z-index: 2;
  margin-top: clamp(.5rem, 1.6vh, 1.25rem);
  display: grid; place-items: center;
  flex: 1 1 auto; min-height: 0;      /* takes the leftover height */
}


/* the portal */
.home__oval img {
  width: 100%; height: 100%; object-fit: cover;
  transition: opacity .34s var(--ease);
}

/* categories, a horizontal row under the portal */
.home__cats {
  position: relative; z-index: 3; flex: 0 0 auto;
  margin-top: clamp(.9rem, 2.4vh, 1.75rem);
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: clamp(1rem, 3vw, 2.75rem);
}
.home__cat {
  font-size: clamp(.66rem, 1vw, .78rem);
  letter-spacing: .22em; text-transform: uppercase;
  color: var(--paper-dim);
  padding: .5rem 0; border-bottom: 1px solid transparent;
  transition: color .28s, border-color .28s;
  text-shadow: 0 1px 12px rgba(10,8,7,.8);
}
.home__cat:hover, .home__cat:focus-visible { color: var(--paper); border-bottom-color: var(--ember); }
.home__cat[data-peeked="1"] { color: var(--ember); border-bottom-color: var(--ember); }

.home__line {
  position: relative; z-index: 3; flex: 0 0 auto;
  margin: clamp(.8rem, 2vh, 1.5rem) auto 0;
  max-width: 52ch; text-align: center;
  font-size: .84rem; line-height: 1.7; color: var(--paper-faint);
}

/* the homepage carries its own name, so the bar wordmark stands down */
body[data-home] .mark { opacity: 0; pointer-events: none; }

/* The suspension block further down owns the sculpture and the aperture at
   these widths; these only handle the surrounding type. */
@media (max-width: 860px) {
  .home__intro { max-width: 100%; }
}

@media (max-width: 620px) {
  .home__cats { gap: .9rem 1.4rem; }
}

/* ---------- category page ---------- */

.cat__head { margin-bottom: 1.5rem; }
.cat__title {
  font-family: var(--font-display); font-weight: 300;
  font-size: clamp(1.7rem, 3.6vw, 2.8rem); line-height: 1.05;
  letter-spacing: -.01em; color: var(--paper);
}
.cat__blurb {
  margin-top: .9rem; max-width: var(--measure);
  font-size: .9rem; line-height: 1.7; color: var(--paper-dim);
}
.cat__blurb--sub { margin: .25rem 0 1.25rem; font-size: .82rem; }

.cat__tools { margin-bottom: 2rem; }

.subgroup { margin-top: 3.25rem; }
.subgroup .sec-head h3 {
  font-size: .66rem; letter-spacing: .24em; text-transform: uppercase;
  color: var(--ember); font-weight: 400;
}


/* ============================================================
   SUSPENSION — the homepage as hung work
   ------------------------------------------------------------
   Her studio photograph is a room of things hanging from the ceiling; the
   sculpture in her design document stands on a rod; and her own sketch has a
   small object dangling on a line. So the portal and the sculpture both hang
   from threads and sway, nudged by the pointer. Only transform:rotate animates,
   with the origin at the top of the thread, so it costs the compositor and
   nothing else.
   ============================================================ */

.hang {
  position: absolute; top: 0;
  transform-origin: 50% 0;          /* pivots at the ceiling, not its middle */
  will-change: transform;
  display: flex; flex-direction: column; align-items: center;
}

.hang__thread {
  display: block; width: 1px; flex: 0 0 auto;
  background: linear-gradient(to bottom,
    rgba(237,231,225,0) 0%,
    rgba(237,231,225,.28) 35%,
    rgba(237,231,225,.42) 100%);
}

.hang--sculpture {
  right: clamp(-2rem, 3vw, 5rem);
  z-index: 1;                        /* BEHIND the portal, as she drew it */
}
.hang--sculpture .hang__thread { height: clamp(10px, 4vh, 46px); }
.hang--sculpture .hang__obj {
  height: clamp(230px, 46svh, 470px);
  width: auto; max-width: none;
  filter: drop-shadow(0 18px 44px rgba(0,0,0,.7));
  user-select: none; -webkit-user-drag: none;
}


/* the aperture: a hole cut through the dark, not a photo with rounded corners.
   It sits still on purpose while the sculpture swings across it. */
.home__oval {
  position: relative; z-index: 2;
  --oval-x: 50%;
  --oval-y: 36%;
  /* Sized from her own design document, measured: the oval is 86% of the page
     width there, at roughly a 1.42 landscape aspect, and it owns the lower half
     of the page. The first build had it at 48% of width, which is why she said
     it was "way way too small" and why the shape change was invisible. */
  /* Width-driven, not height-driven. The old rule capped it at 640px and
     squeezed it to whatever was left after the rest of the page, which is why
     she said it was "way way too small". In her document the oval is 86% of the
     page width, so that is what it is here, and the page scrolls like her
     document does rather than cramming everything into one screen. */
  width: min(86vw, 1180px);
  height: auto;
  aspect-ratio: 1.42;
  background: #000;
  clip-path: ellipse(var(--oval-x) var(--oval-y) at 50% 50%);
  transition: clip-path .5s var(--ease);
}
.home__oval img {
  width: 100%; height: 100%; object-fit: cover;
  transition: opacity .34s var(--ease);
}
/* inner shadow so it reads as depth through an opening */
.home__oval-rim {
  position: absolute; inset: 0; pointer-events: none;
  box-shadow:
    inset 0 0 60px 12px rgba(10,8,7,.85),
    inset 0 0 0 1px rgba(237,231,225,.16);
  border-radius: 50%;
}

@media (max-width: 860px) {
  .hang--sculpture .hang__obj { height: clamp(180px, 34svh, 320px); opacity: .9; }
  .hang--sculpture { right: -2.5rem; }
}
@media (max-width: 620px) {
  .hang--sculpture .hang__obj { height: 210px; opacity: .75; }
  .hang--sculpture { right: -3.5rem; }
}

.cover-preview { margin-top: .6rem; }
.cover-preview img {
  width: 132px; height: 92px; object-fit: cover;
  border: 1px solid var(--ink-line);
}


/* ---------- portal spacing, measured off her design document ----------
   Her PDF: background image over the top ~51% of the page, intro text at 42%
   down at 60% width, sculpture 16% wide crossing the boundary, oval 86% wide
   from the 51% line. She asked for the document's spacing, not the sketch's. */

.home { min-height: auto; padding-bottom: clamp(3rem, 8vh, 6rem); }
.home__bg { height: min(56svh, 560px); }
.home__stars { height: min(64svh, 640px); }
.home__top { padding-top: clamp(1.5rem, 6vh, 4rem); }

/* name on two lines, then air, then the sentences */
.home__name .home__surname { display: block; }
.home__intro {
  margin-top: clamp(2rem, 7vh, 4.5rem);
  max-width: 60%;
  font-size: clamp(.8rem, .95vw, .92rem);
  color: var(--paper-dim);
}

.home__stage { margin-top: clamp(.5rem, 2vh, 1.5rem); min-height: auto; }

/* "categories need to be way bigger than the sentences explaining about the
   site. they are the most important part." */
.home__cats { margin-top: clamp(2rem, 6vh, 4rem); }
.home__cat {
  font-family: var(--font-display);
  font-size: clamp(1rem, 2.1vw, 1.75rem);
  letter-spacing: .05em; text-transform: uppercase;
  color: var(--paper);
}
.home__cat:hover, .home__cat:focus-visible { color: var(--ember); }

@media (max-width: 860px) {
  .home__intro { max-width: 100%; font-size: .82rem; }
  .home__cat { font-size: clamp(.95rem, 4.4vw, 1.3rem); }
}


/* ============================================================
   Portal, second pass — her notes of 22 Aug
   ============================================================ */

/* "Could we make the background and sparkles more like the crop I showed you in
   the index file?" The old build cropped it full-bleed and centred, then pulled
   it to black with a RADIAL vignette from the middle out. This build was fading
   it downward in a straight line, which is a different picture. Back to hers. */
.home__bg {
  /* fixed and full-viewport: the painting runs edge to edge with no inner
     frame. The CONTENT keeps its padding — the background simply does not
     know the padding exists. */
  position: fixed;
  inset: 0;
  height: 100%;
  background: url('assets/mainphoto.jpeg') center center / cover no-repeat;
  /* "want that downplayed a lot" */
  filter: brightness(.42) saturate(.92);
}
.home__bg::after {
  /* a gentle vertical fade only — the old radial painted solid ink over the
     left and right edges, which read as a frame around the page */
  background: linear-gradient(to bottom,
    rgba(14,10,7,.32) 0%,
    rgba(14,10,7,.10) 34%,
    rgba(14,10,7,.38) 62%,
    rgba(14,10,7,.86) 84%,
    var(--ink) 100%);
}

/* the glimmers travel the whole field, as they did in the old build */
.home__stars { height: 100%; }

/* "I want this oval to mirror the curve of background image" — the dome in her
   painting arcs across the upper half, so the aperture is lifted to sit inside
   that arc rather than below it. */
.home__stage { margin-top: clamp(-2rem, -3vh, 0rem); }

.home__oval-rim {
  box-shadow:
    inset 0 0 90px 18px rgba(10,8,7,.8),
    inset 0 0 0 1px rgba(237,231,225,.12);
}
/* ============================================================
   Home fits ONE screen
   ------------------------------------------------------------
   Measured before this: 496px of overflow at 1440x900, with the oval alone
   831px tall in an 838px space, so the name, the sentences and the categories
   were all pushed off the bottom and the page had to be scrolled to see its own
   navigation. The oval was also sized from the viewport WIDTH, which ignores
   how much vertical room is actually left.

   Now the page is a column exactly one screen tall and the oval takes whatever
   height remains, so it is always as large as it can be without pushing
   anything off. On a tall narrow phone it goes back to being width-bound.
   ============================================================ */

.home {
  height: calc(100svh - var(--bar-h));
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding-bottom: clamp(.75rem, 2.5vh, 1.75rem);
}

.home__top { flex: 0 0 auto; padding-top: clamp(.5rem, 2vh, 1.5rem); }

/* the script face carries tall ascenders, so its box ran far above the glyphs */
.home__name {
  font-size: clamp(2.2rem, 5.4vw, 4.6rem);
  line-height: 1.02;
}

.home__intro {
  margin-top: clamp(.75rem, 2.5vh, 1.75rem);
  max-width: min(56ch, 60%);
  font-size: clamp(.76rem, .88vw, .88rem);
  line-height: 1.6;
}

/* the aperture takes the space that is left, and no more */
.home__stage {
  flex: 1 1 auto;
  min-height: 0;
  margin-top: clamp(.5rem, 2vh, 1.25rem);
  display: grid;
  place-items: center;
}

.home__oval {
  height: 100%;
  max-height: 100%;
  width: auto;
  max-width: min(92vw, 1180px);
  aspect-ratio: var(--oval-ratio, 1.6);
}

/* the sculpture scales with the space too, rather than a fixed clamp */
.hang--sculpture .hang__obj { height: min(46vh, 420px); }

/* "make the categories under the oval a little smaller" */
.home__cats {
  flex: 0 0 auto;
  margin-top: clamp(.75rem, 2.5vh, 1.75rem);
  gap: clamp(.75rem, 2.4vw, 2rem);
}
.home__cat { font-size: clamp(.8rem, 1.35vw, 1.15rem); }

/* a short landscape window (a laptop in a browser with tabs) is the tight case */
@media (max-height: 720px) {
  .home__name { font-size: clamp(1.9rem, 4.4vw, 3.2rem); }
  .home__intro { margin-top: .6rem; font-size: .76rem; }
  .home__cat { font-size: clamp(.74rem, 1.1vw, .95rem); }
}

/* on a phone the page is narrow and tall: let it breathe and scroll if needed */
@media (max-width: 720px), (max-aspect-ratio: 4/5) {
  .home { height: auto; min-height: calc(100svh - var(--bar-h)); overflow: visible; }
  .home__oval { height: auto; width: 88vw; max-width: 88vw; }
  .home__intro { max-width: 100%; }
  .hang--sculpture .hang__obj { height: min(34vh, 300px); }
}

/* The oval must be bound by the HEIGHT that is left, not by the viewport width.
   `height:100%` on a centred grid item does not resolve (the row is sized by the
   item, which is circular), so it kept taking its size from max-width and stayed
   831px tall in an 838px space. Positioning it against the stage makes the
   percentage definite. */
.home__stage { position: relative; display: block; }

.home__oval {
  position: absolute;
  inset: 0;
  margin: auto;
  height: 100%;
  width: auto;
  max-width: min(92vw, 1180px);
  max-height: 100%;
  aspect-ratio: var(--oval-ratio, 1.6);
}

@media (max-width: 720px), (max-aspect-ratio: 4/5) {
  /* back to normal flow on a phone, where width is the binding constraint */
  .home__stage { position: relative; min-height: 46svh; }
  .home__oval { position: relative; inset: auto; height: auto; width: 88vw; max-width: 88vw; }
}

/* `.stage` pads every view by the bar height plus 2rem top and 6rem bottom.
   The home page sizes itself to the viewport, so that padding was pushing ~190px
   of it below the fold no matter how small its contents got. On this one page
   the padding is the bar height and nothing else, so the column really is one
   screen tall. */
body[data-home] .stage {
  padding-top: var(--bar-h);
  padding-bottom: 0;
  min-height: 0;
}

/* ============================================================
   Portal + sculpture, third pass — her note of 22 Aug
   ------------------------------------------------------------
   "On mobile it overlaps the sculpture and on desktop the spacing between
   the two is a bit strange— but I think it's most important they don't
   overlap this way."

   Why it happened, measured: the oval is centred and sized by leftover
   HEIGHT, but the sculpture was pinned to the STAGE's right edge — the full
   page width. Their gap therefore changed with every window shape, and at
   many widths the figure landed in the corners the ellipse clips away,
   showing flush against the aperture. On a phone the 88vw oval leaves ~6vw
   per side while the figure hung past the right edge straight across the
   portal's third.

   The fix is structural: one wrapper (.home__portal) carries the oval's box,
   and BOTH the aperture and the figure live inside it. The sculpture is now
   anchored to the RIM, not to the page, so their relation is deliberate and
   identical at every window shape:
   - desktop: she drew the figure behind the portal crossing its right edge;
     it hangs half behind the rim, by a bounded amount that can never run
     away on a narrow window.
   - phone: her rule is no overlap, so the portal gives up ~26vw of its own
     width and the figure hangs in that reserved column beside it, touching
     nothing.
   Her drawing is still coming; this holds the composition until it does.
   ============================================================ */

/* the wrapper owns the oval's sizing (moved from .home__oval unchanged) */
.home__portal {
  position: absolute;
  inset: 0;
  margin: auto;
  height: 100%;
  width: auto;
  max-width: min(92vw, 1180px);
  max-height: 100%;
  aspect-ratio: var(--oval-ratio, 1.6);
}

/* the aperture fills its wrapper; the clip-path still lives here, and the
   --oval-x/--oval-y vars are still set inline on #oval by wirePortal */
.home__oval {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
}

/* anchored to the rim: right edge at the wrapper's boundary, then eased out
   so part of the figure sits behind the portal and part shows past it.
   `translate` (not transform) because hang.js writes transform: rotate()
   every frame — the two properties compose instead of clobbering.
   The protrusion is bounded by viewport width so it can never push the
   figure off-screen on a narrow window; .home{overflow:hidden} clips the
   rest. */
.hang--sculpture {
  right: 0;
  left: auto;
  translate: min(55%, clamp(18px, 4.5vw, 88px)) 0;
}

@media (max-width: 720px), (max-aspect-ratio: 4/5) {
  /* her rule for phones: they do not overlap. The stage reserves a column on
     the right; the portal takes what remains and the figure hangs fully
     inside the reserved space. The figure is small here, as she drew it in
     her own sketch: a small object dangling on a line at the top right. */
  .home__stage {
    padding-right: 21vw;
    min-height: auto;
  }
  .home__portal {
    position: relative;
    inset: auto;
    height: auto;
    width: 100%;
    max-width: none;
  }
  .hang--sculpture {
    right: auto;
    left: 100%;                    /* the portal's right rim ... */
    translate: 8% 0;               /* ... nudged into the reserved column */
    top: 0;
    opacity: .9;
  }
  /* sized by WIDTH so the whole figure fits inside the 21vw column at any
     phone width: 17vw wide + a 1vw inset leaves ~3vw clear before the page
     edge */
  .hang--sculpture .hang__obj {
    height: auto;
    width: clamp(56px, 17vw, 96px);
    opacity: .9;
  }
}

/* ============================================================
   Portal + figures, fourth pass — her annotated PDF (23 Aug)
   ------------------------------------------------------------
   She pasted her edits onto a screenshot and sent it as
   "website design with edits.pdf". The PDF's own image placements
   give exact coordinates (percentages of the browser viewport):

     green oval   x 21.0→74.5%   y 29.6→89.9%   aspect ~1.6
     name         x  4.6→22.6%   y  9.4→29.8%
     yellow piece x 17.6→34.3%   y  4.7→16.5%
     categories   x 14.3→85.6%   y 89.9→98.5%
     sculpture    x 68.5→95.8%   y 14.6→69.4%

   So: the aperture dominates the screen, wider than before (1.6),
   its centre pulled slightly left; both hanging pieces sit CLEAR of
   it; the categories close right under the rim. Implemented with
   viewport units straight from those numbers.
   ============================================================ */

@media ((min-width: 721px) and (min-aspect-ratio: 4/5)) {
  /* tighter top block buys the oval its full band */
  .home__top { padding-top: clamp(.35rem, 1vh, 1rem); }
  .home__name { font-size: clamp(2rem, 5vw, 4.2rem); }
  .home__intro {
    margin-top: clamp(.5rem, 1.6vh, 1.25rem);
    font-size: clamp(.74rem, .84vw, .86rem);
  }

  .home__stage { margin-top: clamp(-3.5rem, -5vh, -1.5rem); }

  /* the portal: width-driven now, to her 53.5vw, centre at ~48% of the screen */
  .home__portal {
    position: absolute;
    inset: 0;
    margin: auto;
    height: 100%;
    width: auto;
    max-width: min(56vw, 1280px);
    max-height: 100%;
    aspect-ratio: var(--oval-ratio, 1.6);
    translate: -2.25vw 0;
    z-index: 2;
  }

  /* sculpture: her left edge sits just inside the rim and the body extends
     out past it; offsets are percent-of-wrapper so the relation holds at
     every window shape */
  .hang--sculpture {
    right: auto;
    left: calc(100% - 6vw);
    top: max(-42%, calc(-30svh + var(--bar-h)));
    translate: none;
    z-index: 1;
  }
  .hang--sculpture .hang__thread { height: 6svh; }
  .hang--sculpture .hang__obj {
    height: min(55svh, 600px);
    max-width: 26vw;               /* narrow desktops: shrink, never sprawl */
    opacity: .96;
  }

  /* her yellow piece: above the portal's left shoulder, thread from the
     ceiling. Her gap between its top and the oval's top is ~41% of the
     portal's height */
  .hang--yellow {
    left: -3.4vw;
    right: auto;
    top: max(-45%, calc(-25svh + var(--bar-h)));
    z-index: 1;
  }
  .hang--yellow .hang__thread { height: 4svh; }
  .hang--yellow .hang__obj {
    width: clamp(120px, 16.5vw, 330px);
    height: auto;
    opacity: .92;
    filter: drop-shadow(0 14px 30px rgba(0,0,0,.65));
    user-select: none; -webkit-user-drag: none;
  }

  /* categories close under the rim, as she placed them */
  .home__cats { margin-top: clamp(.25rem, .6vh, .5rem); gap: clamp(.75rem, 2vw, 1.75rem); }
}

/* phones keep last week's no-overlap arrangement; the yellow piece is a
   desktop composition from her drawing */
@media (max-width: 720px), (max-aspect-ratio: 4/5) {
  .hang--yellow { display: none; }
}
}
/* ------------------------------------------------------------
   cursor — a needle's eye: a thread-coloured ring that tightens
   onto its dot over anything interactive
   ------------------------------------------------------------ */
.cursor { display: none; }
@media (hover: hover) and (pointer: fine) {
  .cursor {
    display: block; position: fixed; top: 0; left: 0;
    width: 30px; height: 30px; z-index: 90; pointer-events: none;
    transform: translate3d(-100px, -100px, 0);
    will-change: transform;
  }
  .cursor::before {
    content: ''; position: absolute; inset: 0; margin: auto;
    width: 5px; height: 5px; border-radius: 50%;
    background: var(--ember);
  }
  .cursor::after {
    content: ''; position: absolute; inset: 0;
    border: 1px solid rgba(237, 226, 203, .38);
    border-radius: 50%;
    transition: inset .28s var(--ease), border-color .28s, transform .28s var(--ease);
  }
  .cursor[data-hot]::after {
    inset: 7px;
    border-color: var(--ember);
    border-radius: 3px;
    transform: rotate(45deg);
  }
}

/* focus is a stitch, not a box */
:focus-visible {
  outline: 1px dashed var(--ember);
  outline-offset: 4px;
}

/* ------------------------------------------------------------
   kinetic display — the outline treatment from the build she
   liked, kept alive without GSAP
   ------------------------------------------------------------ */
.kinetic {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: .96;
  letter-spacing: .01em;
  display: block;
}
.kinetic--outline {
  color: transparent;
  -webkit-text-stroke: 1px var(--paper-dim);
}

/* ============================================================
   HOME — the workshop wall
   ============================================================ */

/* her name: the hand from the site she liked, with a struck
   underline like a signature finished in one move */
.home__name { position: relative; }
.home__name::after {
  content: '';
  position: absolute; left: .2em; bottom: -.18em;
  width: 5.5em; height: 1px;
  background: linear-gradient(to right, var(--ember), transparent 78%);
  opacity: .55;
  transform: scaleX(0); transform-origin: left;
  animation: sign .9s .5s var(--ease) forwards;
}
@keyframes sign { to { transform: scaleX(1); } }

/* her line beneath the categories — it is HER writing, so it is
   set in her hand, in ochre */
.home__line {
  margin-top: clamp(.4rem, 1vh, .8rem);
  font-family: var(--font-script);
  font-size: clamp(1.25rem, 2.1vw, 1.7rem);
  color: var(--ember);
  opacity: .82;
  transform: rotate(-.6deg);
  text-align: center;
}

/* ---------- the categories: tags hung from a rail ---------- */

.home__cats {
  position: relative;
  display: flex; flex-wrap: wrap; justify-content: center;
  align-items: flex-start;
  gap: clamp(.75rem, 2.6vw, 2.4rem);
  padding-top: 4px;
  /* the rail every tag hangs from */
}
.home__cats::before {
  content: '';
  position: absolute; top: 0; left: 2%; right: 2%; height: 1px;
  background: linear-gradient(to right, transparent, rgba(237,226,203,.34) 12%, rgba(237,226,203,.34) 88%, transparent);
}

.cats__strings {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  overflow: visible;
}
.cats__string {
  fill: none;
  stroke: rgba(237, 226, 203, .22);
  stroke-width: 1;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: stringdraw 1.4s .45s var(--ease) forwards;
}
@keyframes stringdraw { to { stroke-dashoffset: 0; } }

/* one tag: a small plate hanging on its own thread off the rail */
.cat-tag {
  position: relative;
  display: block;
  transform: rotate(var(--tilt, 0deg));
  transform-origin: 50% 0;
  transition: transform .45s var(--ease);
}
.cat-tag__thread {
  display: block; width: 1px;
  height: var(--drop, 18px);
  margin: 0 auto;
  background: linear-gradient(to bottom,
    rgba(237,226,203,0), rgba(237,226,203,.4) 40%, rgba(237,226,203,.5));
}
.cat-tag__plate {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: .15rem;
  padding: .55rem 1.05rem .45rem;
  background: linear-gradient(168deg, rgba(25,16,9,.92), rgba(14,10,7,.94));
  border: 1px solid var(--ink-line);
  box-shadow: 0 10px 26px rgba(0,0,0,.45);
}
/* the punched hole the thread runs through */
.cat-tag__hole {
  position: absolute; top: 7px; left: 50%;
  width: 7px; height: 7px;
  transform: translateX(-50%);
  border-radius: 50%;
  background: var(--ink);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.9), 0 0 0 1.5px rgba(237,226,203,.28);
}
.cat-tag__name {
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 1.7vw, 1.5rem);
  letter-spacing: .045em;
  text-transform: uppercase;
  color: var(--paper);
  padding-top: .45rem;
  transition: color .3s;
}
.cat-tag__count {
  font-family: var(--font-mono);
  font-size: .6rem;
  letter-spacing: .14em;
  color: var(--paper-faint);
  transition: color .3s;
}
/* the peeked tag is the one the aperture is showing */
.cat-tag[data-peeked] .cat-tag__name,
.cat-tag:hover .cat-tag__name { color: var(--ember); }
.cat-tag[data-peeked] .cat-tag__count,
.cat-tag:hover .cat-tag__count { color: var(--ember); }
.cat-tag:hover, .cat-tag[data-peeked] {
  transform: rotate(0deg) translateY(2px);
}

/* ============================================================
   THE REGISTER — the full catalogue as a numbered list
   ============================================================ */

.reg-hero { padding: clamp(2rem, 6vh, 4.5rem) 0 clamp(1.5rem, 4vh, 3rem); }
.reg-hero__kicker {
  font-family: var(--font-script);
  font-size: clamp(1.15rem, 1.8vw, 1.5rem);
  color: var(--ember);
  opacity: .85;
  transform: rotate(-.8deg);
  margin-bottom: .9rem;
}
.reg-hero__title {
  font-size: clamp(2.6rem, 7.5vw, 5.6rem);
  margin-bottom: 1.4rem;
}
.reg-hero__title .kinetic { display: block; }
.reg-hero__blurb {
  max-width: 52ch;
  color: var(--paper-dim);
  font-size: .95rem; line-height: 1.75;
}
.reg-hero__meta {
  display: flex; align-items: center; gap: .9rem;
  margin-top: 1.4rem;
  font-family: var(--font-mono);
  font-size: .68rem; letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--paper-faint);
}
.reg-hero__meta b { color: var(--ember); font-weight: 500; }
.reg-hero__dot {
  width: 3px; height: 3px; border-radius: 50%;
  background: var(--madder);
}

/* the register rows: numbered, threaded, deadpan */
.register { border-top: 1px solid var(--ink-line); }
.reg-row {
  position: relative;
  display: grid;
  grid-template-columns: 3.2rem 1fr auto;
  align-items: baseline; gap: 1.1rem;
  padding: 1.15rem .35rem 1.15rem .1rem;
  border-bottom: 1px solid var(--ink-line);
  transition: background-color .3s, padding-left .35s var(--ease);
}
.reg-row__thread {
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 1px;
  background: linear-gradient(to bottom, transparent, var(--ember) 50%, transparent);
  opacity: 0;
  transition: opacity .3s;
}
.reg-row:hover { background: rgba(230, 180, 30, .045); padding-left: .8rem; }
.reg-row:hover .reg-row__thread { opacity: .8; }
.reg-row__num {
  font-family: var(--font-mono);
  font-size: .72rem;
  color: var(--ember);
  letter-spacing: .1em;
}
.reg-row--sub { padding-left: 2.4rem; }
.reg-row--sub .reg-row__num { color: var(--paper-faint); }
.reg-row__title {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 2.4vw, 1.8rem);
  line-height: 1.15;
  color: var(--paper);
  transition: color .3s;
}
.reg-row:hover .reg-row__title { color: var(--ember); }
.reg-row__sub {
  display: block; margin-top: .15rem;
  font-size: .72rem; letter-spacing: .05em;
  color: var(--paper-faint);
}
.reg-row__n {
  font-family: var(--font-mono);
  font-size: .7rem;
  color: var(--paper-faint);
}

/* the preview that trails the pointer down the register */
.peek {
  position: fixed; z-index: 80; pointer-events: none;
  width: 220px; aspect-ratio: 4/3;
  opacity: 0; transform: translate3d(-50%, -50%, 0) scale(.96) rotate(1.2deg);
  transition: opacity .3s var(--ease), transform .3s var(--ease);
  box-shadow: 0 18px 50px rgba(0,0,0,.6);
  border: 1px solid var(--ink-line);
  background: var(--ink-raised);
}
.peek img { width: 100%; height: 100%; object-fit: cover; }
.peek[data-on] { opacity: 1; transform: translate3d(-50%,-50%,0) scale(1) rotate(0deg); }
@media (hover: none), (pointer: coarse) { .peek { display: none; } }

.srch__lead {
  font-family: var(--font-mono);
  font-size: .66rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--paper-faint);
  margin: 2rem 0 1rem;
}

/* ============================================================
   TAGS — work cards as hung tags
   ============================================================ */

.taggrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
  gap: clamp(1.5rem, 2.6vw, 2.4rem);
  padding-top: 2.4rem;              /* room for the threads above */
}

.tag {
  position: relative;
  display: flex; flex-direction: column;
  transform: rotate(var(--tilt, 0deg));
  transform-origin: 50% 0;
  transition: transform .5s var(--ease);
}
/* thread + punched hole above every tag */
.tag__pin {
  display: block; height: 20px;
  position: relative;
}
.tag__string {
  position: absolute; left: 50%; top: 0;
  width: 1px; height: 100%;
  background: linear-gradient(to bottom, rgba(237,226,203,.05), rgba(237,226,203,.42));
}
.tag__string::after {
  content: '';
  position: absolute; left: 50%; bottom: -4px;
  width: 7px; height: 7px;
  transform: translateX(-50%);
  border-radius: 50%;
  background: var(--ink);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.9), 0 0 0 1.5px rgba(237,226,203,.3);
}
.tag__frame {
  position: relative; overflow: hidden;
  aspect-ratio: 4/5;
  background: var(--ink-raised);
  border: 1px solid var(--ink-line);
  /* a neutral mat, because her installation shots are very dark */
  padding: 7px;
}
.tag__frame::before {
  content: '';
  position: absolute; inset: 7px;
  border: 1px solid rgba(237,226,203,.07);
  pointer-events: none;
  z-index: 2;
}
.tag__frame img {
  width: 100%; height: 100%; object-fit: cover;
  filter: brightness(.94);
  transition: transform .8s var(--ease), filter .6s;
}
.tag:hover .tag__frame img { transform: scale(1.04); filter: brightness(1.05); }
.tag:hover { transform: rotate(0deg) translateY(-3px); }
.tag__film, .tag__empty--film {
  position: absolute; z-index: 3; left: 12px; bottom: 12px;
  font-family: var(--font-mono);
  font-size: .56rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--ember);
  padding: .2rem .5rem;
  border: 1px solid rgba(230, 180, 30, .4);
  background: rgba(14, 10, 7, .8);
}
.tag__empty {
  display: grid; place-items: center; height: 100%;
  color: var(--paper-faint);
  font-family: var(--font-mono);
  font-size: .62rem; letter-spacing: .18em; text-transform: uppercase;
}
.tag__num {
  margin-top: .8rem;
  font-family: var(--font-mono);
  font-size: .62rem; letter-spacing: .18em;
  color: var(--ember);
  opacity: .75;
}
.tag__title {
  margin-top: .3rem;
  font-family: var(--font-display);
  font-size: 1.12rem; line-height: 1.3;
  color: var(--paper);
}
.tag__meta {
  margin-top: .25rem;
  font-size: .64rem; letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--paper-faint);
}

/* ============================================================
   CATEGORY PAGE
   ============================================================ */

.cat__kicker {
  font-family: var(--font-script);
  font-size: 1.2rem;
  color: var(--ember);
  opacity: .8;
  transform: rotate(-.8deg);
  margin-bottom: .2rem;
}
.cat__title {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(2rem, 4.6vw, 3.4rem); line-height: 1.05;
  letter-spacing: .005em; color: var(--paper);
}
.cat__blurb {
  margin-top: .9rem; max-width: var(--measure);
  font-size: .92rem; line-height: 1.75; color: var(--paper-dim);
}
.cat__blurb--sub { margin: .25rem 0 1.25rem; font-size: .82rem; }
.cat__tools { margin: 2rem 0 0; }

.subgroup { margin-top: 3.25rem; }
.subgroup .sec-head h3 {
  font-family: var(--font-mono);
  font-size: .72rem; letter-spacing: .24em; text-transform: uppercase;
  color: var(--ember); font-weight: 500;
}
.sec-head h2 {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(1.7rem, 3.6vw, 2.6rem); letter-spacing: .005em;
}

/* ============================================================
   THE STRIP — sideways navigation, stitched to a rail
   ============================================================ */

.catstrip {
  display: flex; flex-wrap: wrap; gap: .4rem 1.7rem; align-items: baseline;
  padding-bottom: 1.1rem; margin-bottom: 1.6rem;
  border-bottom: 1px dashed var(--ink-line);
  position: relative;
}
.catstrip__item {
  font-family: var(--font-mono);
  font-size: .62rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--paper-faint);
  padding: .3rem 0;
  border-bottom: 1px solid transparent;
  transition: color .25s, border-color .25s;
}
.catstrip__item:hover { color: var(--paper); }
.catstrip__item.is-on { color: var(--ember); border-bottom-color: var(--ember); }
.catstrip__item--all { margin-left: auto; color: var(--paper-dim); }
@media (max-width: 620px) {
  .catstrip { gap: .35rem 1rem; }
  .catstrip__item--all { margin-left: 0; }
}

/* ============================================================
   WORK PAGE — the strip, then the entry
   ============================================================ */

.wk__head { margin-bottom: 2rem; }
.wk__title {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(2rem, 4.8vw, 3.4rem); line-height: 1.06;
  letter-spacing: .005em;
}

.wk__foot {
  display: grid; gap: clamp(2rem, 5vw, 4rem);
  margin-top: clamp(2.5rem, 6vh, 4rem);
}
@media (min-width: 900px) {
  .wk__foot { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); align-items: start; }
}

/* the specification: a note taped into the workshop */
.spec {
  position: relative;
  padding: 1.5rem 1.4rem;
  background: rgba(25, 16, 9, .55);
  border: 1px solid var(--ink-line);
}
/* tape at two corners — translucent, slightly wrong, like it was placed by hand */
.spec::before, .spec::after {
  content: '';
  position: absolute;
  width: 74px; height: 20px;
  background: rgba(237, 226, 203, .09);
  border-left: 1px solid rgba(237,226,203,.1);
  border-right: 1px solid rgba(237,226,203,.1);
  backdrop-filter: blur(1px);
}
.spec::before { top: -9px; left: 18px; transform: rotate(-4deg); }
.spec::after { bottom: -9px; right: 22px; transform: rotate(3deg); }

.spec__lead {
  font-family: var(--font-mono);
  font-size: .62rem; letter-spacing: .26em; text-transform: uppercase;
  color: var(--ember);
  margin-bottom: 1rem;
}
.spec__list { display: grid; gap: .55rem; }
.spec__list div {
  display: grid; grid-template-columns: 6.5rem 1fr; gap: 1rem;
  padding-bottom: .55rem;
  border-bottom: 1px dashed var(--ink-line);
}
.spec__list div:last-child { border-bottom: none; padding-bottom: 0; }
.spec__list dt {
  font-family: var(--font-mono);
  font-size: .6rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--paper-faint);
  padding-top: .2rem;
}
.spec__list dd { font-size: .88rem; color: var(--paper); }

.wk__writing .prose { margin-top: 0; }
.prose {
  margin-top: 2rem; max-width: var(--measure);
  font-size: .98rem; line-height: 1.85;
  color: var(--paper-dim);
}
.prose p + p { margin-top: 1.15em; }

/* about */
.page__title {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(2.2rem, 6vw, 3.6rem); line-height: 1.05;
  margin-bottom: 2rem;
}
.page .prose a, .page a[href^="mailto"], .page a[href^="http"] {
  color: var(--ember);
  border-bottom: 1px dashed rgba(230, 180, 30, .4);
}
.about__contact {
  margin-top: 3rem; padding-top: 2rem;
  border-top: 1px dashed var(--ink-line);
}
.prose--tight p { font-size: .86rem; }
.contact-list { display: grid; gap: 1rem; margin-top: 2.5rem; }
.contact-list a {
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  padding: 1.1rem 0; border-bottom: 1px solid var(--ink-line);
  font-family: var(--font-mono);
  font-size: .7rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--paper-dim); transition: color .3s;
}
.contact-list a:hover { color: var(--ember); }
.contact-list span:last-child { color: var(--paper-faint); text-transform: none; letter-spacing: normal; font-family: var(--font-body); }

/* buttons: primary reads as a label; hover flips it like a tag */
.btn {
  transition: transform .3s var(--ease), background-color .3s, color .3s, border-color .3s;
}
.btn:not(.btn--ghost):not(.btn--danger):hover { transform: rotate(-.6deg) translateY(-1px); }

/* ============================================================
   motion off
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .cats__string { animation: none; stroke-dashoffset: 0; }
  .home__name::after { animation: none; transform: scaleX(1); }
  .view { animation-duration: .01s; }
  .tag, .cat-tag, .btn { transition: none; }
}


/* ============================================================
   Mobile — the portal centred, the pieces behind everything
   ------------------------------------------------------------
   The reserved column left the phone half-empty. Her drawing puts
   the figure BEHIND the portal; on a phone that is the whole
   arrangement: the aperture centred, the pieces hanging behind it
   and behind the text, dimmed to stay out of the writing's way.
   ============================================================ */
@media (max-width: 720px), (max-aspect-ratio: 4/5) {
  .home__stage { padding-right: 0; }
  .home__portal { width: 88vw; margin: 0 auto; }
  /* the pieces bleed past the edges on purpose; clip, never scroll */
  .home { overflow-x: clip; }

  .hang--sculpture {
    left: auto;
    right: -7vw;
    top: -7svh;
    translate: none;
    z-index: 0;
    opacity: .55;
  }
  .hang--sculpture .hang__thread { height: 5svh; }
  .hang--sculpture .hang__obj {
    height: auto;
    width: clamp(120px, 34vw, 220px);
    opacity: .9;
  }

  .hang--yellow {
    display: block;
    left: -4vw;
    right: auto;
    top: -10svh;
    z-index: 0;
    opacity: .5;
  }
  .hang--yellow .hang__thread { height: 4svh; }
  .hang--yellow .hang__obj {
    height: auto;
    width: clamp(100px, 30vw, 190px);
  }
}
