/* Self-hosted official Pretendard v1.3.9 dynamic Unicode subsets.
   All modern Hangul remains available; browsers request only needed chunks.
   Source, license, checksums and coverage check: fonts/README.md. */
@import url("fonts/pretendardvariable-dynamic-subset.css");

@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/jetbrains-mono-subset.woff2") format("woff2");
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

/* ===============================================================
   ICaR Lab — design system
   Dark ink by default, warm paper in light mode.
   Everything is driven by the custom properties in :root.
   =============================================================== */

/* ---------- tokens ---------- */

:root {
  --bg:        #ffffff;
  --bg-soft:   #f5f5f3;
  --panel:     rgba(10, 10, 10, 0.028);
  --panel-2:   rgba(10, 10, 10, 0.055);
  --line:      rgba(10, 10, 10, 0.17);
  --line-soft: rgba(10, 10, 10, 0.09);

  --text:   #0a0a0a;
  --dim:    #55555c;
  --faint:  #71717a;

  /* black IS the accent -- every --accent below resolves to ink,
     and flips to paper inside .invert */
  --accent:   var(--text);
  --accent-2: #6f6f78;
  --accent-3: var(--text);
  --grad:     var(--text);

  --shadow: 0 24px 60px -32px rgba(0, 0, 0, 0.3);
  --glow:   0 0 0 1px rgba(10, 10, 10, 0.14);

  /* one family for text and headings, Latin and Hangul alike */
  --display: "Pretendard Variable", Pretendard, "Inter", -apple-system,
             BlinkMacSystemFont, "Segoe UI", sans-serif;
  --sans:  "Pretendard Variable", Pretendard, "Inter", -apple-system, BlinkMacSystemFont,
           "Segoe UI", "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  --mono:  "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --pad: clamp(1.25rem, 5vw, 3rem);
  --maxw: 1140px;
  --r: 16px;
}

/* Black bands -- the nav, the hero and the footer. Same components,
   same rules; only the tokens flip. */
.invert {
  --bg:        #0a0a0a;
  --bg-soft:   #141416;
  --panel:     rgba(255, 255, 255, 0.055);
  --panel-2:   rgba(255, 255, 255, 0.10);
  --line:      rgba(255, 255, 255, 0.19);
  --line-soft: rgba(255, 255, 255, 0.10);

  --text:   #fafafa;
  --dim:    #a7a7ae;
  --faint:  #74747c;

  --accent:   var(--text);
  --accent-2: #9a9aa2;
  --accent-3: var(--text);
  --grad:     var(--text);

  --shadow: 0 24px 60px -24px rgba(0, 0, 0, 0.85);
  --glow:   0 0 0 1px rgba(255, 255, 255, 0.16);

  background: var(--bg);
  color: var(--text);
}

/* ---------- reset ---------- */

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 16.5px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul { margin: 0; padding: 0; list-style: none; }

::selection { background: var(--text); color: var(--bg); }

/* screen-reader-only: gives an outline a heading the design does not show */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- layout ---------- */

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

section { position: relative; }

.band { padding-block: clamp(4rem, 9vw, 7.5rem); }
.band--tight { padding-block: clamp(2.75rem, 6vw, 4.5rem); }
.band--line { border-top: 1px solid var(--line-soft); }

/* ---------- type ---------- */

h1, h2, h3, h4 { margin: 0; font-weight: 400; line-height: 1.12; letter-spacing: -0.015em; }

/* When a heading does wrap, split it evenly rather than leaving one word
   stranded on the last line. Ignored by browsers that lack it. */
.display, .h2, .card__title, .album__title { text-wrap: balance; }

.display {
  font-family: var(--display);
  font-size: clamp(2.3rem, 4.5vw, 3.9rem);
  font-weight: 750;
  line-height: 1.08;
  letter-spacing: -0.042em;
}

.h2 {
  font-family: var(--display);
  font-size: clamp(1.8rem, 3.7vw, 2.7rem);
  font-weight: 700;
  line-height: 1.18;
  letter-spacing: -0.035em;
}

.h3 {
  font-family: var(--sans);
  font-size: 1.12rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.4;
}

.eyebrow {
  font-family: var(--mono);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--accent);
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1.25rem;
}
.eyebrow::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--line), transparent);
}

.lede {
  font-size: clamp(1.02rem, 1.6vw, 1.2rem);
  color: var(--dim);
  max-width: 62ch;
  line-height: 1.75;
}

.muted { color: var(--dim); }
.faint { color: var(--faint); }

.grad-text {
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ---------- keyboard ---------- */

/* Buttons and chips carry custom backgrounds, so the browser's default ring
   can vanish against them. One visible treatment everywhere. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 3px;
}
.invert :focus-visible { outline-color: var(--text); }

/* Lets a keyboard user reach the content without tabbing the whole menu.
   It drops over the sticky black nav band, so it takes the inverted palette:
   a light pill on the dark bar, with a light ring to match. */
.skip {
  position: absolute;
  left: 1rem;
  top: -4rem;
  z-index: 100;
  padding: 0.7rem 1.15rem;
  background: var(--bg);
  color: var(--text);
  border-radius: 0 0 10px 10px;
  font-size: 0.9rem;
  font-weight: 600;
  transition: top 0.18s;
}
.skip:focus { top: 0; }
.skip:focus-visible { outline-color: var(--bg); outline-offset: 2px; }

/* The skip target only takes focus programmatically; a ring around the whole
   page body would be noise, and the scroll jump is the feedback. */
main:focus { outline: none; }

/* ---------- language toggle ---------- */

/* Sits in the black nav band, so it reads on the inverted palette. */
.lang {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-left: 1.25rem;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: 999px;
}
.lang button {
  border: 0;
  background: none;
  color: var(--dim);
  font: inherit;
  font-size: 0.78rem;
  line-height: 1;
  letter-spacing: 0.02em;
  padding: 0.42rem 0.72rem;
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.16s, background 0.16s;
}
.lang button:hover { color: var(--text); }
.lang button.on {
  background: var(--text);
  color: var(--bg);
}

@media (max-width: 860px) {
  .lang { margin-left: auto; margin-right: 0.5rem; }
}

/* At phone widths the bar holds brand + toggle + menu, so the toggle
   gives up its padding before the brand gives up its second line. */
@media (max-width: 460px) {
  .lang { margin-right: 0.35rem; padding: 2px; }
  .lang button { padding: 0.36rem 0.5rem; font-size: 0.72rem; }
}

/* ---------- news ---------- */

/* A short-lived band under the hero. renderNews() sets [hidden] when
   nothing is inside the window, and the rule below has to restate
   display:none because .news sets its own display. */
.news {
  background: var(--bg-soft);
  border-bottom: 1px solid var(--line-soft);
}
.news[hidden] { display: none; }

.news__inner {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(1.1rem, 4vw, 3rem);
  align-items: start;
  padding-block: clamp(1.4rem, 3vw, 2.1rem);
}

.news__label {
  margin: 0;
  padding-top: 0.35rem;
  white-space: nowrap;
}
/* the shared eyebrow trails a rule; here the grid already separates it */
.news__label::after { content: none; }

.news__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.65rem;
}

.news__item {
  display: grid;
  grid-template-columns: 4.6rem 1fr;
  gap: 1rem;
  align-items: baseline;
}

.news__date {
  font-family: var(--mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
  white-space: nowrap;
}

.news__text {
  font-size: 1.02rem;
  line-height: 1.5;
  text-wrap: pretty;
}

.news__link {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-underline-offset: 0.22em;
  transition: text-decoration-color 0.16s;
}
.news__link:hover { text-decoration-color: currentColor; }

@media (max-width: 640px) {
  .news__inner { grid-template-columns: 1fr; gap: 0.85rem; }
  .news__label { padding-top: 0; }
  .news__item { grid-template-columns: 1fr; gap: 0.15rem; }
}

/* ---------- nav ---------- */

.nav {
  position: sticky;
  top: 0;
  z-index: 60;
  backdrop-filter: blur(16px) saturate(150%);
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s, background 0.3s;
}
.nav.is-stuck { border-bottom-color: var(--line-soft); box-shadow: 0 10px 30px -20px rgba(0,0,0,.5); }

.nav__inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 68px;
}

.brand { display: flex; align-items: center; gap: 0.7rem; margin-right: auto; }

.brand__mark {
  width: 34px; height: 34px;
  flex: none;
  display: grid; place-items: center;
}
.brand__mark img { width: 100%; height: 100%; object-fit: contain; }

.brand__text { display: flex; flex-direction: column; line-height: 1.15; }
.brand__name { font-weight: 650; font-size: 0.95rem; letter-spacing: -0.01em; }
.brand__sub  { font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--faint); }

.nav__links { display: flex; align-items: center; gap: 0.15rem; margin-right: 0.5rem; }

.nav__links a {
  position: relative;
  padding: 0.5rem 0.7rem;
  border-radius: 9px;
  font-size: 0.86rem;
  font-weight: 500;
  color: var(--dim);
  transition: color 0.2s, background 0.2s;
}
.nav__links a:hover { color: var(--text); background: var(--panel); }
.nav__links a[aria-current="page"] { color: var(--text); }
.nav__links a[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 0.7rem; right: 0.7rem; bottom: 0.15rem;
  height: 2px;
  border-radius: 2px;
  background: var(--grad);
}

.icon-btn {
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  color: var(--dim);
  cursor: pointer;
  transition: color 0.2s, border-color 0.2s, transform 0.2s;
}
.icon-btn:hover { color: var(--text); border-color: var(--accent); transform: translateY(-1px); }
.icon-btn svg { width: 17px; height: 17px; }

.nav__toggle { display: none; }

/* mobile nav */
@media (max-width: 920px) {
  .nav__toggle { display: grid; }
  .nav__links {
    position: fixed;
    inset: 68px 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0.5rem var(--pad) 1.25rem;
    background: var(--bg);
    border-bottom: 1px solid var(--line);
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.22s, transform 0.22s;
  }
  .nav__links[inert] { visibility: hidden; }
  .nav__links.is-open { opacity: 1; transform: none; pointer-events: auto; }
  .nav__links a { padding: 0.8rem 0.25rem; font-size: 1rem; border-radius: 0; border-bottom: 1px solid var(--line-soft); }
  .nav__links a[aria-current="page"]::after { left: 0.25rem; right: auto; width: 22px; bottom: 0.35rem; }
}

/* ---------- hero ---------- */

.hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  /* a faint measuring grid over a soft pool of light behind the figure --
     the edges stay near-black so the hand-off to the white page below is clean */
  background-image:
    radial-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px),
    radial-gradient(1000px 680px at 70% 44%, #1a1a20 0%, #0a0a0a 62%);
  background-size: 58px 58px, cover;
}

.hero__inner {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.18fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: center;
  padding-block: clamp(3.5rem, 7vw, 6rem) clamp(3rem, 6vw, 5rem);
  min-height: clamp(520px, 76vh, 760px);
}

.hero__title { max-width: 13ch; }
.hero__title em { font-style: italic; }
.hero__lede { margin-top: 1.6rem; max-width: 40ch; }

.hero__art { margin: 0; display: flex; flex-direction: column; gap: 0.9rem; }
.hero__art canvas {
  display: block;
  width: 100%;
  aspect-ratio: 640 / 460;
  max-height: 540px;
}
.hero__art figcaption {
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
  text-align: center;
}

@media (max-width: 940px) {
  .hero__inner { grid-template-columns: 1fr; gap: 2.5rem; }
  .hero__title { max-width: 18ch; }
}

.hero__meta {
  margin-top: 2.25rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.6rem;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--faint);
}
.hero__meta span { display: flex; align-items: center; gap: 0.55rem; }
.hero__meta span::before {
  content: "";
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--accent);
}

.cta-row { margin-top: 2.5rem; display: flex; flex-wrap: wrap; gap: 0.75rem; }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.72rem 1.35rem;
  border-radius: 999px;
  font-size: 0.9rem;
  font-weight: 550;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  cursor: pointer;
  transition: transform 0.2s, border-color 0.2s, background 0.2s, opacity 0.2s;
}
.btn:hover { transform: translateY(-2px); border-color: var(--text); background: var(--panel-2); }
.btn svg { width: 15px; height: 15px; transition: transform 0.2s; }
.btn:hover svg { transform: translateX(3px); }

.btn--primary {
  background: var(--text);
  border-color: var(--text);
  color: var(--bg);
  font-weight: 620;
}
.btn--primary:hover { background: var(--text); border-color: var(--text); opacity: 0.86; }

/* ---------- stats ---------- */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
  overflow: hidden;
}
.stat { background: var(--bg); padding: 1.6rem 1.4rem; }
.stat__num {
  font-family: var(--display);
  font-size: clamp(2rem, 3.7vw, 2.7rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.045em;
}
.stat__label {
  margin-top: 0.55rem;
  font-family: var(--mono);
  font-size: 0.63rem;
  letter-spacing: 0.19em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ---------- generic grid + cards ---------- */

.grid { display: grid; gap: 1.1rem; }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 330px), 1fr)); }

.card {
  position: relative;
  padding: 1.75rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
  background: var(--panel);
  overflow: hidden;
  transition: transform 0.28s cubic-bezier(0.2, 0.7, 0.3, 1), border-color 0.28s, background 0.28s;
}
.card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: var(--grad);
  opacity: 0;
  transition: opacity 0.28s;
}
.card:hover { transform: translateY(-4px); border-color: var(--line); background: var(--panel-2); }
.card:hover::before { opacity: 1; }

.card__index {
  font-family: var(--mono);
  font-size: 0.65rem;
  letter-spacing: 0.18em;
  color: var(--faint);
  margin-bottom: 1.15rem;
}

.card__title {
  font-family: var(--display);
  font-size: 1.3rem;
  font-weight: 700;
  letter-spacing: -0.028em;
  margin-bottom: 0.7rem;
}

.card p { margin: 0; color: var(--dim); font-size: 0.94rem; line-height: 1.7; }

.tags { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 1.25rem; }
.tag {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.05em;
  padding: 0.28rem 0.62rem;
  border-radius: 999px;
  border: 1px solid var(--line-soft);
  color: var(--dim);
  background: var(--panel);
  max-width: 100%;
  white-space: normal;
  overflow-wrap: anywhere;
}

/* ---------- people ---------- */

.people { display: grid; gap: 1.1rem; grid-template-columns: repeat(auto-fit, minmax(258px, 1fr)); }

.person {
  display: flex;
  gap: 1.1rem;
  align-items: flex-start;
  padding: 1.35rem;
  border: 1px solid var(--line-soft);
  border-radius: 14px;
  background: var(--panel);
  transition: transform 0.25s, border-color 0.25s, background 0.25s;
}
.person:hover { transform: translateY(-3px); border-color: var(--line); background: var(--panel-2); }

.avatar {
  flex: none;
  width: 54px; height: 54px;
  border-radius: 14px;
  display: grid; place-items: center;
  font-family: var(--mono);
  font-size: 0.92rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--bg);
  background: var(--text);
  overflow: hidden;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }

.person__name { font-weight: 620; font-size: 1rem; letter-spacing: -0.01em; }
/* on its own line, and never split mid-name, so every card has the same
   two-line head whatever the column width */
.person__ko {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.85rem;
  color: var(--faint);
  font-weight: 400;
  white-space: nowrap;
}
.person__role {
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--accent);
  margin-top: 0.3rem;
}
.person__meta { font-size: 0.82rem; color: var(--dim); margin-top: 0.5rem; word-break: break-word; }

.person__links { display: flex; flex-wrap: wrap; gap: 0.85rem; margin-top: 0.55rem; }
.person__links a {
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim);
  border-bottom: 1px solid var(--line-soft);
  padding-bottom: 1px;
  transition: color 0.2s, border-color 0.2s;
}
.person__links a:hover { color: var(--text); border-color: var(--text); }

.badge {
  display: inline-block;
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0.16rem 0.5rem;
  border-radius: 5px;
  border: 1px solid var(--line);
  color: var(--dim);
}

/* The armband: one row held open on every card, filled only where there is a
   role to show, so the lines below it start at the same height everywhere. */
.badge-slot {
  display: flex;
  align-items: center;
  min-height: 1.5rem;
  margin-top: 0.5rem;
}

/* ---------- advisor block ---------- */

.advisor { display: grid; grid-template-columns: minmax(0, 320px) minmax(0, 1fr); gap: clamp(2rem, 5vw, 4rem); align-items: start; }
@media (max-width: 820px) {
  .advisor { grid-template-columns: 1fr; }
  /* stacked, the portrait would otherwise stretch to the full page width */
  .portrait { max-width: 280px; }
  .contact-list { max-width: 360px; }
}

.portrait {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: 20px;
  border: 1px solid var(--line);
  background: var(--bg-soft);
  display: grid;
  place-items: center;
  overflow: hidden;
  box-shadow: var(--shadow);
}
.portrait img { width: 100%; height: 100%; object-fit: cover; }
.portrait__initials {
  font-family: var(--display);
  font-size: 3.6rem;
  font-weight: 700;
  letter-spacing: -0.045em;
  color: var(--text);
  opacity: 0.9;
}

.contact-list { margin-top: 1.5rem; display: grid; gap: 0.7rem; }
.contact-row { display: flex; gap: 0.85rem; align-items: flex-start; font-size: 0.88rem; }
.contact-row dt {
  flex: none;
  width: 62px;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--faint);
  padding-top: 0.22rem;
}
.contact-row dd { margin: 0; color: var(--dim); }
.contact-row a { color: var(--text); border-bottom: 1px solid var(--line); transition: border-color 0.2s, color 0.2s; }
.contact-row a:hover { color: var(--accent); border-color: var(--accent); }

/* ---------- timeline ---------- */

.timeline { position: relative; padding-left: 1.7rem; }
.timeline::before {
  content: "";
  position: absolute;
  left: 4px; top: 8px; bottom: 8px;
  width: 1px;
  background: linear-gradient(180deg, var(--accent), var(--line-soft) 70%, transparent);
}

.tl-item { position: relative; padding-bottom: 1.7rem; }
.tl-item:last-child { padding-bottom: 0; }
.tl-item::before {
  content: "";
  position: absolute;
  left: -1.7rem; top: 0.5rem;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--bg);
  border: 1.5px solid var(--accent);
}
.tl-item--past::before { border-color: var(--line); }

.tl-period {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--faint);
}
.tl-role { font-weight: 600; font-size: 1rem; margin-top: 0.18rem; letter-spacing: -0.01em; }
.tl-org { color: var(--text); font-size: 0.9rem; font-weight: 550; }
.tl-note { color: var(--dim); font-size: 0.86rem; margin-top: 0.3rem; line-height: 1.6; }

/* ---------- publications ---------- */

.filters { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 2.5rem; }
.chip {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  padding: 0.45rem 0.95rem;
  border-radius: 999px;
  border: 1px solid var(--line-soft);
  background: transparent;
  color: var(--dim);
  cursor: pointer;
  transition: color 0.2s, border-color 0.2s, background 0.2s;
}
.chip:hover { color: var(--text); border-color: var(--line); }
.chip.is-active { color: var(--bg); background: var(--text); border-color: var(--text); font-weight: 600; }

.year-group { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 1.5rem; padding-block: 1.9rem; border-top: 1px solid var(--line-soft); }
.year-group:first-of-type { border-top: none; padding-top: 0; }
@media (max-width: 700px) { .year-group { grid-template-columns: 1fr; gap: 0.9rem; } }

.year-label {
  margin: 0;
  font-family: var(--display);
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--faint);
  position: sticky;
  top: 96px;
  height: max-content;
}
@media (max-width: 700px) { .year-label { position: static; font-size: 1.5rem; color: var(--accent); } }

.pub-list { list-style: none; margin: 0; padding: 0; }
.pub { padding: 0.95rem 0; border-bottom: 1px solid var(--line-soft); }
.pub:last-child { border-bottom: none; }
.pub__title { font-size: 1rem; font-weight: 550; line-height: 1.5; letter-spacing: -0.01em; }
.pub__authors { font-size: 0.86rem; color: var(--dim); margin-top: 0.35rem; }
.pub__authors b { color: var(--text); font-weight: 640; }
.pub__venue { font-size: 0.84rem; margin-top: 0.25rem; color: var(--faint); }
.pub__venue em { font-style: italic; color: var(--dim); }

/* ---------- projects ---------- */

.project {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 1.25rem;
  align-items: start;
  padding: 1.6rem 0;
  border-bottom: 1px solid var(--line-soft);
}
@media (max-width: 720px) { .project { grid-template-columns: 1fr; } }

.project__title { font-size: 1.02rem; font-weight: 580; line-height: 1.5; letter-spacing: -0.01em; }
.project__meta { display: flex; flex-wrap: wrap; gap: 0.4rem 1.1rem; margin-top: 0.75rem; font-size: 0.82rem; color: var(--dim); }

.pill {
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  white-space: nowrap;
  border: 1px solid var(--line-soft);
  color: var(--faint);
  height: max-content;
}
.pill--live { color: var(--bg); background: var(--text); border-color: var(--text); }

/* ---------- courses ---------- */

.course {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--line-soft);
}
.course:last-child { border-bottom: none; }
.course__name { font-weight: 540; font-size: 0.97rem; }
.course__ko { color: var(--faint); font-size: 0.85rem; margin-left: 0.45rem; word-break: keep-all; }
.course__years { margin-left: auto; font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.1em; color: var(--faint); white-space: nowrap; }

/* ---------- page header (inner pages) ---------- */

.pagehead {
  position: relative;
  padding-block: clamp(3.5rem, 8vw, 6rem) clamp(2rem, 4vw, 3rem);
  overflow: hidden;
}
.pagehead::before {
  content: "";
  position: absolute;
  inset: -40% -10% auto -10%;
  height: 130%;
  z-index: -1;
  background: none;
  pointer-events: none;
}

/* ---------- footer ---------- */

.footer { padding-block: 3.5rem 2.5rem; margin-top: 0; }
.footer__grid { display: grid; grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, 1fr)); gap: 2.5rem; }
@media (max-width: 760px) { .footer__grid { grid-template-columns: 1fr; gap: 2rem; } }

.footer h2 {
  font-family: var(--mono);
  font-size: 0.63rem;
  letter-spacing: 0.19em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 0.9rem;
}
.footer li { margin-bottom: 0.45rem; font-size: 0.88rem; color: var(--dim); }
.footer li a:hover { color: var(--accent); }
.footer__bottom {
  margin-top: 2.75rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line-soft);
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.5rem;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ---------- reveal on scroll ---------- */

[data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.7s cubic-bezier(0.2, 0.7, 0.3, 1), transform 0.7s cubic-bezier(0.2, 0.7, 0.3, 1);
  transition-delay: var(--d, 0ms);
}
[data-reveal].is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
  [data-reveal] { opacity: 1; transform: none; }
}

/* keep the sticky bar's slot reserved before the nav script runs */
#nav { display: block; min-height: 68px; background: #0a0a0a; }

/* a page header already carries its own bottom padding */
.pagehead + .band--tight { padding-top: 0; }

/* the hairline rule reads as a strike-through once the label wraps */
@media (max-width: 620px) {
  .eyebrow { flex-wrap: wrap; }
  .eyebrow::after { display: none; }
}

/* ---------- card media ---------- */

.card--media { padding-top: 0; }
.card__media {
  position: relative;
  margin: 0 -1.75rem 1.6rem;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-bottom: 1px solid var(--line-soft);
  background: var(--bg-soft);
}
/* on hover a black rule wipes in along the foot of the image, closing the
   frame against the hairline that appears at the top of the card */
.card__media::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 4px;
  background: var(--text);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.45s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.card:hover .card__media::after { transform: scaleX(1); }
.card__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.7s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.card:hover .card__media img { transform: scale(1.04); }

/* the mobile menu drops out of a black bar, so it has to be black too */
@media (max-width: 920px) { .nav__links { background: #0a0a0a; } }

/* ---------- DOI links on publications ---------- */

.pub__link {
  display: inline;
  background-image: linear-gradient(var(--line), var(--line));
  background-size: 100% 1px;
  background-repeat: no-repeat;
  background-position: 0 100%;
  transition: background-size 0.25s, color 0.2s;
}
.pub__link:hover {
  background-image: linear-gradient(var(--text), var(--text));
}

/* ---------- profile banner ---------- */

.banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
  padding: 1.5rem 1.75rem;
  border-radius: var(--r);
  margin-bottom: 2rem;
}
.banner__t { font-weight: 650; font-size: 1.02rem; letter-spacing: -0.02em; }
.banner__s {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--faint);
  margin-top: 0.3rem;
}
.banner__a { display: flex; gap: 0.6rem; flex-wrap: wrap; }

/* the secondary button sits on ink, so it needs a brighter edge than
   the default panel treatment gives it */
.btn--ghost {
  background: transparent;
  border-color: color-mix(in srgb, var(--text) 45%, transparent);
}
.btn--ghost:hover { background: var(--panel-2); border-color: var(--text); }

.pub-note {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
  margin: -0.5rem 0 2rem;
}

.pub__doi {
  font-family: var(--mono);
  font-size: 0.76em;
  letter-spacing: 0.01em;
  color: var(--faint);
  border-bottom: 1px solid transparent;
  transition: color 0.2s, border-color 0.2s;
  word-break: break-all;
}
.pub__doi:hover { color: var(--text); border-bottom-color: var(--line); }

/* Korean still appears in names, project titles and the footer address,
   and Pretendard covers it, so no separate rules are needed. */

/* ---------- research areas ---------- */

.grid--areas { grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr)); }

/* the hero headline is the lab's name now, not a short slogan */
.hero__title { font-size: clamp(1.95rem, 3.3vw, 2.9rem); max-width: 17ch; }

/* ---------- contact page ---------- */

.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
@media (max-width: 860px) { .contact-grid { grid-template-columns: 1fr; } }

.map { margin: 0; }
.map iframe {
  width: 100%;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--line);
  border-radius: var(--r);
  display: block;
}
@media (max-width: 860px) { .map iframe { aspect-ratio: 3 / 2; } }

.contact-page .contact-row dt { width: 74px; }

/* ---------- gallery ---------- */

.album { margin-bottom: clamp(3rem, 6vw, 4.5rem); }
.album:last-child { margin-bottom: 0; }

.album__head { margin-bottom: 1.5rem; }
.album__title {
  font-family: var(--display);
  font-size: clamp(1.35rem, 2.4vw, 1.8rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.2;
}
.album__ko { color: var(--faint); font-size: 0.9rem; margin-top: 0.3rem; }
.album__meta {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--faint);
  margin-top: 0.55rem;
}

/* auto-fit rather than auto-fill: a single photo fills the row instead of
   sitting in a narrow cell with dead space beside it */
.album__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 1rem;
}
/* cap how wide one or two photos can stretch, so they stay photo-sized */
.album__grid:has(.shot:only-child) { grid-template-columns: minmax(0, 560px); }

.shot {
  position: relative;
  padding: 0;
  border: 0;
  background: var(--bg-soft);
  border-radius: var(--r);
  overflow: hidden;
  aspect-ratio: 4 / 3;
  cursor: zoom-in;
  display: block;
}
.shot img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.7s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.shot:hover img { transform: scale(1.04); }
/* the same rule that closes the research cards */
.shot::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 4px;
  background: var(--text);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.45s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.shot:hover::after, .shot:focus-visible::after { transform: scaleX(1); }

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

.lightbox {
  border: 0;
  padding: 0;
  background: transparent;
  max-width: min(94vw, 1200px);
  max-height: 92vh;
  overflow: visible;
}
.lightbox::backdrop { background: rgba(8, 8, 8, 0.9); }
.lightbox figure { margin: 0; }
.lightbox img {
  display: block;
  max-width: 100%;
  max-height: 82vh;
  width: auto;
  border-radius: var(--r);
}
.lightbox figcaption {
  margin-top: 0.9rem;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.65);
  text-align: center;
}
.lightbox__x {
  position: absolute;
  top: -2.4rem; right: -0.25rem;
  width: 34px; height: 34px;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 50%;
  background: transparent;
  color: #fff;
  font-size: 1.15rem;
  line-height: 1;
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s;
}
.lightbox__x:hover { background: rgba(255, 255, 255, 0.14); border-color: #fff; }

/* ---------- print ----------
   On paper the black bands are just ink, the sticky bar repeats on every
   sheet, and a link's destination is invisible. This makes the publication
   list and the CV printable. */

@media print {
  :root {
    --bg: #fff; --bg-soft: #fff;
    --text: #000; --dim: #333; --faint: #555;
    --line: #bbb; --line-soft: #ddd;
    --panel: transparent; --panel-2: transparent;
    --shadow: none; --glow: none;
  }
  /* the inverted bands print as plain paper */
  .invert { background: #fff !important; color: #000 !important;
            --bg: #fff; --text: #000; --dim: #333; --faint: #555;
            --line: #bbb; --line-soft: #ddd; --panel: transparent; }

  .nav, .hero__art, .lightbox, .filters, .cta-row, .icon-btn,
  .map, .banner, .card__media { display: none !important; }

  .hero { min-height: auto; background: none !important; }
  .hero__inner { display: block; padding-block: 0 1.5rem; }

  body { font-size: 11pt; }
  .wrap { max-width: none; padding-inline: 0; }
  .band, .band--tight, .pagehead { padding-block: 0 0.8rem; }
  .card { border: 1px solid #ddd; break-inside: avoid; }

  /* keep entries whole across page breaks */
  .pub, .project, .person, .tl-item, .course, .album { break-inside: avoid; }
  .year-group { break-inside: auto; }
  h1, h2, h3 { break-after: avoid; }

  /* a printed link is useless without its address */
  .pub__link::after { content: " (" attr(href) ")"; font-size: 8.5pt; color: #555;
                      word-break: break-all; }
  .pub__doi, .person__links a, .contact-row a { text-decoration: underline; }

  .footer { border-top: 1px solid #bbb; padding-block: 1rem 0; }
  .footer__grid > :nth-child(2) { display: none; }   /* the nav list */

  [data-reveal] { opacity: 1 !important; transform: none !important; }
}

/* ---------- interactive loop (research page) ---------- */

/* One tab per loop. The chips are the publication filters' -- same job, same
   shape -- with a tablist's keyboard behaviour added in assets/sim.js. */
.simtabs { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 2.25rem; }
.simtabs .chip:focus-visible { outline: 2px solid var(--text); outline-offset: 3px; }
.sim__note { margin-top: 1.5rem; max-width: 60ch; }
.simpanel .sim { margin-top: 2.5rem; }
/* a browser with canvas turned off keeps the prose and loses the empty box */
.sim--noctx .sim__fig, .sim--noctx .sim__panel { display: none; }

/* Wide: the figure on the left, the controls and then the footnote down the
   right. The two columns match heights and the figure centres inside
   whichever ends up taller, so no column trails a block of empty page.

   Narrow: the controls come first. The figure is three panels tall on a
   phone, and with the controls under it there was no way to move a slider
   and see what it did -- the numbers alone are nearly a screen away. The
   footnote is long and belongs at the end either way. */
.sim {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 260px);
  grid-template-rows: auto 1fr;
  grid-template-areas: "fig panel" "fig foot";
  column-gap: clamp(1.5rem, 3vw, 2.5rem);
  row-gap: 1.05rem;
  align-items: stretch;
}
.sim__fig { grid-area: fig; }
.sim__panel { grid-area: panel; }
.sim__foot { grid-area: foot; }
@media (max-width: 900px) {
  .sim {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    grid-template-areas: "panel" "fig" "foot";
    row-gap: 1.6rem;
  }
  /* every row saved here is a row of the figure that arrives on the same
     screen as the slider being dragged */
  .sim__panel { gap: 0.8rem; }
  .sim__out { padding-top: 0.7rem; }
}

.sim__fig {
  margin: 0;
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
  background: var(--bg-soft);
  padding: 0.9rem;
  display: grid;
  align-content: center;
}
.sim__fig canvas { display: block; width: 100%; aspect-ratio: 78 / 62; }
/* stacked, the three panels read better one above the other */
@media (max-width: 620px) { .sim__fig canvas { aspect-ratio: 38 / 101; } }

.sim__panel { display: flex; flex-direction: column; gap: 1.05rem; }

.sim__ctrl { display: grid; grid-template-columns: 1fr auto; gap: 0.35rem 0.6rem; align-items: baseline; }
.sim__ctrl label { font-size: 0.82rem; color: var(--dim); }
.sim__ctrl label i { font-family: Georgia, "Times New Roman", serif; }
.sim__ctrl output {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  color: var(--text);
  white-space: nowrap;
}
.sim__ctrl input[type="range"] {
  grid-column: 1 / -1;
  width: 100%;
  margin: 0;
  accent-color: var(--text);
  cursor: ew-resize;
}
.sim__ctrl input[type="range"]:focus-visible { outline: 2px solid var(--text); outline-offset: 3px; }

.sim__out {
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--line-soft);
}
.sim__rho { display: flex; flex-direction: column; gap: 0.2rem; }
.sim__rho-label {
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--faint);
}
.sim__rho-val { font-family: var(--mono); font-size: 1.5rem; letter-spacing: -0.02em; color: var(--text); }
.sim__verdict {
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--dim);
  padding: 0.18rem 0.5rem; border: 1px solid var(--line); border-radius: 5px;
}
/* an unstable loop is stated in ink, not colour, like everything else here */
.sim__verdict.is-bad { color: var(--bg); background: var(--text); border-color: var(--text); }

.sim__foot { font-size: 0.78rem; color: var(--faint); margin: 0; }

/* Named for what it will do next, so the width has to hold the longest of
   the three words without the row shifting under a thumb. */
.sim__play { align-self: flex-start; min-width: 7.5rem; text-align: center; }

/* a control that picks between named alternatives rather than sliding */
.sim__ctrl--pick { gap: 0.5rem; }
.sim__ctrl-name { font-size: 0.82rem; color: var(--dim); grid-column: 1 / -1; }
.sim__pick { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 0.4rem; }
.sim__pick .chip { padding: 0.4rem 0.8rem; }
.sim__pick .chip:focus-visible { outline: 2px solid var(--text); outline-offset: 3px; }
/* A control that belongs to another mode is gone, not dimmed. The row sets
   its own display, which beats the [hidden] rule the browser supplies, so it
   has to be said here. */
.sim__ctrl[hidden] { display: none; }
/* a slider the current mode cannot use: still readable, plainly not in play */
.sim__ctrl.is-off { opacity: 0.42; }
.sim__ctrl.is-off input[type="range"] { cursor: not-allowed; }

/* A button laid over the figure opens the viewer. Covering the media rather
   than replacing it leaves the card's own layout, its bleed and its hover rule
   exactly as they were -- a real button sizes itself shrink-to-fit even as a
   block, which would have undone the bleed. */
.card__zoom {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}
.card__zoom:focus-visible { outline: 2px solid var(--text); outline-offset: -4px; }
.lightbox img[src$=".svg"] { width: min(94vw, 1100px); height: auto; }

.sim__out--tight { border-top: 0; padding-top: 0; }
.sim__rho-val--sm { font-size: 1.15rem; }

.sim__out--tight { border-top: 0; padding-top: 0; }
.sim__rho-val--sm { font-size: 1.15rem; }

/* the loop the sliders are tuning, under the live panels */
.sim__loop {
  display: block;
  width: 100%;
  margin: 1.1rem 0 0.2rem;
  color: var(--text);
}
.sim__loop .sl-wire { fill: none; stroke: currentColor; stroke-width: 2 }
.sim__loop .sl-thin { fill: none; stroke: var(--line); stroke-width: 1.4 }
.sim__loop .sl-box  { fill: var(--bg); stroke: currentColor; stroke-width: 1.8 }
.sim__loop text     { text-anchor: middle; fill: currentColor }
.sim__loop .sl-name { font-family: var(--sans); font-size: 14px; font-weight: 500 }
.sim__loop .sl-sig  { font-family: var(--sans); font-size: 13px; fill: var(--dim); text-anchor: start }
.sim__loop .sl-tag  { font-family: var(--mono); font-size: 10px; letter-spacing: .14em;
                      text-transform: uppercase; fill: var(--faint) }
.sim__loop .sl-gain { font-family: Georgia, "Times New Roman", serif; font-style: italic; font-size: 17px }
.sim__loop .sl-sub  { font-size: 11px }
.sim__loop .sl-it   { font-family: Georgia, "Times New Roman", serif; font-style: italic }
.sim__loop .sl-eq   { font-family: Georgia, "Times New Roman", serif; font-style: italic; font-size: 16px }
.sim__loop .sl-mid  { text-anchor: middle; font-family: Georgia, "Times New Roman", serif; font-style: italic; font-size: 15px }
.sim__loop .sl-sign { fill: none; stroke: var(--dim); stroke-width: 1.8; stroke-linecap: round }
