/* ------------------------------------------------------------------ tokens */
/* Subsets built by tools/subset-fonts.py — common-use characters plus
   everything currently in content.json. Anything outside falls through to
   Noto Sans SC. Re-run the script after adding unusual characters. */
@font-face {
  font-family: "BLIX";
  src: url("/fonts/BLIX-Text.subset.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "BLIX";
  src: url("/fonts/BLIX-Bold.subset.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #f6f4ef;
  --bg-2: #efece5;
  --fg: #14130f;
  --fg-60: rgba(20, 19, 15, 0.6);
  --fg-40: rgba(20, 19, 15, 0.4);
  --fg-25: rgba(20, 19, 15, 0.25);
  --line: rgba(20, 19, 15, 0.14);
  --line-soft: rgba(20, 19, 15, 0.07);
  --grid-line: rgba(20, 19, 15, 0.045);
  --accent: #1b2fff;

  /* Latin from Space Grotesk, CJK from BLIX. */
  --sans: "Space Grotesk", "BLIX", "Noto Sans SC", "PingFang SC", "Helvetica Neue", Arial, sans-serif;
  --mono: "JetBrains Mono", "BLIX", "Noto Sans SC", ui-monospace, SFMono-Regular, Menlo, monospace;

  --pad: clamp(20px, 5vw, 64px);
  --max: 1240px;
  /* Card padding, and how far a card's contents sit from the grid's outer
     edge (that 1px is the grid frame). The hero borrows it so its text lines
     up with the posters below rather than with the frame. */
  --card-pad: 14px;
  --card-inset: calc(var(--card-pad) + 1px);
  /* One rhythm for every major block on the inner pages, so the page doesn't
     breathe at four different rates. */
  --gap-block: clamp(32px, 4.5vw, 54px);
  --gap-head: 20px;   /* section heading → its content */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #161512;
    --bg-2: #1e1d19;
    --fg: #ece9e2;
    --fg-60: rgba(236, 233, 226, 0.6);
    --fg-40: rgba(236, 233, 226, 0.4);
    --fg-25: rgba(236, 233, 226, 0.25);
    --line: rgba(236, 233, 226, 0.16);
    --line-soft: rgba(236, 233, 226, 0.08);
    --grid-line: rgba(236, 233, 226, 0.055);
    --accent: #7f8bff;
  }
}

/* ------------------------------------------------------------------- reset */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; cursor: none; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.55;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  cursor: none;
}
@media (hover: none), (pointer: coarse) {
  html, body { cursor: auto; }
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; cursor: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: none; }
@media (hover: none), (pointer: coarse) {
  a, button { cursor: pointer; }
}
h1, h2, h3, p, ul, figure { margin: 0; }
ul { padding: 0; list-style: none; }
::selection { background: var(--fg); color: var(--bg); }

/* ------------------------------------------------------------- primitives */
.wrap {
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: var(--pad);
}

.label {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-40);
}

.rule { height: 1px; background: var(--line); border: 0; }

.section-head {
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
.section-head .grow { flex: 1; height: 1px; background: var(--line-soft); }

/* ------------------------------------------------------------------ header */
.site-head {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
.site-head .wrap {
  height: 62px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 500;
  letter-spacing: -0.01em;
  font-size: 14px;
}
.brand .mark {
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border: 1px solid var(--fg);
  border-radius: 50%;
  font-size: 11px;
  line-height: 1;
}
.nav { display: flex; align-items: center; gap: clamp(14px, 3vw, 34px); flex: 1; position: relative; }
.nav a {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-60);
  padding-block: 4px;
  transition: color 0.25s var(--ease);
}
.nav a:hover { color: var(--fg); }
.nav a[aria-current="page"] { color: var(--fg); }

/* One underline for the whole nav that slides to whichever tab is current —
   no layout shift, and the movement carries the eye across. Positioned from
   JS against the active link's box. */
.nav-ind {
  position: absolute;
  left: 0;
  height: 1px;
  width: 0;
  background: var(--accent);
  transform-origin: left;
  pointer-events: none;
  opacity: 0;
}
.nav-ind.ready {
  opacity: 1;
  transition: transform 0.42s var(--ease), width 0.42s var(--ease), opacity 0.2s var(--ease);
}

.lang {
  display: inline-flex; align-items: center; gap: 5px;
  margin-left: auto;              /* always parked at the far right */
  padding-left: clamp(6px, 2vw, 16px);
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.06em;
}
.lang button { color: var(--fg-25); padding: 4px 0; transition: color 0.2s var(--ease); }
.lang button:hover { color: var(--fg-60); }
.lang button.on { color: var(--fg); }
.lang .sep { color: var(--fg-25); }

@media (max-width: 620px) {
  .site-head .wrap { height: 54px; gap: 12px; }
  .brand { font-size: 12px; white-space: nowrap; }
  .brand .mark { width: 19px; height: 19px; font-size: 10px; }
  .nav { gap: 13px; }
  .nav a { font-size: 9.5px; letter-spacing: 0.08em; }
}

/* -------------------------------------------------------------------- hero */
.intro {
  position: relative;
  padding-block: clamp(36px, 6vh, 60px) clamp(33px, 5.2vh, 51px);
  border-bottom: 1px solid var(--line);
}
/* Grid lives on its own layer so it can be masked away from the left side,
   where the name, icons and schedule sit — the ruling stays a texture on the
   empty half instead of running through the type. */
.intro::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: 44px 44px;
  background-position: right center;
  -webkit-mask-image: linear-gradient(90deg, transparent 0 30%, #000 68%);
  mask-image: linear-gradient(90deg, transparent 0 30%, #000 68%);
}
/* Indented to the works grid's card content, not to the frame itself. */
.intro .wrap { position: relative; z-index: 1; padding-left: calc(var(--pad) + var(--card-inset)); }

/* Name and the social icons share one line. */
.name-row {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 6px;
}
.name {
  font-size: 17px;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.01em;
}
.lede {
  margin-top: 10px;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 15px;
  line-height: 1.75;
  color: var(--fg-60);
}
.hero-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}
.hero-links a {
  /* Matched to the name's line box so the row reads as one line. */
  height: 18px;
  display: inline-flex;
  align-items: center;
  color: var(--fg-40);
  transition: color 0.25s var(--ease), transform 0.25s var(--ease);
}
.hero-links a:hover {
  color: var(--fg);
  transform: translateY(-1px);
}
.hero-links a svg {
  width: 15px;
  height: 15px;
  display: block;
}
.hero-links a:not(:has(svg)) {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.hero-meta {
  margin-top: clamp(16px, 3vw, 24px);
  display: flex;
  flex-wrap: wrap;
  gap: 10px 32px;
  align-items: flex-end;
}

/* schedule strip */
.schedule {
  --slot-w: 28px;
  --dot: 16px;
  display: flex;
  gap: 8px;
  align-items: flex-end;
  /* Each label is centred over its square, so the first square sits inset by
     half the leftover slot width. Pull the strip back by exactly that much so
     it lines up with the name and the icons above. */
  margin-left: calc((var(--dot) - var(--slot-w)) / 2);
}
.slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  flex: 0 0 var(--slot-w);
}
.slot i {
  width: var(--dot);
  height: var(--dot);
  border-radius: 3px;
  display: block;
  border: 1px solid transparent;
  transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.slot:hover i {
  transform: translateY(-2px);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 25%, transparent);
}
.slot b {
  font-family: var(--mono);
  font-size: 8.5px;
  font-weight: 400;
  letter-spacing: 0.02em;
  color: var(--fg-40);
  text-transform: uppercase;
}
.slot.open i { background: color-mix(in srgb, var(--accent) 35%, var(--bg)); }
.slot.tight i { background: color-mix(in srgb, var(--accent) 65%, var(--bg)); }
.slot.full i { background: var(--accent); }
.slot.closed i { background: var(--bg-2); border-color: var(--line); }

/* --------------------------------------------------------------- filters */
.filters {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-top: 20px;
}
.chip {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.1em;
  text-transform: uppercase;
  border: 1px solid var(--line); border-radius: 999px;
  padding: 6px 14px; color: var(--fg-60);
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease), background 0.2s var(--ease);
}
.chip:hover { border-color: var(--fg-40); color: var(--fg); }
.chip[aria-pressed="true"] {
  background: var(--fg); border-color: var(--fg); color: var(--bg);
}

/* ------------------------------------------------------------------- works */
.works { padding-block: clamp(48px, 8vw, 96px); }
/* Hairline frame that degrades gracefully when the last row is not full. */
.grid-frame {
  display: grid;
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
}
.grid-frame > * {
  background: var(--bg);
  box-shadow: 1px 0 0 var(--line), 0 1px 0 var(--line);
}

.works-grid {
  margin-top: 26px;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
}
.work {
  padding: var(--card-pad) var(--card-pad) 16px;
  display: flex;
  flex-direction: column;
  gap: 11px;
  text-align: left;
  width: 100%;
  transition: background 0.3s var(--ease);
}
.work:hover { background: var(--bg-2); }
.work-thumb {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--bg-2);
  border: 1px solid var(--line-soft);
}
.work-thumb.no-img {
  background-image: repeating-linear-gradient(
    -45deg, transparent 0 9px, var(--line-soft) 9px 10px
  );
}
.work-thumb .ph {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--fg-25);
}
/* Posters sit dimmed at rest and come back to full colour on hover. */
.work-thumb img {
  width: 100%; height: 100%; object-fit: cover;
  filter: brightness(0.85) saturate(0.95);
  transition: filter 0.45s var(--ease), transform 0.6s var(--ease);
}
.work:hover .work-thumb img { filter: none; transform: scale(1.025); }
.work-thumb .idx {
  position: absolute; left: 8px; top: 7px; z-index: 1;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em;
  color: var(--fg-40);
}
.work-thumb .play {
  position: absolute; right: 8px; bottom: 8px; z-index: 1;
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--bg); border: 1px solid var(--line);
  font-size: 9px; padding-left: 2px;
  opacity: 0; transform: translateY(4px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}
.work:hover .play { opacity: 1; transform: none; }

/* Credits — which hats I wore on this one. Under the title on the left, with
   the category holding the right end of the same line. */
.work-meta { display: flex; flex-direction: column; gap: 5px; }
.work-foot {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}
.work-roles { display: flex; flex-wrap: wrap; gap: 4px; }
.work-roles span {
  font-family: var(--mono);
  font-size: 9.5px;
  line-height: 1.6;
  letter-spacing: 0.06em;
  padding: 0 6px;
  border-radius: 999px;
  color: var(--fg-40);
  border: 1px solid var(--line);
  white-space: nowrap;
  transition: color 0.3s var(--ease), border-color 0.3s var(--ease);
}
.work:hover .work-roles span { color: var(--fg-60); border-color: var(--fg-25); }
.work-foot .cat { flex: none; padding-top: 1px; }

.work-row { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.work-title { font-size: 17px; font-weight: 500; letter-spacing: -0.02em; }
.work-sub {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--fg-40);
}

.empty {
  padding: 60px 20px;
  text-align: center;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-40);
}

/* ------------------------------------------------------------------ player */
.player {
  position: fixed; inset: 0; z-index: 100;
  display: none; place-items: center;
  padding: clamp(16px, 4vw, 48px);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(10px);
}
.player[open] { display: grid; }
.player-inner { width: min(1240px, 100%); max-height: 100%; display: flex; flex-direction: column; }
.player-bar {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; padding-bottom: 10px;
}

/* Player, then credits under it; stills stack down the right-hand side. The
   right column disappears entirely when a work has no stills. */
.player-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 280px;
  gap: 14px;
  min-height: 0;
}
.player-body.solo { grid-template-columns: minmax(0, 1fr); }

.player-frame {
  aspect-ratio: 16 / 9; width: 100%;
  border: 1px solid var(--line); background: #000;
}
.player-frame iframe { width: 100%; height: 100%; border: 0; display: block; }

.player-info {
  margin-top: 12px;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
}
.player-roles { display: flex; flex-wrap: wrap; gap: 5px; }
.player-roles span {
  font-family: var(--mono);
  font-size: 10px;
  line-height: 1.7;
  letter-spacing: 0.08em;
  padding: 0 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--fg-60);
  white-space: nowrap;
}
.player-info .cat { flex: none; padding-top: 3px; }

.player-shots {
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-right: 2px;
}
.player-shots img {
  width: 100%;
  border: 1px solid var(--line-soft);
  background: var(--bg-2);
}
.player-shots::-webkit-scrollbar { width: 4px; }
.player-shots::-webkit-scrollbar-thumb { background: var(--fg-25); border-radius: 2px; }

@media (max-width: 860px) {
  .player-body { grid-template-columns: minmax(0, 1fr); }
  .player-shots {
    flex-direction: row;
    overflow-x: auto;
    overflow-y: hidden;
    max-height: 120px;
  }
  .player-shots img { width: auto; height: 100%; }
}
.close {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--fg-60);
}
.close:hover { color: var(--fg); }

/* ------------------------------------------------------------------ pages */
.page { padding-block: clamp(30px, 5vh, 48px) clamp(48px, 8vw, 92px); }
.page-title {
  font-size: clamp(2.4rem, 7vw, 5.2rem);
  font-weight: 500; line-height: 0.95; letter-spacing: -0.045em;
  margin-top: 18px;
}

.cols {
  margin-top: var(--gap-block);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
.cell { padding: 22px 20px 26px; }
.cell .k { display: block; margin-bottom: 10px; }
.cell .v { font-size: 17px; font-weight: 500; letter-spacing: -0.015em; }
.cell .v.small { font-size: 15px; font-weight: 400; color: var(--fg-60); letter-spacing: 0; }

/* mail / QQ / WeChat — small pills instead of one oversized address. The two
   that aren't links copy themselves to the clipboard when clicked. */
.contact-icons {
  margin-top: clamp(26px, 4vw, 44px);
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.contact-icons .c {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 8px 14px 8px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--fg-60);
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.contact-icons .c svg { width: 15px; height: 15px; display: block; flex: none; }
.contact-icons .c .v {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.04em;
}
.contact-icons .c:hover { color: var(--fg); border-color: var(--fg-40); }
.contact-icons .c.copied { color: var(--accent); border-color: var(--accent); }

.links { margin-top: var(--gap-block); border-top: 1px solid var(--line); }
.links a {
  display: flex; align-items: center; gap: 16px;
  padding: 16px 2px;
  border-bottom: 1px solid var(--line);
  transition: padding-left 0.3s var(--ease);
}
.links a:hover { padding-left: 12px; }
.links .n { font-family: var(--mono); font-size: 10px; color: var(--fg-25); width: 26px; }
.links .t { font-size: 16px; font-weight: 500; letter-spacing: -0.015em; }
.links .h { font-family: var(--mono); font-size: 11px; color: var(--fg-40); margin-left: auto; }

/* -------------------------------------------------------------- commission */
.statement {
  margin-top: 20px;
  max-width: 52ch;
  font-size: 15px;
  line-height: 1.75;
  color: var(--fg-60);
}

.tag-list { display: flex; flex-wrap: wrap; gap: 6px 0; }
.tag-list li {
  font-size: 13.5px; color: var(--fg);
  padding-right: 12px; margin-right: 12px;
  border-right: 1px solid var(--line);
  line-height: 1.3;
}
.tag-list li:last-child { border-right: 0; margin-right: 0; padding-right: 0; }

/* ------------------------------------------------------------ rate groups */
.group { margin-top: var(--gap-block); }
.group-note {
  margin-top: 14px;
  max-width: 60ch;
  font-size: 13.5px;
  color: var(--fg-60);
}

.tiers {
  margin-top: var(--gap-head);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
}
.tier { padding: 22px 20px 24px; display: flex; flex-direction: column; gap: 14px; }
.tier h3 { font-size: 16px; font-weight: 500; letter-spacing: -0.01em; line-height: 1.35; }
.tier .price {
  font-family: var(--mono);
  font-size: clamp(1.35rem, 3vw, 1.75rem);
  font-weight: 500; letter-spacing: -0.02em; line-height: 1;
}
.tier .inc { display: grid; gap: 6px; }
.tier .inc li {
  font-size: 13px; letter-spacing: 0.01em;
  color: var(--fg-60); padding-left: 14px; position: relative;
}
.tier .inc li::before {
  content: ""; position: absolute; left: 0; top: 0.72em;
  width: 6px; height: 1px; background: var(--fg-25);
}
.tier .fit {
  margin-top: auto; padding-top: 12px;
  border-top: 1px solid var(--line-soft);
  font-size: 13px; color: var(--fg-60);
}
.tier .fit .label { display: block; margin-bottom: 5px; }
.tier .tier-desc {
  font-size: 12.5px; line-height: 1.6; color: var(--fg-40);
}

.block { margin-top: var(--gap-block); }
.steps {
  margin-top: var(--gap-head);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
}
.step { padding: 20px 18px 24px; }
.step .n { font-family: var(--mono); font-size: 10px; color: var(--accent); letter-spacing: 0.1em; }
.step h3 { margin-top: 12px; font-size: 16px; font-weight: 500; letter-spacing: -0.02em; }
.step p { margin-top: 6px; font-size: 13.5px; color: var(--fg-60); }

.terms { margin-top: var(--gap-head); border-top: 1px solid var(--line); }
.terms li {
  display: flex; gap: 18px; padding: 15px 2px;
  border-bottom: 1px solid var(--line);
  font-size: 14.5px; color: var(--fg);
}
.terms li span { font-family: var(--mono); font-size: 10px; color: var(--fg-25); padding-top: 4px; }

.note {
  margin-top: 22px;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em;
  color: var(--fg-40);
}

/* ------------------------------------------------------------------ footer */
.site-foot { border-top: 1px solid var(--line); margin-top: auto; }
.site-foot .wrap {
  min-height: 58px;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.site-foot .label { padding-block: 14px; }
.site-foot .icp { transition: color 0.25s var(--ease); }
.site-foot .icp:hover { color: var(--fg); }

body { min-height: 100vh; display: flex; flex-direction: column; }
main { flex: 1; }

/* --------------------------------------------------------- page transitions
 * Navigation swaps <main> in place instead of reloading, so the background,
 * the header and the custom cursor never blink. Only the content crossfades.
 * ------------------------------------------------------------------------ */
main {
  transition: opacity 0.16s var(--ease), transform 0.16s var(--ease);
}
body.nav-out main {
  opacity: 0;
  transform: translateY(-3px);
}
body.nav-in main {
  opacity: 0;
  transform: translateY(5px);
  transition: none;
}

/* A hairline that runs across the top while the next page is being fetched —
   enough to say "something is happening" on a slow connection. */
.nav-progress {
  position: fixed;
  inset: 0 auto auto 0;
  height: 2px;
  width: 0;
  z-index: 100;
  background: var(--accent);
  opacity: 0;
  pointer-events: none;
}
body.nav-busy .nav-progress {
  opacity: 1;
  width: 70%;
  transition: width 1.4s var(--ease), opacity 0.2s var(--ease);
}
.nav-progress.done {
  width: 100%;
  opacity: 0;
  transition: width 0.2s var(--ease), opacity 0.35s var(--ease) 0.1s;
}

@media (prefers-reduced-motion: reduce) {
  main { transition: none; }
  body.nav-out main, body.nav-in main { opacity: 1; transform: none; }
}

/* --------------------------------------------------------- enhanced hovers */
/* The sliding indicator is the only underline in the nav now — a per-link
   hover rule would fight it for the same 1px. */

.pill, .chip {
  transition: transform 0.25s var(--ease), border-color 0.25s var(--ease), color 0.25s var(--ease), background 0.25s var(--ease);
}
.pill:hover, .chip:hover {
  transform: translateY(-1px);
}
.pill.link:hover {
  border-color: var(--fg);
  color: var(--fg);
}

.work {
  transition: background 0.3s var(--ease), transform 0.3s var(--ease);
}
.work:hover {
  background: var(--bg-2);
  transform: translateY(-2px);
}
.work:hover .work-thumb img {
  transform: scale(1.04);
}

.links a {
  transition: padding-left 0.3s var(--ease), background 0.3s var(--ease);
}
.links a:hover {
  padding-left: 12px;
  background: var(--bg-2);
}

/* player modal animation */
.player {
  opacity: 0;
  transition: opacity 0.25s var(--ease);
}
.player[open] {
  opacity: 1;
}
.player-inner {
  transform: scale(0.96) translateY(8px);
  opacity: 0;
  transition: transform 0.3s var(--ease), opacity 0.3s var(--ease);
}
.player[open] .player-inner {
  transform: none;
  opacity: 1;
}

/* --------------------------------------------------------- custom cursor */
#cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 14px;
  height: 14px;
  margin-left: -7px;
  margin-top: -7px;
  border-radius: 50%;
  background: #fff;
  mix-blend-mode: difference;
  pointer-events: none;
  z-index: 9999;
  transition: width 0.25s var(--ease), height 0.25s var(--ease), margin 0.25s var(--ease);
}
#cursor.is-hover {
  width: 28px;
  height: 28px;
  margin-left: -14px;
  margin-top: -14px;
}
@media (hover: none), (pointer: coarse) {
  #cursor { display: none; }
}

/* ---------------------------------------------------------------- reveal */
[data-reveal] {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}
[data-reveal].in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; transition: none; }
  * { animation: none !important; }
}

/* Locale-specific system fonts avoid rendering Japanese/Korean with a
   Simplified-Chinese fallback when the optional web font is unavailable. */
html[lang="ja"] body {
  font-family: "Noto Sans JP", "Yu Gothic", "Hiragino Kaku Gothic ProN", sans-serif;
}
html[lang="ko"] body {
  font-family: "Noto Sans KR", "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
}
@media (max-width: 620px) {
  .lang { gap: 3px; font-size: 10px; }
}
