/* PARK SANG GYU — shared styles. See DESIGN.md. */

:root {
  --bg: #f7f6f3; /* warm gallery white */
  --ink: #1a1a1a;
  --muted: #6e6e6e;
  --hair: #dcdcdc;
  --accent: #f7931a;
  /* the dark room: the exhibition mini-site and the one dark card on the
     list page are the same room, so its three values live here, once */
  --dark-bg: #0e0e0e;
  --dark-ink: #f2f2f2;
  --dark-muted: #9b9b9b;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Apple SD Gothic Neo", "Malgun Gothic", "Noto Sans KR", sans-serif;
  --serif: "Iowan Old Style", Palatino, Georgia, serif;
  --pad: 20px;
  --max: 1080px;
  --measure: 34em; /* body-text line length */
}

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

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

body {
  font: 16px/1.7 var(--sans);
  background: var(--bg);
  color: var(--ink);
  /* no orphans: never leave a lone word — or in Korean a lone syllable —
     on its own line */
  text-wrap: pretty;
  word-break: keep-all;
  overflow-wrap: break-word;
}
html[lang="ko"] body { letter-spacing: -0.01em; }
h1, h2, h3 { text-wrap: balance; }

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }

/* ── landing → works ─────────────────────────── */

/* The name is the hinge between those two pages: it *is* the landing, and it
   is the header of the list. Naming both makes the browser treat them as one
   thing, so it glides from the middle of the screen up into the header
   instead of blinking out. This is the only crossing that animates: a
   cross-document transition needs BOTH documents to opt in, so the opt-in
   (`@view-transition`) sits in a <style> block on those four pages alone —
   landing and works, EN and KO. Every other navigation stays a plain cut,
   including the way back: the landing cancels the transitions that end in it,
   so the name can play its own arrival there (see its <style> block).
   The naming and the timing live here because both ends need them, and
   because the destination document is the one that styles the transition.
   Browsers without view transitions get today's cut everywhere. */
.wordmark,
.landing h1 { view-transition-name: wordmark; }
::view-transition-group(wordmark) {
  animation-duration: 1.1s;
  animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
/* the page under it changes hands quickly; the works arriving (below) is the
   part meant to be watched */
::view-transition-old(root),
::view-transition-new(root) { animation-duration: 0.3s; }

.kicker {
  font-family: var(--serif);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Captions, years, tombstone notes: serif italic muted (DESIGN.md "Type").
   One fact, one rule — each component below adds only its own size and box. */
.site-footer,
.gallery figcaption time,
.gallery-empty,
.detail figcaption,
.todo {
  font-family: var(--serif);
  font-style: italic;
  color: var(--muted);
}

/* ── header / footer ─────────────────────────── */

.site-header {
  max-width: var(--max);
  margin: 0 auto;
  padding: 18px var(--pad);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px 16px;
}
.wordmark { font-size: 14px; font-weight: 600; letter-spacing: 0.08em; }
.site-header .lang { font-size: 13px; color: var(--muted); transition: color 0.15s; }
.site-header .lang:hover { color: var(--ink); }

.site-footer {
  max-width: var(--max);
  margin: 0 auto;
  padding: 28px var(--pad) 36px;
  font-size: 12px;
}
/* the credit: a hairline, no louder than the © beside it */
.site-footer a { border-bottom: 1px solid var(--hair); transition: color 0.15s; }
.site-footer a:hover { color: var(--ink); }

/* ── landing ─────────────────────────────────── */

/* the link is the whole screen, so a tap anywhere enters the works */
.landing main a {
  min-height: 100dvh;
  display: grid;
  place-content: center;
  text-align: center;
  padding: var(--pad);
  overflow: clip; /* the name is widest mid-arrival — never a scrollbar for it */
}

/* The name arrives once, the way raking light crosses a gallery wall: a soft
   lit edge travels left to right while the tracking settles and the letters
   come into focus. The mask is that edge — a gradient three times wider than
   the line, slid across it; at rest only its opaque end covers the text, so
   nothing is left running and nothing is dimmed. Two curves: the type snaps
   out of the blur and then micro-settles (1.4s), the light crosses at its own
   even, decelerating pace (1.8s), so a letter is still resolving as the light
   reaches it. Tracking and the optical margin always move together, or the
   name drifts off centre on the way in. */
.landing h1 {
  font-size: clamp(24px, 6.4vw, 54px);
  font-weight: 600;
  letter-spacing: 0.14em;
  margin-left: 0.14em; /* optically recenters the tracked-out caps */
  white-space: nowrap;
  mask: linear-gradient(100deg, #000 40%, transparent 58%) 0 0 / 300% 100%
    no-repeat;
  animation: name-settle 1.4s cubic-bezier(0.16, 1, 0.3, 1) backwards,
    name-light 1.8s ease-out backwards;
  transition: letter-spacing 0.6s ease, margin-left 0.6s ease, opacity 0.3s;
}
/* Only a from-frame: the animation lands on the rule above — or on the hover
   state, if the pointer was already there. Nothing is left filled forwards,
   so the hover below stays free to transition once the name has arrived. */
@keyframes name-settle {
  from {
    opacity: 0;
    letter-spacing: 0.26em;
    margin-left: 0.26em;
    filter: blur(0.18em); /* em, so it scales with the clamped size */
  }
}
@keyframes name-light {
  from { mask-position: 100% 0; }
}
/* The whole screen is the link, but only the name answers to the pointer: the
   hover hangs on the <h1>, whose box is exactly the line of text (the grid
   centres a max-content track), so it fires near the letters and nowhere else.
   The name steps back — and, for anyone who welcomes movement, opens a little.
   Split in two so the reduced-motion reader keeps the affordance and loses
   only the motion. */
@media (hover: hover) {
  .landing h1:hover { opacity: 0.6; }
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .landing h1:hover { letter-spacing: 0.17em; margin-left: 0.17em; }
}
/* no light, no focus pull, no travel — the name simply appears */
@media (prefers-reduced-motion: reduce) {
  .landing h1 { mask: none; animation: name-fade 0.7s ease-out backwards; }
}
@keyframes name-fade {
  from { opacity: 0; }
}

/* ── gallery list ────────────────────────────── */

.gallery-page main {
  max-width: var(--max);
  margin: 0 auto;
  padding: 6px var(--pad) 44px;
}
/* gallery.js adds .search-ready once the bar actually works */
.search-ready main { padding-bottom: 170px; } /* room for the fixed search bar */
.page-title { margin: 12px 0 24px; }
.gallery { list-style: none; columns: 2; column-gap: 12px; }
.gallery > li { break-inside: avoid; margin-bottom: 20px; }
@media (min-width: 760px) {
  .gallery { columns: 3; column-gap: 22px; }
  .gallery > li { margin-bottom: 30px; }
}
/* The works are hung, not dropped: each card lifts into place a beat after
   the one before it, so the list arrives with the same unhurried left-to-right
   movement as the name it came from. sibling-index() keeps that rhythm without
   a rule per card — WORKS.md can grow and nothing here changes; where it is
   unsupported the cards simply arrive together, which is the same idea with
   the rhythm removed. Filtering replays it only for cards that actually come
   back: gallery.js leaves the ones already on screen untouched. */
.gallery > li {
  animation: plate-in 0.7s cubic-bezier(0.16, 1, 0.3, 1) backwards;
  animation-delay: calc(sibling-index() * 55ms);
}
@keyframes plate-in {
  from { opacity: 0; translate: 0 14px; }
}
@media (prefers-reduced-motion: reduce) {
  .gallery > li { animation: plate-fade 0.5s ease-out backwards; }
}
@keyframes plate-fade {
  from { opacity: 0; }
}

.gallery a { display: block; }
.gallery img { width: 100%; }
.gallery figcaption { margin-top: 7px; font-size: 13px; line-height: 1.5; }
.gallery figcaption time { margin-left: 4px; }
.gallery-empty { text-align: center; padding: 48px 0; }

/* A swatch of the exhibition's dark room, so it must read as the same room:
   re-point the tokens rather than restate the hex. */
.card--exhibition a {
  --ink: var(--dark-ink);
  --muted: var(--dark-muted);
  background: var(--dark-bg);
  color: var(--ink);
  padding: 24px 18px 22px;
}
.card--exhibition .kicker { color: var(--accent); }
.card--exhibition h2 { margin-top: 12px; font-size: 20px; font-weight: 600; }
.card--exhibition p {
  margin-top: 8px;
  font-family: var(--serif);
  font-style: italic;
  font-size: 13px;
  color: var(--muted);
}

/* ── search / filter bar ─────────────────────── */

/* One fixed box, only as wide as the panel — so taps outside it reach the
   gallery underneath without a pointer-events dance. */
.searchbar {
  display: none; /* revealed by gallery.js — see .search-ready */
  position: fixed;
  inset: auto var(--pad) calc(30px + env(safe-area-inset-bottom));
  max-width: 560px;
  margin-inline: auto;
  background: rgba(252, 251, 249, 0.92);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border: 1px solid var(--hair);
  border-radius: 16px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.14);
  padding: 4px 8px 8px;
  transition: border-color 0.15s;
}
.search-ready .searchbar { display: block; }
.searchbar:focus-within { border-color: var(--ink); }
.searchbar input {
  width: 100%;
  border: 0;
  outline: 0;
  background: none;
  font: 15px var(--sans);
  color: var(--ink);
  padding: 10px 8px 8px;
}
.searchbar input::placeholder { color: var(--muted); }
.chips { display: flex; flex-wrap: wrap; gap: 6px; padding: 2px 4px 0; }
.chip {
  font: 12px var(--sans);
  color: var(--muted);
  background: var(--bg);
  border: 1px solid var(--hair);
  border-radius: 999px;
  padding: 4px 12px;
  cursor: pointer;
  transition: color 0.15s, background 0.15s;
}
.chip:hover { color: var(--ink); }
.chip[aria-pressed="true"] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg);
}

/* ── artwork detail ──────────────────────────── */

.detail main { max-width: 880px; margin: 0 auto; padding: 6px var(--pad) 44px; }
.back {
  display: inline-block;
  margin-bottom: 16px;
  font-size: 13px;
  color: var(--muted);
  transition: color 0.15s;
}
.back:hover { color: var(--ink); }
/* Image plates. A page's own <style> block sets only the max-width it wants
   (see DESIGN.md "Per-page character"); the centering belongs here, once. */
.work-hero,
.work-view { margin-inline: auto; }
.detail figcaption { margin-top: 8px; font-size: 13px; }
.work-head { margin-top: 28px; padding-top: 20px; border-top: 1px solid var(--ink); }
.work-head h1 { font-size: 24px; font-weight: 600; }
.work-head h1 em {
  margin-left: 10px;
  font-family: var(--serif);
  font-size: 17px;
  font-weight: 400;
  color: var(--muted);
}
.tombstone {
  margin-top: 8px;
  font-family: var(--serif);
  font-size: 14px;
  color: var(--muted);
}
.work-body { margin-top: 20px; max-width: var(--measure); }
.work-body p + p { margin-top: 14px; }
.todo {
  border: 1px dashed var(--hair);
  padding: 14px 16px;
  font-size: 14px;
}

/* One way out of a work: back to all of them, centred. No prev/next — the list
   is the only order the site claims. */
.work-nav {
  max-width: 880px;
  margin: 0 auto;
  padding: 20px var(--pad) 6px;
  border-top: 1px solid var(--hair);
  text-align: center;
  font-size: 13px;
  color: var(--muted);
}
.work-nav a:hover { color: var(--ink); }
