/* v3 template system -- the glassmorphism/pill-nav/blob visual language from
   the user-provided reference template, applied here almost verbatim.
   Extended from the template's 2-theme (root/.dark) split to this site's
   existing 4-theme cycle (dark/dim/light/bright, toggled via
   [data-v2-theme] on <html> by the pre-existing v2-toolbar.js), so the
   theme cycle button already on the page keeps working instead of being
   replaced by a simpler 2-state toggle. */
:root {
  --bg-canvas: #F8FAFC;
  --text-main: #0F172A;
  --card-bg: rgba(255, 255, 255, 0.82);
  --border-color: rgba(226, 232, 240, 0.8);
  --accent-glow: rgba(34, 211, 238, 0.15);
}
html[data-v2-theme="dark"] {
  --bg-canvas: #060B13;
  --text-main: #F1F5F9;
  --card-bg: rgba(15, 23, 42, 0.82);
  --border-color: rgba(51, 65, 85, 0.8);
  --accent-glow: rgba(139, 92, 246, 0.2);
}
html[data-v2-theme="dim"] {
  --bg-canvas: #101826;
  --text-main: #E2E8F0;
  --card-bg: rgba(30, 41, 59, 0.82);
  --border-color: rgba(71, 85, 105, 0.8);
  --accent-glow: rgba(139, 92, 246, 0.18);
}
html[data-v2-theme="bright"] {
  --bg-canvas: #FFFFFF;
  --text-main: #0F172A;
  --card-bg: rgba(255, 255, 255, 0.9);
  --border-color: rgba(226, 232, 240, 0.9);
  --accent-glow: rgba(34, 211, 238, 0.12);
}
/* dark/dim both count as "dark" for the template's own `.dark`-scoped
   Tailwind utility classes (dark:hidden, dark:inline, etc.) -- applied via
   a `dark` class kept in sync with the theme attribute (see v3-template.js). */

.v3-scope {
  background-color: var(--bg-canvas);
  color: var(--text-main);
  font-family: 'Plus Jakarta Sans', sans-serif;
  transition: background-color 0.4s ease, color 0.4s ease;
  overflow-x: hidden;
}

.v3-scope .glass-card {
  background: var(--card-bg);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--border-color);
  box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.04);
}

#bg-canvas {
  position: fixed;
  top: 0;
  left: 0;
  z-index: -1;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  opacity: 0.45;
}
html.no-biofield #bg-canvas { display: none; }

.v3-scope .reveal {
  opacity: 0;
  transform: translateY(35px);
  transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}
.v3-scope .reveal.active {
  opacity: 1 !important;
  transform: translateY(0) !important;
  transition-property: border-color, box-shadow, background-color, color;
}
html .v3-scope .reveal.active {
  opacity: 1 !important;
  transform: translateY(0) !important;
}

.v3-scope .nav-link.active-link {
  font-weight: 700;
  color: #22D3EE;
}
.v3-scope .nav-link.active-link::after {
  content: '';
  position: absolute;
  bottom: -4px;
  left: 0;
  width: 100%;
  height: 2.5px;
  background: linear-gradient(90deg, #22D3EE, #8B5CF6);
  border-radius: 9999px;
}

.v3-scope .v3-brand-orb {
  position: relative;
  isolation: isolate;
  display: inline-grid;
  place-items: center;
  width: 76px;
  height: 76px;
  min-width: 76px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 30% 20%, rgba(255, 255, 255, 0.98), rgba(255, 255, 255, 0.35) 42%, transparent 54%),
    linear-gradient(145deg, rgba(255, 255, 255, 0.96), rgba(226, 232, 240, 0.78));
  border: 1px solid rgba(255, 255, 255, 0.92);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.95),
    inset 0 -8px 14px rgba(15, 23, 42, 0.09),
    0 4px 0 rgba(15, 23, 42, 0.22),
    0 15px 28px rgba(15, 23, 42, 0.17),
    0 0 0 1px rgba(34, 211, 238, 0.12);
  transform: perspective(720px) translateY(0) rotateX(0deg) rotateY(0deg);
  transform-style: preserve-3d;
  transition: transform 0.22s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.22s ease, border-color 0.22s ease, filter 0.22s ease;
}

.v3-scope .v3-brand-orb::after {
  content: '';
  position: absolute;
  inset: auto 10px -8px;
  height: 14px;
  border-radius: 999px;
  background: linear-gradient(90deg, rgba(34, 211, 238, 0.22), rgba(139, 92, 246, 0.2), rgba(239, 68, 68, 0.18));
  filter: blur(8px);
  opacity: 0.85;
  z-index: -1;
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.v3-scope .v3-brand-orb__shine {
  position: absolute;
  inset: 3px;
  border-radius: 21px;
  background:
    linear-gradient(135deg, rgba(255, 255, 255, 0.9), transparent 42%),
    radial-gradient(circle at 75% 76%, rgba(34, 211, 238, 0.14), transparent 45%);
  pointer-events: none;
  z-index: 1;
}

.v3-scope .v3-brand-orb__img {
  position: relative;
  z-index: 2;
  width: 70px;
  height: 70px;
  object-fit: contain;
  transform: translateZ(28px);
  filter:
    drop-shadow(0 5px 6px rgba(15, 23, 42, 0.20))
    saturate(1.08)
    contrast(1.04);
  transition: transform 0.22s cubic-bezier(0.16, 1, 0.3, 1), filter 0.22s ease;
}

.v3-scope .v3-brand-orb:hover {
  border-color: rgba(34, 211, 238, 0.42);
  filter: saturate(1.08);
  transform: perspective(720px) translateY(-2px) rotateX(9deg) rotateY(-8deg) scale(1.035);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 1),
    inset 0 -8px 14px rgba(15, 23, 42, 0.1),
    0 5px 0 rgba(15, 23, 42, 0.2),
    0 18px 32px rgba(34, 211, 238, 0.2),
    0 0 0 1px rgba(139, 92, 246, 0.16);
}

.v3-scope .v3-brand-orb:hover::after {
  opacity: 1;
  transform: translateY(3px) scaleX(1.1);
}

.v3-scope .v3-brand-orb:hover .v3-brand-orb__img {
  transform: translateZ(32px) scale(1.05);
  filter: drop-shadow(0 7px 8px rgba(34, 211, 238, 0.22));
}

.v3-scope .v3-brand-orb:active {
  transform: perspective(720px) translateY(2px) rotateX(0deg) rotateY(0deg) scale(0.97);
  box-shadow:
    inset 0 3px 10px rgba(15, 23, 42, 0.18),
    inset 0 -3px 8px rgba(255, 255, 255, 0.45),
    0 1px 0 rgba(15, 23, 42, 0.18),
    0 8px 16px rgba(15, 23, 42, 0.12);
}

.v3-scope .v3-brand-orb:active .v3-brand-orb__img {
  transform: translateZ(12px) scale(0.98);
}

.v3-scope .v3-brand-orb:focus-visible {
  outline: 3px solid rgba(34, 211, 238, 0.45);
  outline-offset: 4px;
}

html[data-v2-theme="dark"] .v3-scope .v3-brand-orb,
html[data-v2-theme="dim"] .v3-scope .v3-brand-orb {
  background:
    radial-gradient(circle at 28% 18%, rgba(255, 255, 255, 0.42), rgba(255, 255, 255, 0.08) 44%, transparent 56%),
    linear-gradient(145deg, rgba(30, 41, 59, 0.96), rgba(2, 6, 23, 0.86));
  border-color: rgba(148, 163, 184, 0.28);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 -8px 14px rgba(0, 0, 0, 0.26),
    0 3px 0 rgba(0, 0, 0, 0.42),
    0 14px 28px rgba(0, 0, 0, 0.32),
    0 0 0 1px rgba(34, 211, 238, 0.16);
}

@media (prefers-reduced-motion: reduce) {
  .v3-scope .v3-brand-orb,
  .v3-scope .v3-brand-orb__img,
  .v3-scope .v3-brand-orb::after {
    transition: none;
  }
  .v3-scope .v3-brand-orb:hover,
  .v3-scope .v3-brand-orb:active {
    transform: none;
  }
}

.v3-scope .blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  z-index: -1;
  animation: v3-moveBlob 18s infinite alternate ease-in-out;
}
@keyframes v3-moveBlob {
  from { transform: translate(0, 0) scale(1); }
  to { transform: translate(12%, 12%) scale(1.15); }
}

.v3-scope .pulse-ring {
  box-shadow: 0 0 0 0 rgba(34, 211, 238, 0.4);
  animation: v3-pulse-ring 2s infinite;
}
@keyframes v3-pulse-ring {
  0% { box-shadow: 0 0 0 0 rgba(34, 211, 238, 0.4); }
  70% { box-shadow: 0 0 0 10px rgba(34, 211, 238, 0); }
  100% { box-shadow: 0 0 0 0 rgba(34, 211, 238, 0); }
}

/* Graded hero overlay -- dark by default, lighter variant for bright/light themes */
.v3-scope .graded-hero-overlay {
  background:
    radial-gradient(circle at 75% 30%, rgba(34, 211, 238, 0.15) 0%, rgba(11, 17, 32, 0) 55%),
    radial-gradient(circle at 25% 70%, rgba(239, 68, 68, 0.12) 0%, rgba(11, 17, 32, 0) 50%),
    linear-gradient(180deg,
      rgba(11, 17, 32, 0.95) 0%,
      rgba(11, 17, 32, 0.72) 20%,
      rgba(11, 17, 32, 0.35) 45%,
      rgba(11, 17, 32, 0.65) 75%,
      rgba(11, 17, 32, 1.0) 100%
    );
}
html:not([data-v2-theme="dark"]):not([data-v2-theme="dim"]) .v3-scope .graded-hero-overlay {
  background:
    radial-gradient(circle at 75% 30%, rgba(14, 165, 233, 0.15) 0%, rgba(248, 250, 252, 0) 55%),
    radial-gradient(circle at 25% 70%, rgba(225, 29, 72, 0.12) 0%, rgba(248, 250, 252, 0) 50%),
    linear-gradient(180deg,
      rgba(248, 250, 252, 0.94) 0%,
      rgba(248, 250, 252, 0.75) 20%,
      rgba(248, 250, 252, 0.40) 45%,
      rgba(248, 250, 252, 0.82) 75%,
      rgba(248, 250, 252, 1.0) 100%
    );
}

/* Custom scrollbar, scoped so it doesn't override the rest of the site */
.v3-scope::-webkit-scrollbar { width: 8px; }
.v3-scope::-webkit-scrollbar-track { background: var(--bg-canvas); }
.v3-scope::-webkit-scrollbar-thumb { background: #94A3B8; border-radius: 4px; }
.v3-scope::-webkit-scrollbar-thumb:hover { background: #64748B; }

/* Ticker/marquee -- same colour-cycled-label + coloured dot separator
   redesign as the v2 marquees (site-chrome-v2.css/home-v2.css), re-scoped
   for the v3 glass aesthetic. Two instances: knows_about topics on Home,
   job-titles + location in the footer. */
.v3-scope .marquee {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 64px, #000 calc(100% - 64px), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 64px, #000 calc(100% - 64px), transparent 100%);
}
.v3-scope .marquee__track { display: flex; gap: 0; width: max-content; animation: v3-marquee 46s linear infinite; }
.v3-scope .marquee__track:hover { animation-play-state: paused; }
@keyframes v3-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.v3-scope .marquee__item {
  font-family: 'Fira Code', monospace; font-size: 0.85rem; font-weight: 600; white-space: nowrap;
  text-transform: uppercase; letter-spacing: 0.06em; transition: color 0.2s ease, transform 0.2s ease;
}
.v3-scope .marquee__item:hover { transform: translateY(-1px) scale(1.05); }
.v3-scope .marquee__item::after {
  content: '\2022';
  display: inline-block;
  margin: 0 22px;
  font-size: 1.08em;
  font-weight: 900;
  line-height: 1;
  transform: translateY(-0.03em);
}
.v3-scope .marquee__item:nth-child(6n+1) { color: var(--v2-violet); }
.v3-scope .marquee__item:nth-child(6n+2) { color: var(--v2-crimson); }
.v3-scope .marquee__item:nth-child(6n+3) { color: var(--v2-cyan); }
.v3-scope .marquee__item:nth-child(6n+4) { color: var(--v2-yellow-ink); }
.v3-scope .marquee__item:nth-child(6n+5) { color: var(--v2-mint-ink); }
.v3-scope .marquee__item:nth-child(6n+6) { color: var(--v2-ink); }
.v3-scope .marquee__item:nth-child(6n+1)::after { color: var(--v2-cyan); }
.v3-scope .marquee__item:nth-child(6n+2)::after { color: var(--v2-yellow-ink); }
.v3-scope .marquee__item:nth-child(6n+3)::after { color: var(--v2-mint-ink); }
.v3-scope .marquee__item:nth-child(6n+4)::after { color: var(--v2-ink); }
.v3-scope .marquee__item:nth-child(6n+5)::after { color: var(--v2-violet); }
.v3-scope .marquee__item:nth-child(6n+6)::after { color: var(--v2-crimson); }
.v3-scope .marquee--footer .marquee__item { font-size: 0.72rem; }
.v3-scope .marquee--footer { border-top: 1px solid rgba(148,163,184,0.2); }
.v3-scope .marquee--footer .marquee__track { animation: v3-marquee-footer 156s linear infinite; }
.v3-scope .marquee--footer .marquee__track:hover { animation-play-state: running; }
@keyframes v3-marquee-footer { from { transform: translateX(0); } to { transform: translateX(-25%); } }
/* The base 6-colour cycle above is theme-reactive -- 3 of its 6 slots are
   the "-ink"/plain-ink tokens, deliberately DARK so they read as body text
   on a light page background. The footer's own background is always dark
   (bg-slate-900) regardless of site theme, so those same three slots were
   landing as near-black text on a near-black bar -- illegible, not a
   colour-taste issue. Fixed colours here instead of theme tokens, chosen
   only for contrast against that one fixed dark background. */
.v3-scope .marquee--footer .marquee__item:nth-child(6n+1) { color: #22D3EE; }
.v3-scope .marquee--footer .marquee__item:nth-child(6n+2) { color: #A78BFA; }
.v3-scope .marquee--footer .marquee__item:nth-child(6n+3) { color: #FBBF24; }
.v3-scope .marquee--footer .marquee__item:nth-child(6n+4) { color: #34D399; }
.v3-scope .marquee--footer .marquee__item:nth-child(6n+5) { color: #F87171; }
.v3-scope .marquee--footer .marquee__item:nth-child(6n+6) { color: #E2E8F0; }
.v3-scope .marquee--footer .marquee__item:nth-child(6n+1)::after { color: #FBBF24; }
.v3-scope .marquee--footer .marquee__item:nth-child(6n+2)::after { color: #34D399; }
.v3-scope .marquee--footer .marquee__item:nth-child(6n+3)::after { color: #F87171; }
.v3-scope .marquee--footer .marquee__item:nth-child(6n+4)::after { color: #E2E8F0; }
.v3-scope .marquee--footer .marquee__item:nth-child(6n+5)::after { color: #22D3EE; }
.v3-scope .marquee--footer .marquee__item:nth-child(6n+6)::after { color: #A78BFA; }

/* Typed-text cursor blink, for the hero profession rotation */
.v3-scope .typed-cursor {
  display: inline-block; width: 2px; height: 1em; background: currentColor;
  margin-left: 2px; vertical-align: -0.1em; animation: v3-blink 0.9s step-end infinite;
}
@keyframes v3-blink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .v3-scope .typed-cursor { animation: none; }
  .v3-scope .marquee__track { animation: none; }
}

/* ============================================================
   Behavioural CSS for ported interactions (About/Skills/etc.) --
   the JS hooks (about-fx.js and friends) are kept as-is and still target
   these exact class names, but the old about-v2.css/skills-v2.css visual
   skin is NOT loaded on these pages any more -- every section is rebuilt in
   the v3 glass-card/Tailwind language instead. Only the actual motion/
   interaction mechanics live here (nothing about colour, spacing or type,
   which come from Tailwind utility classes directly in the markup). ---- */

/* Specimen scan-line sweep (About §01) */
.v3-scope .specimen-scan { position: absolute; left: 0; right: 0; top: 0; height: 40%; pointer-events: none; background: linear-gradient(180deg, rgba(34,211,238,0.35), transparent); transform: translateY(-100%); opacity: 0; }
.v3-scope .is-scanned .specimen-scan { animation: v3-scan 1.1s ease-out forwards; }
@keyframes v3-scan { 0% { transform: translateY(-100%); opacity: 0.9; } 100% { transform: translateY(250%); opacity: 0; } }

/* Manifesto reading-progress rail (About §02) */
.v3-scope .manifesto-rail-fill { position: absolute; left: 0; top: 0; width: 100%; height: 0%; background: linear-gradient(180deg, #22D3EE, #8B5CF6); }

/* Expertise pill stagger-in (About §03) */
.v3-scope .reveal-pill { transform: translate(var(--mx, 0px), var(--my, 0px)) translateY(14px); opacity: 0; }
.v3-scope .reveal-pill.is-visible { animation: v3-pill-in 0.6s cubic-bezier(0.16,1,0.3,1) forwards; }
@keyframes v3-pill-in { to { opacity: 1; transform: translate(var(--mx, 0px), var(--my, 0px)) translateY(0); } }

/* Identifier terminal-reveal (About §04) */
.v3-scope .reveal-ident { opacity: 0; }
.v3-scope .reveal-ident.is-visible { animation: v3-ident-in 0.5s ease forwards; }
@keyframes v3-ident-in { from { opacity: 0; } to { opacity: 1; } }
.v3-scope .ident-cursor { display: inline-block; width: 7px; height: 1em; background: #22D3EE; margin-left: 2px; vertical-align: text-bottom; animation: v3-blink 0.9s step-end infinite; }
@keyframes v3-blink { 50% { opacity: 0; } }

/* Spotlight glow (About §02 quote, §05 creds -- reuses --sx/--sy already set by v2Motion.attachSpotlight) */
.v3-scope .spotlight-glow { position: relative; overflow: hidden; }
.v3-scope .spotlight-glow::before {
  content: ''; position: absolute; inset: 0; opacity: 0; transition: opacity 0.3s ease; pointer-events: none;
  background: radial-gradient(260px circle at var(--sx, 50%) var(--sy, 50%), rgba(34,211,238,0.18), transparent 70%);
}
.v3-scope .spotlight-glow:hover::before { opacity: 1; }

/* Record-card grid reveal + lightbox (About §06 timeline) */
.v3-scope .reveal-record { opacity: 0; transform: translateY(14px); transition: opacity 0.5s ease, transform 0.5s ease, border-color 0.2s ease, box-shadow 0.2s ease; }
.v3-scope .reveal-record.is-visible { opacity: 1; transform: none; }
.record-lightbox-backdrop {
  position: fixed; inset: 0; z-index: 200; background: rgba(15,23,42,0.85);
  backdrop-filter: blur(14px) saturate(1.1); -webkit-backdrop-filter: blur(14px) saturate(1.1);
  opacity: 0; pointer-events: none; transition: opacity 0.35s ease;
}
.record-lightbox-backdrop.is-open { opacity: 1; pointer-events: auto; }
.record-lightbox-flyer {
  position: fixed; z-index: 201; overflow: auto; box-shadow: 0 20px 60px -12px rgba(0,0,0,0.4);
  border: 1px solid rgba(148,163,184,0.3); background: #fff; color: #0F172A;
  padding: 20px 22px 22px; display: flex; flex-direction: column; gap: 6px; border-radius: 18px;
  font-family: 'Plus Jakarta Sans', sans-serif;
  transition: left 0.55s cubic-bezier(0.22,1,0.36,1), top 0.55s cubic-bezier(0.22,1,0.36,1),
              width 0.55s cubic-bezier(0.22,1,0.36,1), height 0.55s cubic-bezier(0.22,1,0.36,1),
              padding 0.55s cubic-bezier(0.22,1,0.36,1), border-radius 0.55s cubic-bezier(0.22,1,0.36,1);
}
html[data-v2-theme="dark"] .record-lightbox-flyer, html[data-v2-theme="dim"] .record-lightbox-flyer { background: #1E293B; color: #F1F5F9; border-color: rgba(51,65,85,0.8); }
.record-lightbox-flyer .record-card-title { font-family: 'Space Grotesk', sans-serif; font-weight: 700; font-size: 1.05rem; }
.record-lightbox-desc { font-size: 0.95rem; line-height: 1.6; margin: 6px 0 0; opacity: 0; transition: opacity 0.3s ease 0.25s; color: #64748B; }
.record-lightbox-flyer.is-grown .record-lightbox-desc { opacity: 1; }
.record-lightbox-close {
  position: fixed; z-index: 202; width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid rgba(148,163,184,0.3); background: #fff; color: #0F172A;
  display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 8px 24px -8px rgba(0,0,0,0.3);
  opacity: 0; pointer-events: none; transition: opacity 0.25s ease, border-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
}
html[data-v2-theme="dark"] .record-lightbox-close, html[data-v2-theme="dim"] .record-lightbox-close { background: #1E293B; color: #F1F5F9; }
.record-lightbox-close.is-open { opacity: 1; pointer-events: auto; }
.record-lightbox-close:hover { border-color: #22D3EE; color: #22D3EE; transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) {
  .v3-scope .reveal-pill, .v3-scope .reveal-ident, .v3-scope .reveal-record { opacity: 1 !important; transform: none !important; animation: none !important; }
  .v3-scope .specimen-scan { display: none; }
  .record-lightbox-flyer { transition: opacity 0.25s ease; }
  .record-lightbox-backdrop, .record-lightbox-close, .record-lightbox-desc { transition: opacity 0.25s ease; }
}

/* ============================================================
   Community: tilt-physics cards, photo accordion w/ rotated
   captions, video play-to-fullscreen, full-scale lightbox,
   masonry event-grid columns. Ported from site.js/style.css/
   community-v2.css -- same mechanics, v3-consistent colours.
   Selectors are page-agnostic (.event-card/.event-media/
   .lightbox aren't Community-only) so this also lights up for
   any future page reusing the same markup (Gallery carousels
   share the .lightbox, via the same img selector). ---------- */

.v3-scope .event-grid { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 20px; perspective: 900px; }
.v3-scope .event-grid__col { display: flex; flex-direction: column; flex: 1 1 0; min-width: 0; }
/* Tilt-physics base -- shared by any page's .card grid (Skills, Portfolio)
   as well as Community's .event-card, matching site.js's original
   unconditional `.card, .toc-card, .event-card` selector (see
   attachTiltPhysics in v3-template.js). */
.v3-scope .card, .v3-scope .event-card, .v3-scope .toc-card {
  --tilt-x: 0deg; --tilt-y: 0deg; --lift: 0px; --press-scale: 1;
  transform: translateY(var(--lift)) scale(var(--press-scale)) rotateX(var(--tilt-x)) rotateY(var(--tilt-y));
  transition: transform 0.18s ease, box-shadow 0.18s ease;
  will-change: transform;
}
.v3-scope .card:hover, .v3-scope .event-card:hover, .v3-scope .toc-card:hover { --lift: -3px; }
.v3-scope .event-card { margin-bottom: 22px; scroll-margin-top: 104px; }
/* Reveal-on-scroll for any v2Motion.revealEach('...card') consumer (Skills'
   domain cards, Portfolio's project cards) -- was previously toggled by JS
   with no CSS behind it, so it was a harmless no-op (cards just always
   showed at full opacity); this makes the fade-in real everywhere .card is
   used. Opacity-only (no translateY): .card's `transform` property is
   already owned by the tilt-physics rule above (one shared `transform:
   translateY(var(--lift)) scale(...) rotateX(...) rotateY(...)` per
   element) -- a second rule setting `transform: translateY(16px)` here
   would win by source order and silently kill the tilt/press/lift
   composition instead of adding to it. */
.v3-scope .card { opacity: 0; transition: opacity 0.5s ease; }
.v3-scope .card.is-visible { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .v3-scope .card { transition: none; opacity: 1 !important; }
}
.v3-scope .event-card:target { animation: v3-target-flash 1.8s ease; }
@keyframes v3-target-flash { 0% { box-shadow: 0 0 0 3px var(--v2-gold, #22D3EE); } 100% { box-shadow: none; } }

.v3-scope .event-media { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; margin-top: 16px; }
.v3-scope .event-media__item { position: relative; margin: 0; overflow: hidden; border-radius: 10px; border: 1px solid rgba(148,163,184,0.25); aspect-ratio: 4 / 3; background: rgba(148,163,184,0.15); }
.v3-scope .event-media__item img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; transition: transform 0.3s ease; cursor: zoom-in; }
.v3-scope .event-media__item--contain { position: relative; background-size: cover; background-position: center; }
.v3-scope .event-media__item--contain::before { content: ''; position: absolute; inset: -15%; z-index: 0; background: inherit; filter: blur(18px) brightness(0.82); background-size: cover; background-position: center; }
.v3-scope .event-media__item--contain img { object-fit: contain; position: relative; z-index: 1; }
.v3-scope .event-media__item:hover img { transform: scale(1.04); }
.v3-scope .event-media__caption {
  position: absolute; left: 0; right: 0; bottom: 0; margin: 0; padding: 16px 8px 6px;
  font-family: 'Fira Code', monospace; font-size: 0.7rem; color: #f5f0e8; line-height: 1.3;
  background: linear-gradient(to top, rgba(10,8,6,0.82), transparent);
  pointer-events: none; z-index: 2;
}
.v3-scope .event-media__more summary {
  list-style: none; cursor: pointer; font-family: 'Fira Code', monospace; font-size: 0.74rem; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--v2-gold, #22D3EE); padding: 10px; border: 1px dashed rgba(148,163,184,0.35); margin-top: 4px; text-align: center; border-radius: 10px;
}
.v3-scope .event-media__more summary::-webkit-details-marker { display: none; }

/* Accordion fan-out (first 6 photos): narrow strips at rest, each with a
   rotated (sideways) caption label since there's no horizontal room for
   one -- hovering a strip grows it AND un-rotates its own caption flat. */
.v3-scope .event-media--accordion { display: flex; gap: 8px; height: 190px; overflow: hidden; margin-top: 16px; }
.v3-scope .event-media--accordion .event-media__item { flex: 1 1 0%; min-width: 44px; aspect-ratio: auto; height: 100%; transition: flex-grow 0.5s cubic-bezier(0.22,1,0.36,1); }
.v3-scope .event-media--accordion .event-media__item img { object-position: center; }
.v3-scope .event-media--accordion:hover .event-media__item { flex-grow: 1; }
.v3-scope .event-media--accordion:hover .event-media__item:hover { flex-grow: 6; }
.v3-scope .event-media--accordion .event-media__caption {
  left: 50%; right: auto; bottom: 34px; width: max-content; max-width: 140px;
  padding: 4px 2px; background: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-shadow: 0 1px 2px rgba(0,0,0,0.9), 0 0 6px rgba(0,0,0,0.6);
  transform: translateX(-50%) rotate(-90deg); transform-origin: center;
  transition: transform 0.35s cubic-bezier(0.22,1,0.36,1), bottom 0.35s cubic-bezier(0.22,1,0.36,1);
}
.v3-scope .event-media--accordion .event-media__item:hover .event-media__caption { bottom: 8px; max-width: calc(100% - 16px); transform: translateX(-50%) rotate(0deg); }
@media (max-width: 640px) {
  .v3-scope .event-media--accordion { height: 140px; }
  .v3-scope .event-media--accordion .event-media__item { flex: 1 1 88px; }
  .v3-scope .event-media--accordion .event-media__caption { bottom: 6px; transform: translateX(-50%) rotate(0deg); max-width: 90%; }
}
@media (prefers-reduced-motion: reduce) {
  .v3-scope .event-media--accordion .event-media__item, .v3-scope .event-media--accordion .event-media__caption { transition: none; }
}

/* Video play-to-fullscreen (CSS-only -- native Fullscreen API kept
   flashing on then immediately exiting on desktop Firefox; see
   community-fx.js for the full rationale). */
.v3-scope .event-media__video { position: relative; margin: 16px 0 0; display: inline-block; max-width: 100%; }
.v3-scope .event-media__video video { height: 260px; max-width: 100%; width: auto; border-radius: 10px; border: 1px solid rgba(148,163,184,0.25); display: block; box-shadow: 0 10px 30px -5px rgba(0,0,0,0.15); }
.v3-scope .event-media__video--landscape video { width: 462px; height: 260px; object-fit: cover; object-position: 50% 30%; }
.v3-scope .event-media__video__play {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 58px; height: 58px; border-radius: 50%; border: none; background: rgba(0,0,0,0.55); color: #fff;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: transform 0.2s cubic-bezier(0.16,1,0.3,1), background 0.2s ease;
}
.v3-scope .event-media__video__play svg { margin-left: 3px; }
.v3-scope .event-media__video__play:hover { transform: translate(-50%, -50%) scale(1.1); background: #22D3EE; }
.v3-scope .event-media__video__play[hidden] { display: none; }
.v3-scope .event-media__video__close { display: none; }
.v3-scope .event-media__video.is-pseudo-fullscreen { position: fixed; inset: 0; z-index: 500; margin: 0; max-width: none; display: flex; align-items: center; justify-content: center; background: #000; }
.v3-scope .event-media__video.is-pseudo-fullscreen video { width: 100%; height: 100%; max-width: 100vw; max-height: 100vh; object-fit: contain; border: none; border-radius: 0; box-shadow: none; }
.v3-scope .event-media__video.is-pseudo-fullscreen .event-media__video__play { display: none; }
.v3-scope .event-media__video.is-pseudo-fullscreen .event-media__video__close {
  display: flex; position: fixed; top: 20px; right: 20px; z-index: 501; width: 44px; height: 44px; border-radius: 50%; border: none;
  background: rgba(0,0,0,0.55); color: #fff; align-items: center; justify-content: center; cursor: pointer; transition: background 0.2s ease;
}
.v3-scope .event-media__video.is-pseudo-fullscreen .event-media__video__close:hover { background: #22D3EE; }
html.has-pseudo-fullscreen { overflow: hidden; }

/* Full-scale photo lightbox (page-agnostic: any .event-media__item img or
   future .carousel__slide img opens here) -- lives outside .v3-scope
   since it's appended straight to <body>, not inside the page markup. */
.lightbox {
  position: fixed; inset: 0; z-index: 500; display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,0.88); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  opacity: 0; pointer-events: none; transition: opacity 0.3s ease; padding: 40px;
}
.lightbox.is-open { opacity: 1; pointer-events: auto; }
.lightbox__figure { margin: 0; max-width: min(92vw, 1200px); max-height: 88vh; display: flex; flex-direction: column; align-items: center; gap: 14px; }
.lightbox__img { max-width: 100%; max-height: 78vh; object-fit: contain; border-radius: 8px; box-shadow: 0 20px 60px -12px rgba(0,0,0,0.5); transform: scale(0.96); transition: transform 0.3s cubic-bezier(0.16,1,0.3,1); }
.lightbox.is-open .lightbox__img { transform: scale(1); }
.lightbox__caption { color: rgba(241,245,249,0.92); font-family: 'Plus Jakarta Sans', sans-serif; font-size: 0.9rem; text-align: center; max-width: 62ch; margin: 0; }
.lightbox__close, .lightbox__arrow {
  position: absolute; border-radius: 50%; border: 1px solid rgba(255,255,255,0.25); background: rgba(255,255,255,0.08); color: #fff;
  cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background 0.18s ease, transform 0.18s ease;
}
.lightbox__close { top: 22px; right: 24px; width: 44px; height: 44px; font-size: 1.6rem; line-height: 1; }
.lightbox__close:hover { background: rgba(255,255,255,0.18); transform: rotate(90deg); }
.lightbox__arrow { top: 50%; transform: translateY(-50%); width: 52px; height: 52px; font-size: 1.8rem; line-height: 1; }
.lightbox__arrow:hover { background: rgba(255,255,255,0.18); }
.lightbox__arrow--prev { left: 20px; }
.lightbox__arrow--next { right: 20px; }
.lightbox__arrow[hidden] { display: none; }
body.lightbox-open { overflow: hidden; }
@media (max-width: 640px) {
  .lightbox { padding: 16px; }
  .lightbox__arrow { width: 40px; height: 40px; font-size: 1.4rem; }
  .lightbox__close { width: 38px; height: 38px; top: 12px; right: 12px; }
}

/* Community sidebar nav -- scrollspy active state (community-fx.js) */
.v3-scope .community-nav a.is-active { color: var(--v2-gold, #22D3EE); border-color: var(--v2-gold, #22D3EE); background: var(--v2-gold-soft, rgba(34,211,238,0.1)); }

/* Portfolio category filter chips -- active state (site.js-ported logic) */
.v3-scope .filter-chip.is-active { background: #0F172A; color: #fff; border-color: #0F172A; }
html[data-v2-theme="dark"] .filter-chip.is-active, html[data-v2-theme="dim"] .filter-chip.is-active { background: #fff; color: #0F172A; border-color: #fff; }

/* Bento-tint, keyed off .v3-scope (present on every v3 <body> unconditionally)
   instead of the legacy .v2-scope. v2-tokens.css's original .v2-scope
   .v2-bento-tint[data-tint-cycle] rules (still used by old, non-v3 pages)
   require the WHOLE .v2-scope cascade as an ancestor -- which also sets
   .v2-scope's own font-family/background/color, plus a dozen more component
   rules (a{color}, a:hover{color}, .filter-chip/.btn base+hover, .card,
   .tag, .section__title, .breadcrumb...) that directly fight this page's
   own Tailwind-authored markup (e.g. a{color:var(--v2-wine-bright)} beats a
   bare Tailwind text-color utility on specificity, silently recolouring
   every link). A v3 page that wants bento-tint striping should never need
   to opt into that entire legacy skin just for one background effect --
   these companion rules give the exact same 6-way cycle without it. */
.v3-scope .v2-bento-tint[data-tint-cycle="0"] { background: color-mix(in oklch, var(--v2-violet) 16%, var(--v2-glass)); }
.v3-scope .v2-bento-tint[data-tint-cycle="1"] { background: color-mix(in oklch, var(--v2-crimson) 16%, var(--v2-glass)); }
.v3-scope .v2-bento-tint[data-tint-cycle="2"] { background: color-mix(in oklch, var(--v2-cyan) 16%, var(--v2-glass)); }
.v3-scope .v2-bento-tint[data-tint-cycle="3"] { background: color-mix(in oklch, var(--v2-yellow) 18%, var(--v2-glass)); }
.v3-scope .v2-bento-tint[data-tint-cycle="4"] { background: color-mix(in oklch, var(--v2-mint) 18%, var(--v2-glass)); }
.v3-scope .v2-bento-tint[data-tint-cycle="5"] { background: color-mix(in oklch, var(--v2-ink) 10%, var(--v2-glass)); }

@media (prefers-reduced-motion: reduce) {
  .v3-scope .event-card { transition: box-shadow 0.18s ease; }
  .lightbox, .lightbox__img { transition: opacity 0.2s ease; }
}

/* Publications: feed-item reveal + PUB-## record-ID badge -- reads like a
   specimen/accession number (same lab-record framing used elsewhere on the
   site), popping in slightly after its card so it reads as an annotation
   on the card rather than competing with the title for first attention. */
.v3-scope .feed-item { opacity: 0; transform: translateY(16px); transition: opacity 0.5s ease, transform 0.5s ease; }
.v3-scope .feed-item.is-visible { opacity: 1; transform: none; }
.v3-scope .feed-item__record-id {
  opacity: 0; transform: scale(0.6);
  transition: opacity 0.4s ease 0.15s, transform 0.4s cubic-bezier(0.22,1,0.36,1) 0.15s;
}
.v3-scope .feed-item.is-visible .feed-item__record-id { opacity: 1; transform: scale(1); }
@media (prefers-reduced-motion: reduce) {
  .v3-scope .feed-item, .v3-scope .feed-item__record-id { transition: none; opacity: 1 !important; transform: none !important; }
}

/* Certificates: .tag reveal + left-accent border (credential/licence/
   membership chips). --v2-gold-driven for the normal case (page's own
   assigned hue), a fixed crimson for --pending (mirrors the old
   .tag--pending rule) regardless of page accent -- "still in progress"
   reads as a distinct, consistent signal rather than blending in. */
.v3-scope .tag { opacity: 0; transform: translateY(12px); transition: opacity 0.5s ease, transform 0.5s ease; border-left: 2px solid var(--v2-gold, #22D3EE); }
.v3-scope .tag.is-visible { opacity: 1; transform: none; }
.v3-scope .tag--pending { border-left-color: #EF4444; }
@media (prefers-reduced-motion: reduce) {
  .v3-scope .tag { transition: none; opacity: 1 !important; transform: none !important; }
}

/* Oversized ghost numeral behind each numbered section heading -- restored
   from the old home-v2.css/about-v2.css editorial motif (a graphic anchor
   rather than a plain small text label). Sits behind the real heading
   (z-index 0 vs 1) inside a `relative`-positioned wrapper; the small
   visible "01"/"02" label + heading text stay exactly as already built,
   this is a purely additive background layer. */
.v3-scope .section__ghost-num {
  position: absolute; top: -0.3em; left: -0.02em; z-index: 0; pointer-events: none;
  font-family: 'Space Grotesk', sans-serif; font-weight: 800; line-height: 0.8;
  font-size: clamp(5rem, 13vw, 11rem); color: #0F172A; opacity: 0.05;
  user-select: none; white-space: nowrap;
}
html[data-v2-theme="dark"] .v3-scope .section__ghost-num, html[data-v2-theme="dim"] .v3-scope .section__ghost-num { color: #F1F5F9; opacity: 0.06; }
.v3-scope .section__ghost-wrap { position: relative; }
.v3-scope .section__ghost-wrap > *:not(.section__ghost-num) { position: relative; z-index: 1; }

/* ============================================================
   Field Map: ECharts chrome overlays (compass/scale/zoom/hint sit
   absolutely positioned on the chart canvas itself), legend filter
   pills, JS-created timeline scrubber (field-map.js builds these
   elements with document.createElement -- no Tailwind classes ever
   land on them, so they need real CSS here or they render unstyled),
   scrollytelling card list. Ported from style.css/map-v2.css. ------ */
.v3-scope .geo-map-frame { --sx: 50%; --sy: 50%; position: relative; overflow: hidden; }
.v3-scope .geo-map-frame::after {
  content: ''; position: absolute; inset: 0; z-index: 3; pointer-events: none; opacity: 0; transition: opacity 0.4s ease;
  background: radial-gradient(420px circle at var(--sx) var(--sy), rgba(139,92,246,0.12), transparent 70%);
}
.v3-scope .geo-map-frame:hover::after { opacity: 1; }
.v3-scope .geo-map-echarts { width: 100%; height: 620px; max-height: 78vh; }
@media (max-width: 720px) { .v3-scope .geo-map-echarts { height: 440px; } }

.v3-scope .geo-map-hint {
  position: absolute; top: 14px; left: 14px; z-index: 2;
  font-family: 'Fira Code', monospace; font-size: 0.62rem; color: #64748B;
  background: rgba(248,250,252,0.85); padding: 4px 9px; border-radius: 20px; border: 1px solid rgba(148,163,184,0.3);
  opacity: 0; transition: opacity 0.25s ease; pointer-events: none;
}
.v3-scope .geo-map-hint.is-visible { opacity: 1; }
.v3-scope .geo-compass { position: absolute; top: 14px; right: 14px; z-index: 2; display: flex; flex-direction: column; align-items: center; gap: 2px; font-family: 'Fira Code', monospace; font-size: 0.62rem; color: #64748B; pointer-events: none; }
@media (max-width: 720px) { .v3-scope .geo-compass, .v3-scope .geo-map-hint { display: none; } }

.v3-scope .geo-scale { position: absolute; left: 14px; bottom: 14px; z-index: 2; display: flex; flex-direction: column; align-items: flex-start; gap: 3px; pointer-events: none; }
.v3-scope .geo-scale__bar { height: 3px; background: #64748B; position: relative; }
.v3-scope .geo-scale__bar::before, .v3-scope .geo-scale__bar::after { content: ''; position: absolute; top: -3px; width: 1px; height: 9px; background: #64748B; }
.v3-scope .geo-scale__bar::before { left: 0; }
.v3-scope .geo-scale__bar::after { right: 0; }
.v3-scope .geo-scale__label { font-family: 'Fira Code', monospace; font-size: 0.62rem; color: #64748B; }

.v3-scope .geo-zoom { position: absolute; bottom: 14px; right: 14px; z-index: 2; display: flex; flex-direction: column; gap: 6px; }
.v3-scope .geo-zoom__btn {
  width: 32px; height: 32px; border-radius: 50%; border: 1px solid rgba(148,163,184,0.35);
  background: rgba(255,255,255,0.9); color: #0F172A; display: flex; align-items: center; justify-content: center;
  cursor: pointer; font-family: 'Fira Code', monospace; font-size: 1rem; line-height: 1;
  box-shadow: 0 4px 14px -4px rgba(0,0,0,0.2); transition: background 0.18s ease, color 0.18s ease, transform 0.18s ease;
}
.v3-scope .geo-zoom__btn:hover { background: #22D3EE; color: #fff; transform: scale(1.06); }
.v3-scope .geo-zoom__btn--reset { font-size: 0.65rem; }

.v3-scope .geo-legend__item { display: inline-flex; align-items: center; gap: 6px; background: none; border: none; padding: 0; font: inherit; cursor: pointer; opacity: 1; transition: opacity 0.2s ease; }
.v3-scope .geo-legend__item.is-dimmed { opacity: 0.35; }
.v3-scope .geo-legend__swatch { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.v3-scope .geo-legend__item--screening .geo-legend__swatch { background: var(--v2-gold, #FBBF24); }
.v3-scope .geo-legend__item--conference .geo-legend__swatch { background: var(--v2-wine-bright, var(--v2-wine, #8B5CF6)); }
.v3-scope .geo-legend__item--outreach .geo-legend__swatch { background: var(--v2-clay, #F97316); }
.v3-scope .geo-legend__swatch--district { border-radius: 2px; background: none; border: 1.5px solid #CBD5E1; }

.v3-scope .geo-timeline__track { position: relative; display: flex; justify-content: space-between; align-items: center; height: 2px; background: rgba(148,163,184,0.3); margin: 0 6px; }
.v3-scope .geo-timeline__year {
  position: relative; background: none; border: none; cursor: pointer; padding: 14px 4px;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  font-family: 'Fira Code', monospace; font-size: 0.76rem; color: #64748B; transition: color 0.2s ease;
}
.v3-scope .geo-timeline__year::before {
  content: ''; width: 8px; height: 8px; border-radius: 50%; background: #fff;
  border: 1.5px solid #94A3B8; transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}
.v3-scope .geo-timeline__year:hover { color: #0F172A; }
.v3-scope .geo-timeline__year:hover::before { border-color: #22D3EE; transform: scale(1.15); }
.v3-scope .geo-timeline__year.is-active { color: #22D3EE; }
.v3-scope .geo-timeline__year.is-active::before { background: #22D3EE; border-color: #22D3EE; box-shadow: 0 0 10px 2px rgba(34,211,238,0.35); }
.v3-scope .geo-timeline__reset {
  font-family: 'Fira Code', monospace; font-size: 0.7rem; color: #64748B; background: none;
  border: 1px solid rgba(148,163,184,0.3); border-radius: 999px; padding: 6px 14px; cursor: pointer; margin-top: 10px;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.v3-scope .geo-timeline__reset:hover { color: #22D3EE; border-color: #22D3EE; }

.v3-scope .geo-card { border-left: 2px solid rgba(148,163,184,0.3); padding: 2px 0 2px 20px; transition: border-left-color 0.3s ease, opacity 0.3s ease; }
.v3-scope .geo-card.is-active { border-left-color: #22D3EE; }
.v3-scope .geo-card.is-dimmed { opacity: 0.35; }

html[data-v2-theme="dark"] .v3-scope .geo-map-hint, html[data-v2-theme="dim"] .v3-scope .geo-map-hint { background: rgba(15,23,42,0.85); color: #94A3B8; border-color: rgba(51,65,85,0.5); }
html[data-v2-theme="dark"] .v3-scope .geo-zoom__btn, html[data-v2-theme="dim"] .v3-scope .geo-zoom__btn { background: rgba(30,41,59,0.9); color: #F1F5F9; border-color: rgba(71,85,105,0.5); }
html[data-v2-theme="dark"] .v3-scope .geo-compass, html[data-v2-theme="dim"] .v3-scope .geo-compass,
html[data-v2-theme="dark"] .v3-scope .geo-scale__bar, html[data-v2-theme="dim"] .v3-scope .geo-scale__bar,
html[data-v2-theme="dark"] .v3-scope .geo-scale__bar::before, html[data-v2-theme="dim"] .v3-scope .geo-scale__bar::before,
html[data-v2-theme="dark"] .v3-scope .geo-scale__bar::after, html[data-v2-theme="dim"] .v3-scope .geo-scale__bar::after,
html[data-v2-theme="dark"] .v3-scope .geo-scale__label, html[data-v2-theme="dim"] .v3-scope .geo-scale__label,
html[data-v2-theme="dark"] .v3-scope .geo-timeline__year, html[data-v2-theme="dim"] .v3-scope .geo-timeline__year,
html[data-v2-theme="dark"] .v3-scope .geo-timeline__reset, html[data-v2-theme="dim"] .v3-scope .geo-timeline__reset { color: #94A3B8; }
html[data-v2-theme="dark"] .v3-scope .geo-timeline__year:hover, html[data-v2-theme="dim"] .v3-scope .geo-timeline__year:hover { color: #F1F5F9; }
html[data-v2-theme="dark"] .v3-scope .geo-timeline__year::before, html[data-v2-theme="dim"] .v3-scope .geo-timeline__year::before { background: #1E293B; }

@media (prefers-reduced-motion: reduce) {
  .v3-scope .geo-timeline__year, .v3-scope .geo-timeline__year::before, .v3-scope .geo-card, .v3-scope .geo-legend__item, .v3-scope .geo-zoom__btn, .v3-scope .geo-map-frame::after { transition: none; }
}

/* ============================================================
   Gallery: scroll-pinned scatter->line->circle->arc morph intro
   (gallery-morph.js creates .gallery-morph__card elements at runtime --
   no Tailwind classes ever land on them) + fan-carousel deck/lightbox
   (fan-carousel.js, same "JS-created, needs real CSS" situation for the
   lightbox). Ported from gallery-morph.css/fan-carousel.css, v3 colours. */
.v3-scope .gallery-morph { position: relative; background: var(--bg-canvas); }
.v3-scope .gallery-morph__scroller { position: relative; height: 260vh; }
.v3-scope .gallery-morph__stage { position: sticky; top: 0; height: 100vh; overflow: hidden; display: flex; align-items: center; justify-content: center; text-align: center; }
.v3-scope .gallery-morph__intro { position: absolute; top: 46%; left: 50%; transform: translate(-50%, -50%); z-index: 1; pointer-events: none; padding: 0 24px; max-width: 640px; }
.v3-scope .gallery-morph__eyebrow { font-family: 'Fira Code', monospace; font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase; color: #22D3EE; margin: 0 0 14px; }
.v3-scope .gallery-morph__title { font-family: 'Space Grotesk', sans-serif; font-weight: 700; font-size: clamp(1.6rem, 3.4vw, 2.6rem); color: var(--text-main); margin: 0; }
.v3-scope .gallery-morph__hint { font-family: 'Fira Code', monospace; font-size: 0.7rem; letter-spacing: 0.1em; text-transform: uppercase; color: #64748B; margin: 16px 0 0; }
.v3-scope .gallery-morph__card {
  position: absolute; top: 50%; left: 50%; width: 78px; height: 108px; margin: -54px 0 0 -39px;
  border-radius: 12px; overflow: hidden; box-shadow: 0 20px 44px -18px rgba(0,0,0,0.35);
  cursor: pointer; will-change: transform, opacity; opacity: 0;
}
.v3-scope .gallery-morph__card img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 720px) {
  .v3-scope .gallery-morph__card { width: 56px; height: 78px; margin: -39px 0 0 -28px; }
  .v3-scope .gallery-morph__hint { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .v3-scope .gallery-morph__scroller { height: auto; }
  .v3-scope .gallery-morph__stage { position: static; height: auto; padding: 60px 24px; flex-wrap: wrap; gap: 10px; }
  .v3-scope .gallery-morph__card { position: static; margin: 0; opacity: 1 !important; transform: none !important; }
  .v3-scope .gallery-morph__intro { display: none; }
}

.v3-scope .fan-carousel { position: relative; max-width: 980px; margin: 0 auto 40px; padding: 40px 0 96px; }
.v3-scope .fan-carousel__deck { position: relative; height: 420px; display: flex; align-items: center; justify-content: center; perspective: 1200px; }
.v3-scope .fan-carousel__card {
  position: absolute; width: 190px; height: 270px; border-radius: 14px; overflow: hidden;
  box-shadow: 0 20px 44px -18px rgba(0,0,0,0.35); border: 1px solid rgba(148,163,184,0.25);
  transition: transform 0.55s cubic-bezier(0.22,1,0.36,1), opacity 0.55s ease, z-index 0s 0.1s;
  cursor: pointer; background: rgba(148,163,184,0.1);
}
.v3-scope .fan-carousel__card img { width: 100%; height: 100%; object-fit: cover; display: block; }
.v3-scope .fan-carousel__card::after { content: ''; position: absolute; inset: 0; background: rgba(15,23,42,0.4); opacity: 1; transition: opacity 0.4s ease; }
.v3-scope .fan-carousel__card.is-active::after { opacity: 0; }
.v3-scope .fan-carousel__card:not(.is-active):hover::after { opacity: 0.12; }
.v3-scope .fan-carousel__caption {
  position: absolute; left: 6vw; right: 6vw; bottom: 0; z-index: 5; text-align: center;
  font-family: 'Fira Code', monospace; font-size: 0.82rem; color: #64748B; opacity: 0; transition: opacity 0.4s ease; pointer-events: none;
}
.v3-scope .fan-carousel__caption.is-visible { opacity: 1; }
.v3-scope .fan-carousel__arrow {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 10; width: 44px; height: 44px; border-radius: 50%;
  border: 1px solid rgba(148,163,184,0.3); background: var(--card-bg); color: var(--text-main);
  display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 10px 24px -8px rgba(0,0,0,0.2);
  transition: border-color 0.25s ease, color 0.25s ease;
}
.v3-scope .fan-carousel__arrow:hover { border-color: #22D3EE; color: #22D3EE; }
.v3-scope .fan-carousel__arrow--prev { left: 0; }
.v3-scope .fan-carousel__arrow--next { right: 0; }
.v3-scope .fan-carousel__dots { position: absolute; bottom: 44px; left: 50%; transform: translateX(-50%); z-index: 10; display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; max-width: 70%; }
.v3-scope .fan-carousel__dot { width: 6px; height: 6px; border-radius: 50%; border: none; background: rgba(148,163,184,0.4); cursor: pointer; padding: 0; transition: background 0.25s ease, transform 0.25s ease; }
.v3-scope .fan-carousel__dot.is-active { background: #22D3EE; transform: scale(1.4); }
@media (max-width: 640px) {
  .v3-scope .fan-carousel__deck { height: 320px; }
  .v3-scope .fan-carousel__card { width: 140px; height: 200px; }
  .v3-scope .fan-carousel__arrow { width: 38px; height: 38px; }
}
@media (prefers-reduced-motion: reduce) { .v3-scope .fan-carousel__card { transition: opacity 0.3s ease; } }

/* Fan-carousel lightbox: JS-created (fan-carousel.js), appended straight to
   <body> -- lives outside .v3-scope, same as the Community/Publications
   lightbox, so styled unscoped like that one. */
.fan-lightbox-backdrop {
  position: fixed; inset: 0; z-index: 500; background: rgba(15,23,42,0.9);
  backdrop-filter: blur(14px) saturate(1.1); -webkit-backdrop-filter: blur(14px) saturate(1.1);
  opacity: 0; pointer-events: none; transition: opacity 0.35s ease;
}
.fan-lightbox-backdrop.is-open { opacity: 1; pointer-events: auto; }
.fan-lightbox-flyer {
  position: fixed; z-index: 501; overflow: hidden; box-shadow: 0 20px 60px -12px rgba(0,0,0,0.5);
  border: 1px solid rgba(148,163,184,0.25); background: #1E293B;
  transition: left 0.55s cubic-bezier(0.22,1,0.36,1), top 0.55s cubic-bezier(0.22,1,0.36,1),
              width 0.55s cubic-bezier(0.22,1,0.36,1), height 0.55s cubic-bezier(0.22,1,0.36,1),
              border-radius 0.55s cubic-bezier(0.22,1,0.36,1);
}
.fan-lightbox-flyer img { width: 100%; height: 100%; display: block; }
.fan-lightbox-caption {
  position: fixed; z-index: 501; font-family: 'Fira Code', monospace; font-size: 0.84rem; color: #CBD5E1;
  text-align: center; max-width: min(90vw, 60ch); opacity: 0; transition: opacity 0.3s ease 0.2s; pointer-events: none;
  left: 50%; transform: translateX(-50%);
}
.fan-lightbox-caption.is-open { opacity: 1; }
.fan-lightbox-close {
  position: fixed; z-index: 502; width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid rgba(148,163,184,0.3); background: #1E293B; color: #F1F5F9;
  display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 8px 24px -8px rgba(0,0,0,0.4);
  opacity: 0; pointer-events: none; transition: opacity 0.25s ease, border-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
}
.fan-lightbox-close.is-open { opacity: 1; pointer-events: auto; }
.fan-lightbox-close:hover { border-color: #22D3EE; color: #22D3EE; transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) {
  .fan-lightbox-flyer { transition: opacity 0.25s ease; }
  .fan-lightbox-backdrop, .fan-lightbox-caption, .fan-lightbox-close { transition: opacity 0.25s ease; }
}

/* Footer social icon tray -- real brand glyphs (native shape + colour) in a
   dock that fans outward from a pivot below the row on hover. Restored from
   the old site-chrome-v2.css version (was +-30/20/11deg) and since widened
   twice at direct request: first to +-42/28/15deg, now +-58/40/22deg with a
   springier overshoot easing, a tray-wide scale-up the moment the pointer
   enters (not just the hovered icon), and a per-icon transition-delay
   stagger so the fan unfurls as a wave rather than every icon snapping out
   in lockstep -- the actual "more kinetism" ask, not just wider angles. */
.v3-scope .site-footer__icons { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 10px; }
.v3-scope .site-footer__icons li { display: contents; }
.v3-scope .site-footer__icons a {
  --fan: 0deg; --lift: 0px; --scale: 1;
  width: 44px; height: 44px; border-radius: 50%; border: 1px solid rgba(148,163,184,0.28);
  background: rgba(255,255,255,0.06); display: flex; align-items: center; justify-content: center;
  font-size: 1.15rem; cursor: pointer;
  transform: rotate(var(--fan)) translateY(var(--lift)) scale(var(--scale));
  transform-origin: 50% 220%;
  transition: transform 0.42s cubic-bezier(0.34, 1.56, 0.64, 1), border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}
.v3-scope .site-footer__icons:hover a { --lift: -8px; --scale: 1.08; }
.v3-scope .site-footer__icons:hover li:nth-child(1) a { --fan: -58deg; transition-delay: 0s; }
.v3-scope .site-footer__icons:hover li:nth-child(2) a { --fan: -44deg; transition-delay: 0.015s; }
.v3-scope .site-footer__icons:hover li:nth-child(3) a { --fan: -30deg; transition-delay: 0.03s; }
.v3-scope .site-footer__icons:hover li:nth-child(4) a { --fan: -15deg; transition-delay: 0.045s; }
.v3-scope .site-footer__icons:hover li:nth-child(5) a { --fan: 0deg; transition-delay: 0.06s; }
.v3-scope .site-footer__icons:hover li:nth-child(6) a { --fan: 15deg; transition-delay: 0.045s; }
.v3-scope .site-footer__icons:hover li:nth-child(7) a { --fan: 30deg; transition-delay: 0.03s; }
.v3-scope .site-footer__icons:hover li:nth-child(8) a { --fan: 44deg; transition-delay: 0.015s; }
.v3-scope .site-footer__icons:hover li:nth-child(9) a { --fan: 58deg; transition-delay: 0s; }
.v3-scope .site-footer__icons a:hover {
  --lift: -28px; --scale: 1.22; z-index: 1; border-color: currentColor; background: rgba(255,255,255,0.16);
  box-shadow: 0 18px 34px -8px rgba(0,0,0,0.55), 0 0 0 1px currentColor inset;
  transition-delay: 0s !important;
}
/* Click: bounce in place (current fan/lift/scale held, an extra elastic
   pulse on top), THEN the link actually opens -- see the click handler in
   v3-template.js, which delays navigation until this finishes playing. */
@keyframes v3-icon-bounce {
  0% { transform: rotate(var(--fan)) translateY(var(--lift)) scale(var(--scale)); }
  30% { transform: rotate(var(--fan)) translateY(var(--lift)) scale(calc(var(--scale) * 1.55)); }
  55% { transform: rotate(var(--fan)) translateY(var(--lift)) scale(calc(var(--scale) * 0.85)); }
  75% { transform: rotate(var(--fan)) translateY(var(--lift)) scale(calc(var(--scale) * 1.15)); }
  100% { transform: rotate(var(--fan)) translateY(var(--lift)) scale(var(--scale)); }
}
.v3-scope .site-footer__icons a.is-bouncing { animation: v3-icon-bounce 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); }
@media (prefers-reduced-motion: reduce) {
  .v3-scope .site-footer__icons a { transition: border-color 0.2s ease, background 0.2s ease; }
  .v3-scope .site-footer__icons:hover a, .v3-scope .site-footer__icons a:hover { --fan: 0deg; --lift: 0px; --scale: 1; transition-delay: 0s !important; }
  .v3-scope .site-footer__icons a.is-bouncing { animation: none; }
}
