/* =========================================================================
   Weiren Feng — portfolio
   Ink & Aurora: deep cool ink, one teal accent, generous whitespace.
   Dark is the default; [data-theme="light"] overrides the tokens.
   ========================================================================= */

/* ---- Design tokens ---------------------------------------------------- */
:root {
  --font-display: 'Space Grotesk', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --font-sans: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;

  --maxw: 1120px;
  --gutter: clamp(1.25rem, 5vw, 2.5rem);
  --deck-gap: clamp(1rem, 2.4vw, 1.5rem);
  --card-w: min(86vw, 460px);
  --radius: 18px;
  --radius-sm: 12px;

  /* Dark theme (default) */
  --bg: #0a0d14;
  --bg-2: #0c1018;
  --surface: #11151e;
  --surface-2: #161b26;
  --border: rgba(255, 255, 255, 0.08);
  --border-strong: rgba(255, 255, 255, 0.16);

  --text: #eceef3;
  --text-dim: #a7afc0;
  --text-faint: #7c869a;

  --accent: #4fd6c0;
  --accent-text: #67e2cf;
  --accent-2: #8b93ff;
  --accent-soft: rgba(79, 214, 192, 0.16);
  --accent-softer: rgba(79, 214, 192, 0.08);

  --btn-bg: #4fd6c0;
  --btn-text: #04130f;

  --header-bg: rgba(10, 13, 20, 0.72);
  --shadow: 0 24px 60px -28px rgba(0, 0, 0, 0.7);
  --grain-opacity: 0.06;
  --grain-img: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");

  color-scheme: dark;
}

:root[data-theme="light"] {
  --bg: #f6f7fb;
  --bg-2: #eef0f6;
  --surface: #ffffff;
  --surface-2: #f1f3f8;
  --border: rgba(16, 24, 40, 0.10);
  --border-strong: rgba(16, 24, 40, 0.18);

  --text: #10141c;
  --text-dim: #495063;
  --text-faint: #6a7283;

  --accent: #0d9488;
  --accent-text: #0a7567;
  --accent-2: #6366f1;
  --accent-soft: rgba(13, 148, 136, 0.14);
  --accent-softer: rgba(13, 148, 136, 0.08);

  --btn-bg: #0b8174;
  --btn-text: #ffffff;

  --header-bg: rgba(246, 247, 251, 0.72);
  --shadow: 0 24px 60px -30px rgba(16, 24, 40, 0.28);
  --grain-opacity: 0.04;

  color-scheme: light;
}

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

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: 84px;
}

body {
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  min-height: 100svh;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, svg { display: block; }

a { color: inherit; text-decoration: none; }

button { font: inherit; color: inherit; }

ul { list-style: none; padding: 0; }

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

:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 2px;
  border-radius: 4px;
}
:focus:not(:focus-visible) { outline: none; }

/* ---- Layout primitives ------------------------------------------------ */
.container {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: clamp(4rem, 9vw, 7rem); }

/* 60ch is a reading measure sized off body text; on a 2.4rem heading it
   wraps mid-phrase and leaves one word stranded. Headings can run the full
   column — it is the sub-heading that needs the measure. */
.section__head { margin-bottom: clamp(2rem, 4vw, 3rem); }

.section__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.7rem, 4vw, 2.4rem);
  line-height: 1.1;
  letter-spacing: -0.01em;
  margin-top: 0.5rem;
}

.section__sub {
  color: var(--text-dim);
  margin-top: 0.75rem;
  font-size: 1.05rem;
  max-width: 60ch;
}

.eyebrow {
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-text);
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---- Icons ------------------------------------------------------------ */
.icon {
  width: 1.1em;
  height: 1.1em;
  flex: none;
  vertical-align: middle;
}

/* ---- Buttons ---------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-weight: 600;
  line-height: 1;
  padding: 0.85em 1.2em;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  white-space: nowrap;
  transition: transform 0.15s ease, background 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
}
.btn:active { transform: translateY(1px); }

.btn--primary {
  background: var(--btn-bg);
  color: var(--btn-text);
  border-color: var(--btn-bg);
}
.btn--primary:hover {
  filter: brightness(1.07);
  box-shadow: 0 10px 26px -12px var(--accent);
}

.btn--ghost {
  background: transparent;
  color: var(--text);
  border-color: var(--border-strong);
}
.btn--ghost:hover {
  border-color: var(--accent);
  color: var(--accent-text);
  background: var(--accent-softer);
}

.btn--sm { padding: 0.62em 0.95em; border-radius: 10px; font-size: 0.95rem; }

/* ---- Tags & stats ----------------------------------------------------- */
.tags { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.tags li {
  font-family: var(--mono);
  font-size: 0.8rem;
  color: var(--text-dim);
  background: var(--surface-2);
  border: 1px solid var(--border);
  padding: 0.4em 0.7em;
  border-radius: 999px;
}

.stats { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.stat {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--accent-softer);
}
.stat__num {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  line-height: 1;
  color: var(--accent-text);
}
.stat__label {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.03em;
  color: var(--text-dim);
}

/* ---- Header / nav ----------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--header-bg);
  -webkit-backdrop-filter: blur(12px) saturate(150%);
  backdrop-filter: blur(12px) saturate(150%);
  border-bottom: 1px solid var(--border);
}
.header__inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  height: 64px;
}

.wordmark {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
  color: var(--text);
}
.wordmark .dot { color: var(--accent); }

.nav { margin-left: auto; display: flex; gap: 0.25rem; }
.nav a {
  color: var(--text-dim);
  padding: 0.5rem 0.75rem;
  border-radius: 8px;
  font-size: 0.95rem;
  font-weight: 500;
  transition: color 0.2s ease, background 0.2s ease;
}
.nav a:hover { color: var(--text); background: var(--surface-2); }

.theme-toggle {
  margin-left: 0.25rem;
  display: inline-grid;
  place-items: center;
  width: 40px; height: 40px;
  border-radius: 10px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  cursor: pointer;
  transition: border-color 0.2s ease, color 0.2s ease, background 0.2s ease;
}
.theme-toggle:hover { border-color: var(--accent); color: var(--accent-text); }
.theme-toggle .icon { width: 1.15rem; height: 1.15rem; }

.icon-moon { display: none; }
:root[data-theme="light"] .icon-sun { display: none; }
:root[data-theme="light"] .icon-moon { display: block; }

/* ---- Hero ------------------------------------------------------------- */
.hero {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  min-height: min(86svh, 820px);
  padding-block: clamp(3rem, 8vw, 5.5rem) clamp(3.5rem, 9vw, 6rem);
}

.hero__aurora,
.hero__grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
}
.hero__aurora {
  background:
    linear-gradient(to bottom, transparent 52%, var(--bg) 100%),
    radial-gradient(42% 52% at 12% 8%, var(--accent-soft), transparent 70%),
    radial-gradient(38% 46% at 88% 2%, color-mix(in srgb, var(--accent-2) 22%, transparent), transparent 70%),
    radial-gradient(46% 50% at 72% 86%, color-mix(in srgb, var(--accent-2) 14%, transparent), transparent 72%);
}
.hero__grain {
  background-image: var(--grain-img);
  background-size: 140px 140px;
  opacity: var(--grain-opacity);
  mix-blend-mode: overlay;
}

/* This element is the .container itself, so capping it at 760px also
   overrode the 1120px track and, with margin auto, floated the whole hero
   180px right of every heading below it — the page had no single left edge.
   Cap the lines instead and let the container stay on the grid. */
.hero__inner { position: relative; z-index: 1; }
.hero__inner > * { max-width: 760px; }

.hero__status { display: inline-flex; align-items: center; gap: 0.6rem; }
.status-dot {
  position: relative;
  width: 0.6rem; height: 0.6rem;
  border-radius: 50%;
  background: var(--accent);
}
.status-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--accent);
}

.hero__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.7rem, 8vw, 4.6rem);
  line-height: 1.02;
  letter-spacing: -0.025em;
  margin-top: 1.1rem;
}

.hero__title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.1rem, 2.6vw, 1.5rem);
  color: var(--text);
  margin-top: 0.6rem;
}
.hero__title .sep { color: var(--text-faint); margin-inline: 0.15em; }

.hero__lede {
  color: var(--text-dim);
  font-size: clamp(1.05rem, 2vw, 1.22rem);
  line-height: 1.6;
  max-width: 56ch;
  margin-top: 1.25rem;
}

.hero__meta {
  font-family: var(--mono);
  font-size: 0.85rem;
  color: var(--text-faint);
  margin-top: 1rem;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 2rem;
}

.hero__jump {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  font-family: var(--mono);
  font-size: 0.85rem;
  color: var(--text-dim);
  margin-top: 1.75rem;
  transition: color 0.2s ease;
}
.hero__jump:hover { color: var(--accent-text); }
.hero__jump .icon { transition: transform 0.2s ease; }
.hero__jump:hover .icon { transform: translateY(2px); }

/* ---- Work / project cards -------------------------------------------- */
/* ---- Work deck (horizontal, snap-scrolled) ---------------------------- */
.deck { position: relative; }

.deck__viewport {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* Bleed out to the window edge, but keep the first card on the same left
     edge as the headings. In margin/padding a percentage resolves against
     the containing block, so (100vw - 100%)/2 is the distance from the
     window to the text grid. */
  margin-inline: calc((100% - 100vw) / 2);
  padding-inline: calc((100vw - 100%) / 2);
  /* scroll-padding resolves percentages against the scrollport itself, where
     the same expression would come out as zero — the snap line would land on
     the window edge and scroll the padding away. Same distance, stated
     without percentages. */
  scroll-padding-inline: max(var(--gutter), calc((100vw - var(--maxw)) / 2 + var(--gutter)));
  padding-block: 0.35rem;
}
.deck__viewport::-webkit-scrollbar { display: none; }
.deck__viewport:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; border-radius: var(--radius); }

/* Each card used to be its own flex column, so a longer description pushed
   that card's stats, tags and buttons out of line with the card beside it.
   One grid owns the rows and every card is a subgrid of it, so each band is
   as tall as the tallest card needs and they all line up across the deck. */
.cards {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: var(--card-w);
  /* top · kicker · title · body(flex) · stats · tags · actions */
  grid-template-rows: auto auto auto 1fr auto auto auto;
  gap: var(--deck-gap);
}

.deck .card {
  display: grid;
  grid-row: 1 / -1;
  grid-template-rows: subgrid;
}

.card__body { display: flex; flex-direction: column; gap: 0.85rem; }

/* Subgrid makes every band as tall as the tallest card needs, and a flex row
   stretches its children to fill — so a card with one row of tags had those
   tags pulled into tall ovals to fill a band sized for two rows. */
.deck .stats,
.deck .tags { align-items: start; align-content: start; }
.card__body .card__desc { margin: 0; }

/* Without trailing room the scroll bottoms out with two cards still sharing
   the view, so the last dots never light up and the arrow stops responding
   early. A flex item works where trailing padding does not — scroll
   containers leave that padding out of scrollWidth. */
.cards::after {
  content: '';
  /* Also has to make up the right-hand bleed, which the scroll container
     leaves out of scrollWidth for the same reason. */
  grid-row: 1 / -1;
  width: max(0px, calc(100% - var(--card-w) - var(--deck-gap) + (100vw - 100%) / 2));
}

.deck .card {
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

.deck__controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: clamp(1rem, 2.4vw, 1.4rem);
}

.deck__dots { display: flex; align-items: center; gap: 0.45rem; }
.deck__dot {
  width: 22px; height: 3px;
  border-radius: 2px;
  background: var(--border-strong, var(--border));
  transition: background 0.25s ease, width 0.25s ease;
}
.deck__dot[data-active] { background: var(--accent); width: 34px; }

.deck__arrows { display: flex; gap: 0.5rem; }
.deck__arrow {
  display: grid;
  place-items: center;
  width: 42px; height: 42px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  transition: border-color 0.2s ease, background 0.2s ease, opacity 0.2s ease, transform 0.2s ease;
}
.deck__arrow svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.deck__arrow:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.deck__arrow:active:not(:disabled) { transform: scale(0.94); }
.deck__arrow:disabled { opacity: 0.32; cursor: default; }
.deck__arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* Cards share a row, so the tallest one sets the height for all of them.
   Cap the screenshot and tighten the padding, or one card with an image
   drags every other card down with it. */
.deck .card { padding: clamp(1.35rem, 2.4vw, 1.75rem); gap: 0.85rem; }
.deck .card__shot img { aspect-ratio: 16 / 9; object-fit: cover; max-height: 152px; }
.deck .card__desc { font-size: 0.965rem; line-height: 1.62; }
@media (min-width: 820px) {
  :root { --card-w: min(48vw, 520px); }
}

.card {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 1.05rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: clamp(1.5rem, 3vw, 2.25rem);
  transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}
.card::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(60% 60% at 100% 0%, var(--accent-soft), transparent 70%);
  opacity: 0.55;
  pointer-events: none;
  transition: opacity 0.25s ease;
}
.card:hover {
  transform: translateY(-4px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow);
}
.card:hover::before { opacity: 1; }
.card > * { position: relative; }

.card__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.card__logo {
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  border-radius: 13px;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: var(--btn-text);
}
.card__logo .icon { width: 1.45rem; height: 1.45rem; }
.card__index {
  font-family: var(--mono);
  font-size: 0.85rem;
  letter-spacing: 0.1em;
  color: var(--text-faint);
}

.card__kicker {
  font-family: var(--mono);
  font-size: 0.76rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-text);
}
.card__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.5rem, 3.5vw, 2rem);
  line-height: 1.05;
  letter-spacing: -0.015em;
  margin-top: -0.5rem;
}
.card__desc {
  color: var(--text-dim);
  line-height: 1.65;
  max-width: 56ch;
}

.card__actions {
  margin-top: auto;
  padding-top: 0.25rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

/* ---- Skills ----------------------------------------------------------- */
.skill-groups {
  display: grid;
  gap: clamp(1.25rem, 3vw, 1.75rem);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.skill-group {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: clamp(1.25rem, 2.5vw, 1.6rem);
}
.skill-group__title {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  margin-bottom: 0.95rem;
  display: flex;
  align-items: center;
  gap: 0.55rem;
}
.skill-group__title::before {
  content: "";
  width: 0.5rem; height: 0.5rem;
  border-radius: 2px;
  background: var(--accent);
}

/* ---- About ------------------------------------------------------------ */
.about__grid {
  display: grid;
  gap: clamp(1.5rem, 4vw, 2.5rem);
  grid-template-columns: 1fr;
}
@media (min-width: 760px) {
  /* The heading used to sit above both columns, so it read as floating over
     the card rather than beside it. It now lives in the left column, and the
     column is inset by the card's own padding so both start on the same line
     — the card's first row sits 28px below its border, the bare prose does not. */
  .about__grid { grid-template-columns: 1.3fr 1fr; align-items: start; }
  .about__bio { padding-top: clamp(1.25rem, 3vw, 1.75rem); }
  .about__bio .section__title { margin-top: 0.35rem; }
  .about__bio > p:last-child { margin-top: 1.1rem; }
}
.about__bio p {
  color: var(--text-dim);
  font-size: 1.08rem;
  line-height: 1.75;
  max-width: 62ch;
}

.facts {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: clamp(1.25rem, 3vw, 1.75rem);
}
.facts dl { display: grid; gap: 1rem; }
.fact dt {
  font-family: var(--mono);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-faint);
  margin-bottom: 0.2rem;
}
.fact dd { color: var(--text); font-weight: 500; }

/* ---- Footer ----------------------------------------------------------- */
.site-footer {
  border-top: 1px solid var(--border);
  background: var(--bg-2);
  padding-block: clamp(1.35rem, 2.4vw, 1.85rem);
}
/* One centred line: copyright, links, back-to-top. */
.footer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.75rem 2rem;
}
.footer__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 1.5rem;
}
.footer__links a {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  color: var(--text-dim);
  font-weight: 500;
  transition: color 0.2s ease;
}
.footer__links a:hover { color: var(--accent-text); }

.footer__copy { color: var(--text-faint); font-size: 0.85rem; }
.footer__top { color: var(--text-faint); transition: color 0.2s ease; }
.footer__top:hover { color: var(--accent-text); }

/* ---- Skip link -------------------------------------------------------- */
.skip-link {
  position: fixed;
  top: 0.6rem;
  left: 0.6rem;
  z-index: 100;
  background: var(--btn-bg);
  color: var(--btn-text);
  padding: 0.6rem 0.9rem;
  border-radius: 8px;
  font-weight: 600;
  transform: translateY(-180%);
  transition: transform 0.2s ease;
}
.skip-link:focus { transform: none; }

/* ---- Scrollbar (fine pointers) --------------------------------------- */
@media (pointer: fine) {
  ::-webkit-scrollbar { width: 12px; height: 12px; }
  ::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: 10px;
    border: 3px solid transparent;
    background-clip: content-box;
  }
  ::-webkit-scrollbar-thumb:hover {
    background: var(--text-faint);
    background-clip: content-box;
  }
}

/* ---- Responsive tweaks ------------------------------------------------ */
@media (max-width: 600px) {
  .nav { display: none; }
  .theme-toggle { margin-left: auto; }
}

/* ---- Motion ----------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }

  /* One-shot hero entrance */
  .hero__inner > * { animation: rise 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) both; }
  .hero__inner > *:nth-child(1) { animation-delay: 0.04s; }
  .hero__inner > *:nth-child(2) { animation-delay: 0.10s; }
  .hero__inner > *:nth-child(3) { animation-delay: 0.16s; }
  .hero__inner > *:nth-child(4) { animation-delay: 0.22s; }
  .hero__inner > *:nth-child(5) { animation-delay: 0.28s; }
  .hero__inner > *:nth-child(6) { animation-delay: 0.34s; }
  .hero__inner > *:nth-child(7) { animation-delay: 0.40s; }
  @keyframes rise {
    from { opacity: 0; transform: translateY(12px); }
    to { opacity: 1; transform: none; }
  }

  /* Availability pulse */
  .status-dot::after { animation: ping 2.4s cubic-bezier(0, 0, 0.2, 1) infinite; }
  @keyframes ping {
    0% { transform: scale(1); opacity: 0.55; }
    75%, 100% { transform: scale(2.6); opacity: 0; }
  }

  /* Reveal-on-scroll (class added by JS only when motion is allowed) */
  .reveal-on .reveal { opacity: 0; transform: translateY(16px); }
  .reveal-on .reveal.is-visible {
    opacity: 1;
    transform: none;
    transition: opacity 0.6s ease, transform 0.6s ease;
  }
  .reveal-on .cards .card:nth-child(2),
  .reveal-on .cards .card:nth-child(4),
  .reveal-on .skill-group:nth-child(2) { transition-delay: 0.06s; }
  .reveal-on .skill-group:nth-child(3) { transition-delay: 0.12s; }
  .reveal-on .skill-group:nth-child(4) { transition-delay: 0.18s; }
  .reveal-on .mini:nth-child(2) { transition-delay: 0.05s; }
  .reveal-on .mini:nth-child(3) { transition-delay: 0.10s; }
  .reveal-on .mini:nth-child(4) { transition-delay: 0.15s; }
  .reveal-on .mini:nth-child(5) { transition-delay: 0.20s; }
  .reveal-on .mini:nth-child(6) { transition-delay: 0.25s; }
  .reveal-on .lab__group:nth-child(3) { transition-delay: 0.06s; }
  .reveal-on .lab__group:nth-child(4) { transition-delay: 0.12s; }
}


/* ---- Card screenshot & private-source note ----------------------------- */
.card__shot {
  display: block;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 12px;
  line-height: 0;
  background: var(--bg2);
}

.card__shot img {
  display: block;
  width: 100%;
  height: auto;
  transition: transform 0.5s ease;
}

.card__note {
  align-self: center;
  color: var(--text-faint);
  font-family: var(--mono);
  font-size: 0.76rem;
  letter-spacing: 0.02em;
}

@media (pointer: fine) {
  .card__shot:hover img { transform: scale(1.025); }
}

/* ---- Experience ------------------------------------------------------- */
.roles {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(1rem, 2vw, 1.25rem);
}

.role {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: clamp(1.35rem, 2.8vw, 1.9rem);
}

.role__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.4rem 1.25rem;
  margin-bottom: 0.9rem;
}

.role__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 2.2vw, 1.2rem);
  letter-spacing: -0.01em;
}

.role__org {
  margin: 0.3rem 0 0;
  color: var(--text-dim);
  font-size: 0.95rem;
}

.role__period {
  margin: 0;
  color: var(--text-faint);
  font-family: var(--mono);
  font-size: 0.82rem;
  white-space: nowrap;
}

.role__desc {
  margin: 0 0 1.1rem;
  color: var(--text-dim);
  line-height: 1.78;
}

.role__aside {
  margin-top: 1.15rem;
  padding-top: 1.05rem;
  border-top: 1px solid var(--border);
}

.role__aside-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 0.6rem;
}

.role__aside-title {
  color: var(--text);
  font-size: 0.92rem;
  font-weight: 600;
}

.role__aside-org { color: var(--text-dim); font-size: 0.88rem; }

.role__aside-period {
  margin-left: auto;
  color: var(--text-faint);
  font-family: var(--mono);
  font-size: 0.76rem;
  white-space: nowrap;
}

.role__aside-desc {
  margin: 0.3rem 0 0;
  color: var(--text-faint);
  font-size: 0.86rem;
  line-height: 1.6;
}

/* ---- Teaching: compact cards ------------------------------------------ */
/* Eight courses always form complete rows: 4 × 2, 2 × 4, then 1 × 8. */
.mini-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(0.85rem, 2vw, 1.1rem);
}
@media (max-width: 900px) {
  .mini-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .mini-grid { grid-template-columns: 1fr; }
}

.mini {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 1.15rem 1.25rem 1.05rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: inherit;
  text-decoration: none;
  transition: transform 0.22s ease, border-color 0.22s ease, background 0.22s ease;
}

.mini__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.02rem;
  letter-spacing: -0.01em;
}

.mini__desc {
  flex: 1;
  margin: 0;
  color: var(--text-dim);
  font-size: 0.9rem;
  line-height: 1.65;
}

.mini__go {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--accent-text);
  font-family: var(--mono);
  font-size: 0.78rem;
}

.mini__go .icon {
  width: 0.85em;
  height: 0.85em;
  transition: transform 0.22s ease;
}

/* ---- Lab: pills -------------------------------------------------------- */
.lab__group + .lab__group { margin-top: clamp(1.4rem, 3vw, 1.9rem); }

.lab__label {
  margin: 0 0 0.75rem;
  color: var(--text-faint);
  font-family: var(--mono);
  font-size: 0.76rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.pills {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
}

.pills a {
  display: inline-block;
  padding: 0.42rem 0.85rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-dim);
  font-size: 0.87rem;
  text-decoration: none;
  transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

@media (pointer: fine) {
  .mini:hover {
    transform: translateY(-2px);
    border-color: var(--border-strong);
  }
  .mini:hover .mini__go .icon { transform: translate(2px, -2px); }
  .pills a:hover {
    color: var(--text);
    border-color: var(--accent);
    background: var(--accent-softer);
  }
}

.mini:focus-visible,
.pills a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

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


/* ---- Teaching: a loop of the idea each course teaches -------------------
   The section's claim is that every concept gets an animation, so the cards
   make that claim instead of describing it. Each card runs the one idea its
   course is about, in that site's own accent colour, in plain CSS. */
.viz {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  height: 58px;
  margin-inline: auto;
  margin-bottom: 0.15rem;
}
.viz i, .viz b, .viz s, .viz u, .viz em { display: block; }
.viz b, .viz i { border-radius: 4px; background: color-mix(in oklab, var(--viz) 16%, transparent); }

/* DrillLab — each completed step removes another layer of guidance */
.viz--drill { width: 100%; }
.drill-stairs {
  position: relative;
  display: flex;
  width: 100%;
  max-width: 158px;
  height: 48px;
  align-items: flex-end;
  gap: 3px;
}
.drill-stairs i {
  flex: 1;
  border: 1px solid color-mix(in oklab, var(--viz) 22%, var(--border));
  border-radius: 4px 4px 2px 2px;
  background: color-mix(in oklab, var(--viz) 7%, transparent);
}
.drill-stairs i:nth-child(1) { height: 9px; animation: drillStageOne 5s ease-in-out infinite; }
.drill-stairs i:nth-child(2) { height: 17px; animation: drillStageTwo 5s ease-in-out infinite; }
.drill-stairs i:nth-child(3) { height: 25px; animation: drillStageThree 5s ease-in-out infinite; }
.drill-stairs i:nth-child(4) { height: 33px; animation: drillStageFour 5s ease-in-out infinite; }
.drill-stairs s {
  position: absolute;
  left: calc(12.5% - 4px);
  bottom: 12px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--viz);
  box-shadow: 0 0 10px color-mix(in oklab, var(--viz) 55%, transparent);
  animation: drillClimb 5s cubic-bezier(.45, 0, .2, 1) infinite;
}
@keyframes drillClimb {
  0% { left: calc(12.5% - 4px); bottom: 12px; opacity: 0; }
  6%,16% { left: calc(12.5% - 4px); bottom: 12px; opacity: 1; }
  28%,38% { left: calc(37.5% - 4px); bottom: 20px; opacity: 1; }
  50%,60% { left: calc(62.5% - 4px); bottom: 28px; opacity: 1; }
  72%,88% { left: calc(87.5% - 4px); bottom: 36px; opacity: 1; }
  94%,100% { left: calc(87.5% - 4px); bottom: 36px; opacity: 0; }
}
@keyframes drillStageOne {
  0%,100% { background: color-mix(in oklab, var(--viz) 7%, transparent); border-color: color-mix(in oklab, var(--viz) 22%, var(--border)); }
  6%,90% { background: color-mix(in oklab, var(--viz) 25%, transparent); border-color: color-mix(in oklab, var(--viz) 52%, var(--border)); }
}
@keyframes drillStageTwo {
  0%,24%,100% { background: color-mix(in oklab, var(--viz) 7%, transparent); border-color: color-mix(in oklab, var(--viz) 22%, var(--border)); }
  28%,90% { background: color-mix(in oklab, var(--viz) 25%, transparent); border-color: color-mix(in oklab, var(--viz) 52%, var(--border)); }
}
@keyframes drillStageThree {
  0%,46%,100% { background: color-mix(in oklab, var(--viz) 7%, transparent); border-color: color-mix(in oklab, var(--viz) 22%, var(--border)); }
  50%,90% { background: color-mix(in oklab, var(--viz) 25%, transparent); border-color: color-mix(in oklab, var(--viz) 52%, var(--border)); }
}
@keyframes drillStageFour {
  0%,68%,100% { background: color-mix(in oklab, var(--viz) 7%, transparent); border-color: color-mix(in oklab, var(--viz) 22%, var(--border)); }
  72%,90% { background: color-mix(in oklab, var(--viz) 25%, transparent); border-color: color-mix(in oklab, var(--viz) 52%, var(--border)); }
}

/* DataData — a pointer walking an array, each cell lighting as it lands */
.viz--array i { width: 20px; height: 20px; animation: vizArray 3.6s infinite; }
.viz--array i:nth-child(1) { animation-delay: 0s }
.viz--array i:nth-child(2) { animation-delay: .18s }
.viz--array i:nth-child(3) { animation-delay: .36s }
.viz--array i:nth-child(4) { animation-delay: .54s }
.viz--array i:nth-child(5) { animation-delay: .72s }
.viz--array i:nth-child(6) { animation-delay: .90s }
@keyframes vizArray {
  0%, 4%   { background: var(--viz); transform: translateY(-4px); }
  16%,100% { background: color-mix(in oklab, var(--viz) 16%, transparent); transform: none; }
}

/* AlgoAlgo — a binary search closing in from both ends */
.viz--bisect { position: relative; width: 100%; max-width: 168px; }
.viz--bisect u { position: absolute; left: 0; right: 0; height: 2px; border-radius: 2px;
                 background: color-mix(in oklab, var(--viz) 18%, transparent); }
.viz--bisect b { position: absolute; width: 3px; height: 16px; border-radius: 2px; background: var(--viz); }
.viz--bisect b.lo { left: 0;  animation: vizLo 3.4s cubic-bezier(.6,0,.4,1) infinite; }
.viz--bisect b.hi { right: 0; animation: vizHi 3.4s cubic-bezier(.6,0,.4,1) infinite; }
.viz--bisect s { position: absolute; left: 50%; width: 8px; height: 8px; margin-left: -4px;
                 border-radius: 50%; background: var(--viz); opacity: 0;
                 animation: vizMid 3.4s infinite; }
@keyframes vizLo  { 0%,8% { left: 0 }   58%,100% { left: calc(50% - 14px) } }
@keyframes vizHi  { 0%,8% { right: 0 }  58%,100% { right: calc(50% - 14px) } }
@keyframes vizMid { 0%,55% { opacity: 0; transform: scale(.4) } 70%,88% { opacity: 1; transform: scale(1) } 100% { opacity: 0 } }

/* TSer — a value becomes a type: the result stays readable while inference runs */
.viz--type { width: 100%; gap: 7px; font-family: var(--mono); }
.type-code, .type-result {
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 44px;
  border: 1px solid color-mix(in oklab, var(--viz) 24%, var(--border));
  border-radius: 7px;
  background: color-mix(in oklab, var(--viz) 7%, transparent);
}
.type-code { flex: 1; min-width: 0; padding: 5px 7px; color: var(--text-faint); font-size: 8px; line-height: 1.25; }
.type-code b { width: max-content; padding: 0; color: var(--text); background: none; font-size: 13px; }
.type-arrow { color: var(--viz); font: 700 13px var(--mono); animation: vizInfer 3.2s infinite; }
.type-result { width: 62px; padding: 4px 6px; opacity: .42; transform: translateX(-4px); animation: vizType 3.2s infinite; }
.type-result small { color: var(--text-faint); font-size: 7px; line-height: 1; }
.type-result strong { color: var(--viz); font-size: 10px; line-height: 1.45; }
@keyframes vizInfer {
  0%,18%,100% { opacity: .25; transform: translateX(-3px) }
  34%,72% { opacity: 1; transform: translateX(2px) }
}
@keyframes vizType {
  0%,20%,100% { opacity: .42; transform: translateX(-4px); box-shadow: none }
  38%,76% { opacity: 1; transform: none; box-shadow: 0 0 18px color-mix(in oklab, var(--viz) 20%, transparent) }
}

/* APIer — a labelled request goes out; a labelled response comes back */
.viz--rtt { width: 100%; max-width: 190px; gap: 7px; font-family: var(--mono); }
.api-node {
  display: grid;
  place-items: center;
  width: 42px;
  height: 30px;
  border: 1px solid color-mix(in oklab, var(--viz) 27%, var(--border));
  border-radius: 7px;
  color: var(--text-dim);
  background: color-mix(in oklab, var(--viz) 8%, transparent);
  font-size: 7px;
  font-weight: 700;
  letter-spacing: .08em;
}
.api-lane { position: relative; flex: 1; height: 34px; }
.api-lane::before, .api-lane::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: color-mix(in oklab, var(--viz) 22%, transparent);
}
.api-lane::before { top: 9px; }
.api-lane::after { bottom: 9px; }
.api-request, .api-response {
  position: absolute;
  z-index: 1;
  padding: 1px 4px;
  border-radius: 4px;
  background: var(--surface);
  color: var(--viz);
  font: 700 7px var(--mono);
  font-style: normal;
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--viz) 22%, transparent);
}
.api-request { top: 3px; left: 0; animation: vizRequest 3.8s cubic-bezier(.45,0,.55,1) infinite; }
.api-response { bottom: 3px; right: 0; animation: vizResponse 3.8s cubic-bezier(.45,0,.55,1) infinite; }
@keyframes vizRequest {
  0%,8% { left: 0; opacity: 0 }
  14% { opacity: 1 }
  42%,52% { left: calc(100% - 27px); opacity: 1 }
  58%,100% { left: calc(100% - 27px); opacity: 0 }
}
@keyframes vizResponse {
  0%,46% { right: 0; opacity: 0 }
  54% { opacity: 1 }
  84%,92% { right: calc(100% - 27px); opacity: 1 }
  100% { right: calc(100% - 27px); opacity: 0 }
}

/* RedisVisual — most reads stop at the cache; some fall through to the store */
.viz--cache { position: relative; width: 100%; max-width: 158px; }
.viz--cache b { width: 15px; height: 20px; }
.viz--cache b.hit { animation: vizHit 4s infinite; }
.viz--cache b.db  { margin-left: auto; }
.viz--cache u { flex: 1; height: 1.5px; background: color-mix(in oklab, var(--viz) 16%, transparent); }
.viz--cache s { position: absolute; left: 17px; width: 6px; height: 6px; border-radius: 50%;
                background: var(--viz); animation: vizRead 4s infinite; }
@keyframes vizRead {
  0%,4%    { left: 17px; opacity: 1 }
  20%,30%  { left: 50px; opacity: 1 }     /* reaches the cache */
  40%      { left: 17px; opacity: .35 }   /* served from cache */
  55%      { left: 50px; opacity: 1 }
  72%      { left: calc(100% - 22px) }    /* a miss goes on to the store */
  92%,100% { left: 17px; opacity: 1 }
}
@keyframes vizHit {
  0%,18%   { background: color-mix(in oklab, var(--viz) 16%, transparent) }
  24%,34%  { background: var(--viz) }
  44%,100% { background: color-mix(in oklab, var(--viz) 16%, transparent) }
}

/* AgentLab — the messages array grows, then the loop starts another turn */
.viz--grow { width: 100%; gap: 8px; font-family: var(--mono); }
.agent-stack { display: flex; flex: 1; flex-direction: column; gap: 3px; }
.agent-stack i {
  display: flex;
  align-items: center;
  gap: 4px;
  height: 14px;
  padding: 1px 4px;
  border: 1px solid color-mix(in oklab, var(--viz) 18%, var(--border));
  border-radius: 4px;
  color: var(--text-faint);
  background: color-mix(in oklab, var(--viz) 7%, transparent);
  font: 7px var(--mono);
  font-style: normal;
  opacity: .22;
  transform: translateY(4px);
  animation: vizMessage 4.2s infinite;
}
.agent-stack i:nth-child(2) { animation-delay: .5s; }
.agent-stack i:nth-child(3) { animation-delay: 1s; }
.agent-stack b {
  display: grid;
  place-items: center;
  width: 11px;
  height: 10px;
  border-radius: 3px;
  color: var(--surface);
  background: var(--viz);
  font-size: 6px;
}
.agent-loop {
  padding: 5px 6px;
  border: 1px solid color-mix(in oklab, var(--viz) 24%, var(--border));
  border-radius: 999px;
  color: var(--viz);
  background: color-mix(in oklab, var(--viz) 8%, transparent);
  font: 700 7px var(--mono);
  white-space: nowrap;
  animation: vizLoop 4.2s infinite;
}
@keyframes vizMessage {
  0%,8% { opacity: .22; transform: translateY(4px) }
  18%,68% { opacity: 1; transform: none }
  82%,100% { opacity: .22; transform: translateY(-2px) }
}
@keyframes vizLoop {
  0%,50% { opacity: .35; transform: rotate(0) }
  64%,78% { opacity: 1; transform: rotate(-5deg); box-shadow: 0 0 16px color-mix(in oklab, var(--viz) 20%, transparent) }
  90%,100% { opacity: .35; transform: rotate(0); box-shadow: none }
}

/* SwiftLab — @State changes and the rendered View follows the same value */
.viz--bind { width: 100%; gap: 7px; font-family: var(--mono); }
.swift-state, .swift-view {
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 42px;
  border: 1px solid color-mix(in oklab, var(--viz) 24%, var(--border));
  border-radius: 8px;
  background: color-mix(in oklab, var(--viz) 7%, transparent);
}
.swift-state { flex: 1; padding: 5px 7px; }
.swift-view { width: 46px; align-items: center; }
.swift-state small, .swift-view small { color: var(--viz); font-size: 7px; line-height: 1; }
.swift-state b { color: var(--text-dim); background: none; font-size: 8px; }
.swift-view b { display: grid; place-items: center; color: var(--text); background: none; font-size: 15px; line-height: 1.2; }
.swift-value { display: inline; border-radius: 0; background: none; }
.swift-value::after { content: '0'; color: var(--text); animation: vizValue 4.2s steps(1, end) infinite; }
.swift-state .swift-value::before { content: '= '; color: var(--text-faint); }
.swift-flow { color: var(--viz); font: 700 13px var(--mono); animation: vizFlow 4.2s infinite; }
.swift-view { animation: vizView 4.2s infinite; }
@keyframes vizValue {
  0%,24%,100% { content: '0' }
  25%,54% { content: '1' }
  55%,84% { content: '2' }
  85%,99% { content: '3' }
}
@keyframes vizFlow {
  0%,18%,100% { opacity: .25; transform: translateX(-2px) }
  28%,84% { opacity: 1; transform: translateX(2px) }
}
@keyframes vizView {
  0%,18%,100% { box-shadow: none }
  28%,36%,58%,66%,86%,94% { box-shadow: 0 0 18px color-mix(in oklab, var(--viz) 22%, transparent); border-color: var(--viz) }
}

@media (prefers-reduced-motion: reduce) {
  .viz i, .viz b, .viz s, .viz u, .viz em, .viz span, .viz s::after, .swift-value::after { animation: none !important; }
  .type-result, .agent-stack i, .agent-loop { opacity: 1; transform: none; }
}

/* ---- Renren: the site guide ------------------------------------------- */
.renren-guide {
  --renren-size: 68px;
  position: fixed;
  z-index: 90;
  right: clamp(1rem, 2.5vw, 1.8rem);
  bottom: clamp(1rem, 2.5vw, 1.8rem);
  width: var(--renren-size);
  height: var(--renren-size);
  pointer-events: none;
}

.renren__launcher {
  position: relative;
  width: var(--renren-size);
  height: var(--renren-size);
  padding: 4px;
  border: 1px solid color-mix(in oklab, var(--accent) 68%, var(--border));
  border-radius: 50%;
  background: color-mix(in oklab, var(--surface) 88%, transparent);
  box-shadow: 0 16px 36px -14px rgba(0, 0, 0, .65), 0 0 0 5px color-mix(in oklab, var(--accent) 8%, transparent);
  cursor: pointer;
  pointer-events: auto;
  transition: transform .22s cubic-bezier(.2,.7,.2,1), border-color .22s ease, box-shadow .22s ease;
}
.renren__launcher:hover {
  transform: translateY(-3px) rotate(2deg);
  border-color: var(--accent);
  box-shadow: 0 20px 42px -14px rgba(0, 0, 0, .7), 0 0 0 7px color-mix(in oklab, var(--accent) 11%, transparent);
}
.renren__launcher:active { transform: translateY(-1px) scale(.97); }
.renren__launcher:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 4px; }

.renren__face {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: inherit;
  background: var(--surface-2);
}
.renren__face img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.08);
}
.renren__face::before,
.renren__face::after {
  content: '';
  position: absolute;
  z-index: 1;
  top: 39%;
  width: 12%;
  height: 5%;
  border-top: 2px solid rgba(46, 29, 23, .9);
  border-radius: 50%;
  opacity: 0;
  animation: renrenBlink 5.8s infinite;
}
.renren__face::before { left: 28%; transform: rotate(7deg); }
.renren__face::after { right: 25%; transform: rotate(-7deg); }
@keyframes renrenBlink {
  0%, 91%, 95%, 100% { opacity: 0 }
  92%, 94% { opacity: 1 }
}

.renren__status {
  position: absolute;
  right: 1px;
  bottom: 5px;
  width: 14px;
  height: 14px;
  border: 3px solid var(--surface);
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 12px color-mix(in oklab, var(--accent) 75%, transparent);
}

.renren__bubble {
  position: absolute;
  right: 0;
  bottom: calc(var(--renren-size) + 14px);
  width: min(310px, calc(100vw - 2rem));
  padding: .9rem .95rem .85rem;
  border: 1px solid var(--border-strong);
  border-radius: 15px 15px 4px 15px;
  background: color-mix(in oklab, var(--surface) 94%, transparent);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  backdrop-filter: blur(16px) saturate(140%);
  box-shadow: 0 24px 64px -24px rgba(0, 0, 0, .72);
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px) scale(.97);
  transform-origin: bottom right;
  pointer-events: none;
  transition: opacity .2s ease, visibility .2s ease, transform .24s cubic-bezier(.2,.8,.2,1);
}
.renren__bubble::after {
  content: '';
  position: absolute;
  right: 24px;
  bottom: -7px;
  width: 12px;
  height: 12px;
  border-right: 1px solid var(--border-strong);
  border-bottom: 1px solid var(--border-strong);
  background: var(--surface);
  transform: rotate(45deg);
}
.renren-guide.is-open .renren__bubble {
  opacity: 1;
  visibility: visible;
  transform: none;
  pointer-events: auto;
}

.renren__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  margin-bottom: .55rem;
  color: var(--text-faint);
  font: 700 .64rem/1 var(--mono);
  letter-spacing: .08em;
}
.renren__head > span { display: inline-flex; align-items: center; gap: .4rem; }
.renren__head i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
}
.renren__close {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
}
.renren__close:hover { color: var(--text); background: var(--surface-2); }
.renren__close:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 1px; }

.renren__copy {
  min-height: 3.2em;
  color: var(--text);
  font-family: var(--font-display);
  font-size: .95rem;
  font-weight: 600;
  line-height: 1.55;
}
.renren__actions { display: flex; align-items: center; gap: .55rem; margin-top: .8rem; }
.renren__actions button,
.renren__actions a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 32px;
  padding: .35rem .65rem;
  border-radius: 8px;
  font-family: var(--mono);
  font-size: .7rem;
  font-weight: 700;
  cursor: pointer;
}
.renren__actions button {
  border: 1px solid var(--accent);
  background: var(--accent-soft);
  color: var(--accent-text);
}
.renren__actions a { color: var(--text-dim); border: 1px solid var(--border); }
.renren__actions button:hover { background: var(--accent); color: var(--btn-text); }
.renren__actions a:hover { border-color: var(--border-strong); color: var(--text); }
.renren__actions button:focus-visible,
.renren__actions a:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }

.renren__zzz {
  position: absolute;
  right: 46px;
  bottom: 50px;
  display: flex;
  align-items: flex-end;
  gap: 1px;
  color: var(--accent-text);
  font: 700 .68rem var(--mono);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity .25s ease, transform .25s ease;
}
.renren__zzz i { font-style: normal; }
.renren__zzz i:nth-child(2) { font-size: .56rem; transform: translateY(-5px); }
.renren__zzz i:nth-child(3) { font-size: .46rem; transform: translateY(-10px); }
.renren-guide.is-idle:not(.is-open) .renren__zzz { opacity: 1; transform: none; }
.renren-guide.is-idle:not(.is-open) .renren__launcher { transform: rotate(-3deg) scale(.98); }

.card.renren-picked,
.mini.renren-picked {
  border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-soft), var(--shadow);
}

@media (max-width: 560px) {
  .renren-guide {
    --renren-size: 60px;
    right: 12px;
    bottom: 12px;
  }
  .renren__bubble { right: 0; width: min(294px, calc(100vw - 24px)); }
  .renren__copy { font-size: .9rem; }
}

@media (prefers-reduced-motion: reduce) {
  .renren__face::before,
  .renren__face::after { animation: none !important; }
  .renren__zzz { display: none; }
  .renren__bubble,
  .renren__launcher { transition: none !important; }
}
