/* =================================================================
   Ivan Orpiano — Portfolio
   Design system: "Workflow Canvas"
   - Dot-grid canvas, node-style cards, data-flow connectors
   - Themes: dark (default) + light, toggled via [data-theme]
   ================================================================= */

/* ---------- Design tokens ---------- */
:root {
  /* Accent (shared across themes) */
  --iris: #818cf8;
  --iris-strong: #6366f1;
  --cyan: #2dd4bf;
  --flow: linear-gradient(90deg, var(--iris) 0%, var(--cyan) 100%);

  /* Type */
  --font-display: 'Playfair Display', Georgia, serif;
  --font-body: 'Inter', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, monospace;

  /* Scale */
  --step--1: clamp(0.82rem, 0.79rem + 0.15vw, 0.9rem);
  --step-0:  clamp(1rem, 0.96rem + 0.2vw, 1.08rem);
  --step-1:  clamp(1.2rem, 1.1rem + 0.4vw, 1.45rem);
  --step-2:  clamp(1.6rem, 1.35rem + 1vw, 2.3rem);
  --step-3:  clamp(2.4rem, 1.9rem + 2.4vw, 4.2rem);

  /* Geometry */
  --radius: 16px;
  --radius-sm: 10px;
  --radius-pill: 999px;
  --maxw: 1200px;
  --gutter: clamp(20px, 5vw, 56px);
  --section-y: clamp(72px, 9vw, 132px);

  /* Motion */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --t-fast: 0.18s var(--ease);
  --t: 0.32s var(--ease);
}

/* Dark theme (default) */
[data-theme="dark"] {
  --canvas: #0c111b;
  --canvas-2: #0a0e16;
  --surface: #131a27;
  --surface-2: #18212f;
  --line: rgba(148, 163, 184, 0.14);
  --line-strong: rgba(148, 163, 184, 0.28);
  --ink: #eef2f8;
  --ink-2: #9fb0c5;
  --ink-3: #6b7a90;
  --dot: rgba(129, 140, 248, 0.14);
  --shadow: 0 18px 50px -20px rgba(0, 0, 0, 0.7);
  --glow: 0 0 0 1px rgba(129, 140, 248, 0.35), 0 0 40px -8px rgba(129, 140, 248, 0.45);
  color-scheme: dark;
}

/* Light theme ("blueprint") */
[data-theme="light"] {
  --canvas: #f4f6fb;
  --canvas-2: #eef1f8;
  --surface: #ffffff;
  --surface-2: #f7f9fd;
  --line: rgba(15, 23, 42, 0.10);
  --line-strong: rgba(15, 23, 42, 0.20);
  --ink: #131a27;
  --ink-2: #4a5a72;
  --ink-3: #7c8aa0;
  --dot: rgba(99, 102, 241, 0.14);
  --shadow: 0 18px 45px -24px rgba(30, 41, 90, 0.35);
  --glow: 0 0 0 1px rgba(99, 102, 241, 0.4), 0 0 36px -10px rgba(99, 102, 241, 0.4);
  --iris: #6366f1;
  --cyan: #0d9488;
  color-scheme: light;
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; touch-action: pan-x pan-y; }

body {
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.65;
  color: var(--ink);
  background-color: var(--canvas);
  background-image: radial-gradient(var(--dot) 1px, transparent 1px);
  background-size: 26px 26px;
  background-position: -13px -13px;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  transition: background-color var(--t), color var(--t);
}

/* ---------- Theme switch animation ---------- */
/* Modern path (View Transitions API): a circular reveal expanding from
   the toggle button. The reveal is pure CSS — JS only sets the origin
   coordinates (--vt-x/--vt-y/--vt-r) and the .theme-reveal class before
   starting the transition. Keyframes must be declared here rather than
   driven by Element.animate(pseudoElement: …), which WebKit (all iPad /
   iPhone browsers) does not support for view-transition pseudos.
   The overrides are scoped to html.theme-reveal so that any engine that
   supports view transitions but not the reveal still gets the browser's
   built-in cross-fade instead of an instant snap. */
@keyframes theme-reveal-in {
  from { clip-path: circle(0px at var(--vt-x, 50%) var(--vt-y, 50%)); }
  to   { clip-path: circle(var(--vt-r, 150vmax) at var(--vt-x, 50%) var(--vt-y, 50%)); }
}
html.theme-reveal::view-transition-old(root),
html.theme-reveal::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}
html.theme-reveal::view-transition-old(root) { z-index: 1; }
html.theme-reveal::view-transition-new(root) {
  z-index: 2;
  animation: theme-reveal-in 0.6s var(--ease) both;
}

html.theme-switching *,
html.theme-switching *::before,
html.theme-switching *::after {
  transition: none !important;
}

/* Fallback path (no View Transitions API): briefly transition every
   color-bound property so the whole page cross-fades between themes
   instead of snapping element by element */
html.theme-fade,
html.theme-fade *,
html.theme-fade *::before,
html.theme-fade *::after {
  transition:
    background-color 0.45s var(--ease),
    color 0.45s var(--ease),
    border-color 0.45s var(--ease),
    box-shadow 0.45s var(--ease),
    fill 0.45s var(--ease),
    stroke 0.45s var(--ease) !important;
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none !important; }
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; }
button { font: inherit; color: inherit; cursor: pointer; border: none; background: none; }
:focus-visible { outline: 2px solid var(--iris); outline-offset: 3px; border-radius: 4px; }

.mono { font-family: var(--font-mono); }

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

.skip-link {
  position: fixed; top: 10px; left: 10px; z-index: 2000;
  background: var(--surface); color: var(--ink);
  padding: 10px 16px; border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  transform: translateY(-150%); transition: transform var(--t-fast);
}
.skip-link:focus { transform: translateY(0); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--font-display); font-weight: 600;
  font-size: var(--step-0);
  padding: 13px 22px; border-radius: var(--radius-pill);
  transition: transform var(--t-fast), box-shadow var(--t-fast), background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
  white-space: nowrap;
}
.btn svg { transition: transform var(--t-fast); }
.btn--primary { background: var(--ink); color: var(--canvas); }
.btn--primary:hover { transform: translateY(-2px); box-shadow: var(--glow); }
.btn--primary:hover svg { transform: translateX(4px); }
.btn--ghost { border: 1px solid var(--line-strong); color: var(--ink); }
.btn--ghost:hover { border-color: var(--iris); color: var(--iris); transform: translateY(-2px); }
.btn--block { width: 100%; justify-content: center; }
.btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; box-shadow: none; }

/* ---------- Navigation ---------- */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 1000;
  transition: background var(--t), border-color var(--t), backdrop-filter var(--t), box-shadow var(--t);
  border-bottom: 1px solid transparent;
}
.nav.is-scrolled {
  background: color-mix(in srgb, var(--canvas) 95%, transparent);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border-bottom-color: var(--line-strong);
  box-shadow: 0 1px 24px -8px rgba(0, 0, 0, 0.25);
}
.nav__inner {
  max-width: var(--maxw); margin-inline: auto;
  padding: 16px var(--gutter);
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
}

.brand { display: inline-flex; align-items: center; gap: 9px; font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; }
.brand__node {
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--flow); box-shadow: 0 0 0 4px color-mix(in srgb, var(--iris) 22%, transparent);
  flex-shrink: 0;
}
.brand__name { color: var(--ink); letter-spacing: -0.01em; }
.brand__tag { font-family: var(--font-mono); font-size: 0.72rem; color: var(--ink-3); font-weight: 500; }

.nav__links { display: flex; gap: 6px; }
.nav__link {
  font-family: var(--font-display); font-weight: 500; font-size: 0.95rem;
  color: var(--ink-2); padding: 8px 14px; border-radius: var(--radius-pill);
  position: relative; transition: color var(--t-fast), background var(--t-fast);
}
.nav__link:hover { color: var(--ink); }
.nav__link.is-active { color: var(--ink); background: color-mix(in srgb, var(--iris) 12%, transparent); }

.nav__actions { display: flex; align-items: center; gap: 10px; }
.theme-toggle {
  display: grid; place-items: center; width: 40px; height: 40px;
  border-radius: 50%; border: 1px solid var(--line-strong); color: var(--ink-2);
  transition: color var(--t-fast), border-color var(--t-fast), transform var(--t-fast);
}
.theme-toggle:hover { color: var(--iris); border-color: var(--iris); transform: rotate(-12deg); }
.theme-toggle .icon-moon { display: none; }
[data-theme="light"] .theme-toggle .icon-sun { display: none; }
[data-theme="light"] .theme-toggle .icon-moon { display: block; }

/* ---------- Hero ---------- */
.hero { padding-top: clamp(120px, 18vh, 200px); padding-bottom: var(--section-y); position: relative; }
.hero__grid {
  display: grid; grid-template-columns: 1.15fr 0.85fr; gap: clamp(32px, 5vw, 72px);
  align-items: center;
}
.hero__text > * + * { margin-top: 22px; }

.pill {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--font-mono); font-size: 0.8rem; letter-spacing: 0.02em;
  color: var(--ink-2); padding: 7px 14px; border-radius: var(--radius-pill);
  border: 1px solid var(--line-strong); background: var(--surface);
}
.pill__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--cyan); position: relative; }
.pill__dot::after { content: ""; position: absolute; inset: -4px; border-radius: 50%; background: var(--cyan); opacity: 0.4; animation: ping 2s var(--ease) infinite; }
@keyframes ping { 0% { transform: scale(0.8); opacity: 0.5; } 80%, 100% { transform: scale(2.4); opacity: 0; } }

.hero__title {
  font-family: var(--font-display); font-weight: 700;
  font-size: var(--step-3); line-height: 0.98; letter-spacing: -0.03em; color: var(--ink);
}
.grad { background: var(--flow); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.grad::selection { -webkit-text-fill-color: #fff; background: rgba(99, 102, 241, 0.5); }
[data-theme="light"] .grad::selection { -webkit-text-fill-color: #131a27; }

.hero__role {
  font-family: var(--font-mono); font-size: var(--step-1); color: var(--ink); font-weight: 500;
  letter-spacing: -0.01em;
}
.hero__summary { max-width: 46ch; color: var(--ink-2); font-size: var(--step-0); }
.hero__summary strong { color: var(--ink); font-weight: 600; }

.hero__cta { display: flex; gap: 14px; flex-wrap: wrap; }

.hero__stats { display: grid; grid-template-columns: repeat(3, auto); gap: clamp(20px, 4vw, 48px); padding-top: 14px; margin-top: 34px; border-top: 1px solid var(--line); }
.stat__num { font-family: var(--font-display); font-weight: 700; font-size: clamp(1.7rem, 1.3rem + 1.6vw, 2.5rem); color: var(--ink); line-height: 1; letter-spacing: -0.02em; }
.stat__plus { color: var(--iris); }
.stat__label { font-size: var(--step--1); color: var(--ink-3); margin-top: 8px; max-width: 16ch; }

/* ---------- Hero pipeline (signature) ---------- */
.hero__pipeline { display: grid; place-items: center; }
.pipeline {
  position: relative; width: min(100%, 360px); aspect-ratio: 1; padding: 18px;
  border-radius: 24px; border: 1px solid var(--line);
  background:
    radial-gradient(var(--dot) 1px, transparent 1px) 0 0 / 22px 22px,
    var(--surface);
  box-shadow: var(--shadow);
}
.pipeline__cap {
  position: absolute; top: 14px; left: 16px;
  font-family: var(--font-mono); font-size: 0.72rem; color: var(--ink-3);
  display: inline-flex; align-items: center; gap: 7px;
}
.pipeline__cap .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--cyan); animation: blink 1.6s steps(2) infinite; }
@keyframes blink { 50% { opacity: 0.25; } }

.pipeline__wires { position: absolute; inset: 0; width: 100%; height: 100%; }
.wire { fill: none; stroke: var(--line-strong); stroke-width: 1.5; stroke-dasharray: 5 6; }

.node {
  position: absolute; left: var(--x); top: var(--y); transform: translate(-50%, -50%);
  background: var(--surface-2); border: 1px solid var(--line-strong);
  border-radius: 12px; padding: 9px 13px; min-width: 92px; text-align: center;
  box-shadow: 0 8px 22px -14px rgba(0,0,0,0.6);
}
.node__kind { display: block; font-family: var(--font-mono); font-size: 0.62rem; color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.08em; }
.node__label { display: block; font-family: var(--font-display); font-weight: 600; font-size: 0.95rem; color: var(--ink); }
.node--in { border-color: color-mix(in srgb, var(--iris) 55%, var(--line-strong)); }
.node--out { border-color: color-mix(in srgb, var(--cyan) 55%, var(--line-strong)); }
.node::before { content: ""; position: absolute; top: -4px; left: 50%; transform: translateX(-50%); width: 7px; height: 7px; border-radius: 50%; background: var(--iris); }
.node--in::before { display: none; }

.pulse {
  position: absolute; width: 9px; height: 9px; border-radius: 50%;
  background: var(--cyan); box-shadow: 0 0 12px 2px color-mix(in srgb, var(--cyan) 70%, transparent);
  offset-path: path("M160 56 C 100 56, 72 120, 72 152 L 72 196 C 72 232, 120 256, 160 256");
  /* fallback positioning handled in JS for browsers without offset-path */
  opacity: 0;
}
@supports (offset-path: path("M0 0")) {
  .pulse { animation: flow 3.4s linear infinite; opacity: 1; }
  @keyframes flow { 0% { offset-distance: 0%; } 100% { offset-distance: 100%; } }
}

/* ---------- Section scaffolding ---------- */
.section { padding-block: var(--section-y); }
.head { margin-bottom: clamp(32px, 5vw, 56px); }
.eyebrow {
  display: inline-block; font-family: var(--font-mono); font-size: 0.78rem;
  letter-spacing: 0.06em; color: var(--iris); margin-bottom: 14px;
}
.head__title {
  font-family: var(--font-display); font-weight: 700;
  font-size: var(--step-2); letter-spacing: -0.02em; color: var(--ink); line-height: 1.08;
}

/* ---------- About ---------- */
.about { display: grid; grid-template-columns: 1.3fr 0.7fr; gap: clamp(28px, 4vw, 56px); align-items: start; }
.ident { display: flex; align-items: center; gap: 16px; margin-bottom: 26px; }
.avatar {
  position: relative; flex-shrink: 0; width: 64px; height: 64px; border-radius: 18px;
  display: grid; place-items: center; overflow: hidden;
  background: var(--surface-2); border: 1px solid var(--line-strong);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--iris) 14%, transparent);
}
.avatar__mono { font-family: var(--font-display); font-weight: 700; font-size: 1.3rem; background: var(--flow); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.avatar__mono::selection { -webkit-text-fill-color: #fff; background: rgba(99, 102, 241, 0.5); }
.avatar img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ident__text { display: flex; flex-direction: column; gap: 3px; }
.ident__text strong { font-family: var(--font-display); font-weight: 700; font-size: var(--step-1); color: var(--ink); letter-spacing: -0.01em; }
.ident__role { font-size: 0.8rem; color: var(--iris); }
.about__lead > * + * { margin-top: 18px; }
.about__lead p { color: var(--ink-2); max-width: 56ch; font-size: var(--step-0); }
.about__lead strong { color: var(--ink); font-weight: 600; }
.about__loc { display: inline-flex; align-items: center; gap: 9px; font-size: var(--step--1); color: var(--ink-3) !important; }
.about__loc svg { color: var(--iris); flex-shrink: 0; }
.about__cards { display: grid; gap: 18px; }

/* ---------- Node card (reusable) ---------- */
.ncard, .scard, .xp {
  position: relative; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: clamp(20px, 3vw, 28px);
  transition: transform var(--t), border-color var(--t), box-shadow var(--t);
}
.ncard__port, .scard__port, .xp__port {
  position: absolute; top: 22px; left: -5px; width: 9px; height: 9px;
  border-radius: 50%; background: var(--canvas); border: 2px solid var(--iris);
}
.ncard:hover, .scard:hover { transform: translateY(-4px); border-color: var(--line-strong); box-shadow: var(--shadow); }
.ncard__h, .scard__h { font-family: var(--font-mono); font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-3); margin-bottom: 12px; }
.ncard__title { font-family: var(--font-display); font-weight: 600; font-size: var(--step-1); color: var(--ink); }
.ncard__sub { color: var(--ink-2); font-size: var(--step--1); margin-top: 4px; }
.ncard__meta { color: var(--ink-3); font-size: 0.76rem; margin-top: 12px; }
.ncard__list { display: grid; gap: 9px; }
.ncard__list li { position: relative; padding-left: 20px; color: var(--ink-2); font-size: var(--step--1); }
.ncard__list li::before { content: ""; position: absolute; left: 0; top: 0.62em; width: 7px; height: 7px; border-radius: 2px; background: var(--flow); }
/* Spotlight: the assistant scrolls to a card and flashes this to "show" it. */
.is-spotlit { border-color: var(--iris); box-shadow: 0 0 0 3px color-mix(in srgb, var(--iris) 30%, transparent), var(--glow); }

/* ---------- Experience ---------- */
.xp__head { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 16px; align-items: start; margin-bottom: 22px; padding-bottom: 22px; border-bottom: 1px solid var(--line); }
.xp__role { font-family: var(--font-display); font-weight: 700; font-size: var(--step-1); color: var(--ink); letter-spacing: -0.01em; }
.xp__org { color: var(--iris); font-weight: 500; margin-top: 3px; }
.xp__meta { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; text-align: right; }
.xp__place { font-size: 0.76rem; color: var(--ink-3); }
.chip { font-family: var(--font-mono); font-size: 0.76rem; color: var(--ink-2); padding: 5px 12px; border-radius: var(--radius-pill); border: 1px solid var(--line-strong); white-space: nowrap; }
.xp__points { display: grid; gap: 15px; }
.xp__points li { position: relative; padding-left: 26px; color: var(--ink-2); }
.xp__points li::before {
  content: ""; position: absolute; left: 0; top: 0.55em; width: 12px; height: 12px;
  border-radius: 3px; border: 2px solid var(--iris); background: var(--surface);
}
.xp__points strong { color: var(--ink); font-weight: 600; }

/* ---------- Grids ---------- */
.grid { display: grid; gap: 18px; }
.grid--projects { grid-template-columns: repeat(2, 1fr); }
.grid--skills { grid-template-columns: repeat(3, 1fr); }
.grid--certs { grid-template-columns: repeat(3, 1fr); }

/* ---------- Project card ---------- */
.pcard {
  position: relative; display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: clamp(22px, 3vw, 30px);
  overflow: hidden;
  transition: transform var(--t), border-color var(--t), box-shadow var(--t);
}
.pcard::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: var(--flow); transform: scaleX(0); transform-origin: left; transition: transform var(--t);
}
.pcard:hover { transform: translateY(-5px); border-color: var(--line-strong); box-shadow: var(--shadow); }
.pcard:hover::before { transform: scaleX(1); }
.pcard__top { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.pcard__index { color: var(--ink-3); font-size: 0.78rem; }
.pcard__date { margin-left: auto; color: var(--ink-3); font-size: 0.78rem; }
.badge { font-family: var(--font-mono); font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--cyan); padding: 3px 9px; border-radius: var(--radius-pill); border: 1px solid color-mix(in srgb, var(--cyan) 45%, var(--line)); }
.pcard__title { font-family: var(--font-display); font-weight: 700; font-size: var(--step-1); color: var(--ink); letter-spacing: -0.01em; line-height: 1.15; }
.pcard__desc { color: var(--ink-2); font-size: var(--step--1); margin-top: 12px; }
.pcard__desc strong { color: var(--ink); font-weight: 600; }
.pcard--featured { grid-column: span 2; }
.pcard__award { display: inline-flex; align-items: center; gap: 9px; margin-top: 16px; font-size: var(--step--1); color: var(--ink); font-weight: 500; }
.pcard__award svg { color: var(--cyan); flex-shrink: 0; }

.ports { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--line); }
.ports li { font-family: var(--font-mono); font-size: 0.74rem; color: var(--ink-2); padding: 5px 11px; border-radius: var(--radius-sm); background: var(--surface-2); border: 1px solid var(--line); position: relative; transition: color var(--t-fast), border-color var(--t-fast); }
.ports li:hover { color: var(--iris); border-color: color-mix(in srgb, var(--iris) 45%, var(--line)); }
.pcard__link { display: inline-flex; align-items: center; gap: 8px; margin-top: 18px; font-family: var(--font-display); font-weight: 600; font-size: 0.9rem; color: var(--iris); width: fit-content; transition: gap var(--t-fast); }
.pcard__link:hover { gap: 12px; }

/* ---------- Skill card ---------- */
.scard__k { color: var(--iris); margin-right: 6px; }
.tags { display: flex; flex-wrap: wrap; gap: 9px; }
.tags li {
  font-family: var(--font-display); font-weight: 500; font-size: 0.9rem; color: var(--ink);
  padding: 8px 14px; border-radius: var(--radius-pill); border: 1px solid var(--line-strong);
  background: var(--surface-2); transition: transform var(--t-fast), border-color var(--t-fast), color var(--t-fast), background var(--t-fast);
}
.tags li:hover { transform: translateY(-3px); border-color: var(--iris); color: var(--iris); }

/* ---------- Tech marquee (hero → about bridge) ---------- */
.marquee {
  position: relative;
  padding-block: clamp(26px, 4vw, 42px);
  border-block: 1px solid var(--line);
  background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--surface) 45%, transparent), transparent);
  overflow: hidden;
  /* fade the bars in/out at the edges */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}
.marquee__track {
  display: flex;
  width: max-content;
  animation: marquee-flow 42s linear infinite;
  will-change: transform;
}
/* four identical groups sit side by side; translating one full copy (-25%)
   loops seamlessly. Four copies (not two) so the three still-visible copies
   always cover the viewport — with only two, any screen wider than a single
   group showed an empty gap at the end of each cycle. */
.marquee__group { display: contents; }
/* keep the marquee flowing continuously — do not pause on hover/touch */
.marquee__track { animation-play-state: running !important; }

/* Keep the marquee flowing during the theme switch. The theme's view
   transition paints a static snapshot of the old page while the circular
   reveal runs, which visually freezes the marquee. Naming the marquee
   lifts it into its own capture layer: hiding the (frozen) old snapshot
   and cancelling the default cross-fade leaves the live new capture on
   screen the whole time, so the animation never stops. */
.marquee { view-transition-name: tech-marquee; }
::view-transition-old(tech-marquee) { display: none; }
::view-transition-new(tech-marquee) { animation: none; }
/* The marquee's capture layer paints above the page snapshot, so every
   fixed overlay that normally sits above the marquee (top nav, mobile
   quick-nav dock, album card, AI assistant) needs its own layer too —
   capture layers stack in document paint order, keeping these on top
   and static while the theme switches. */
.nav { view-transition-name: site-nav; }
.dock { view-transition-name: quick-dock; }
.album-fab { view-transition-name: album-fab; }
.ai-fab { view-transition-name: ai-fab; }
.ai-panel { view-transition-name: ai-panel; }
::view-transition-old(site-nav),
::view-transition-old(quick-dock),
::view-transition-old(album-fab),
::view-transition-old(ai-fab),
::view-transition-old(ai-panel) { display: none; }
::view-transition-new(site-nav),
::view-transition-new(quick-dock),
::view-transition-new(album-fab),
::view-transition-new(ai-fab),
::view-transition-new(ai-panel) { animation: none; }

.marquee__item {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-right: 16px;
  white-space: nowrap;
  padding: 12px 20px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  background: var(--surface);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--ink);
  transition: border-color var(--t-fast), color var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast);
}
/* brand logo, masked so it inherits currentColor and stays visible on both themes */
.marquee__icon {
  flex: none;
  width: 20px;
  height: 20px;
  background-color: currentColor;
  -webkit-mask: var(--logo) center / contain no-repeat;
          mask: var(--logo) center / contain no-repeat;
}
.marquee__item:hover {
  border-color: var(--iris);
  color: var(--iris);
  transform: translateY(-2px);
  box-shadow: var(--glow);
}

@keyframes marquee-flow {
  from { transform: translateX(0); }
  to   { transform: translateX(-25%); }
}

/* ---------- Certificate card ---------- */
.ccard { position: relative; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: clamp(22px, 3vw, 28px); transition: transform var(--t), border-color var(--t), box-shadow var(--t); }
.ccard:hover { transform: translateY(-4px); border-color: var(--line-strong); box-shadow: var(--shadow); }
.ccard__issuer { display: inline-block; font-size: 0.74rem; color: var(--cyan); letter-spacing: 0.04em; margin-bottom: 14px; padding: 4px 10px; border: 1px solid color-mix(in srgb, var(--cyan) 35%, var(--line)); border-radius: var(--radius-pill); }
.ccard__title { font-family: var(--font-display); font-weight: 600; font-size: var(--step-0); color: var(--ink); line-height: 1.3; }
.ccard__date { color: var(--ink-3); font-size: 0.76rem; margin-top: 12px; }

/* ---------- Contact ---------- */
.section--contact { padding-bottom: clamp(80px, 10vw, 140px); }
.contact { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: clamp(32px, 5vw, 64px); align-items: start; }
.contact__intro { color: var(--ink-2); max-width: 42ch; margin-bottom: 28px; }
.contact__methods { display: grid; gap: 12px; }
.contact__methods a { display: flex; align-items: center; gap: 14px; padding: 14px 16px; border-radius: var(--radius); border: 1px solid var(--line); background: var(--surface); transition: transform var(--t-fast), border-color var(--t-fast); }
.contact__methods a:hover { transform: translateX(4px); border-color: var(--iris); }
.cm__icon { display: grid; place-items: center; width: 42px; height: 42px; border-radius: 11px; background: var(--surface-2); color: var(--iris); flex-shrink: 0; }
.cm__text { display: flex; flex-direction: column; font-size: var(--step--1); color: var(--ink); word-break: break-word; }
.cm__k { font-family: var(--font-mono); font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.07em; color: var(--ink-3); }
.contact__social { margin-top: 28px; }
.socials { display: flex; gap: 12px; margin-top: 12px; }
.socials a { display: grid; place-items: center; width: 46px; height: 46px; border-radius: 13px; border: 1px solid var(--line-strong); color: var(--ink-2); transition: transform var(--t-fast), color var(--t-fast), border-color var(--t-fast); }
.socials a:hover { transform: translateY(-3px); color: var(--iris); border-color: var(--iris); }

/* ---------- Form ---------- */
.form { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: clamp(24px, 4vw, 36px); display: grid; gap: 18px; box-shadow: var(--shadow); }
.field { display: grid; gap: 7px; }
.field label { font-family: var(--font-mono); font-size: 0.76rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-2); }
.field input, .field textarea {
  font-family: var(--font-body); font-size: var(--step-0); color: var(--ink);
  background: var(--surface-2); border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); padding: 12px 14px; width: 100%;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.field textarea { resize: vertical; min-height: 120px; }
.field input::placeholder, .field textarea::placeholder { color: var(--ink-3); }
.field input:focus, .field textarea:focus { outline: none; border-color: var(--iris); box-shadow: 0 0 0 3px color-mix(in srgb, var(--iris) 18%, transparent); }
.field.is-invalid input, .field.is-invalid textarea { border-color: #f87171; }
.field__error { font-size: 0.76rem; color: #f87171; min-height: 1em; }

/* ---------- Footer ---------- */
.footer { border-top: 1px solid var(--line); padding-block: 48px 28px; margin-top: var(--section-y); }
.footer__inner { display: flex; flex-wrap: wrap; align-items: center; gap: 18px 32px; }
.footer__tag { color: var(--ink-3); font-size: var(--step--1); flex: 1 1 220px; }
.footer__links { display: flex; flex-wrap: wrap; gap: 18px; }
.footer__links a { color: var(--ink-2); font-size: var(--step--1); transition: color var(--t-fast); }
.footer__links a:hover { color: var(--iris); }
.footer__copy { color: var(--ink-3); font-size: 0.74rem; margin-top: 28px; padding-top: 24px; border-top: 1px solid var(--line); text-align: center; }

/* ---------- Alert ---------- */
.alert-overlay { position: fixed; inset: 0; z-index: 1500; display: grid; place-items: center; padding: 24px; background: color-mix(in srgb, var(--canvas-2) 75%, transparent); backdrop-filter: blur(8px); opacity: 0; transition: opacity var(--t); }
.alert-overlay[hidden] { display: none; }
.alert-overlay.is-open { opacity: 1; }
.alert { position: relative; width: min(440px, 100%); background: var(--surface); border: 1px solid var(--line-strong); border-radius: 22px; padding: 40px 32px 32px; text-align: center; box-shadow: var(--shadow); transform: scale(0.94) translateY(10px); transition: transform var(--t); }
.alert-overlay.is-open .alert { transform: scale(1) translateY(0); }
.alert__close { position: absolute; top: 16px; right: 16px; color: var(--ink-3); display: grid; place-items: center; width: 34px; height: 34px; border-radius: 50%; transition: color var(--t-fast), background var(--t-fast); }
.alert__close:hover { color: var(--ink); background: var(--surface-2); }
.alert__icon { display: grid; place-items: center; width: 64px; height: 64px; margin: 0 auto 18px; border-radius: 50%; }
.alert__icon.success { color: var(--cyan); background: color-mix(in srgb, var(--cyan) 14%, transparent); }
.alert__icon.error { color: #f87171; background: color-mix(in srgb, #f87171 14%, transparent); }
.alert__icon.warning { color: #fbbf24; background: color-mix(in srgb, #fbbf24 16%, transparent); }
.alert__title { font-family: var(--font-display); font-weight: 700; font-size: var(--step-1); color: var(--ink); margin-bottom: 10px; }
.alert__msg { color: var(--ink-2); font-size: var(--step--1); margin-bottom: 26px; }
.alert .btn { margin-inline: auto; }

/* ---------- Splash intro ----------
   AI boot sequence, hard-capped under 3s: a neural workflow constellation
   assembles on the canvas — the gradient core pops in and reaches out with
   six connectors, satellite nodes come online, data packets stream back
   along the wires and ignite the core (shockwave across the dot grid),
   the wordmark resolves out of the pulse, "/ Computer Science" types on,
   then the whole canvas lifts away like a panel behind a glowing scan
   edge. CSS owns the timeline with `forwards` fill so the overlay plays
   and hides itself even if JS never runs — script.js (initSplash) only
   choreographs the [data-reveal] handoff and removes the node afterwards.
   Every delay routes through --splash-t0 (0s in production) so a test
   harness can freeze the whole timeline at instant T with one variable.
   z-index 1900: above all page chrome, below the skip-link (2000) so a
   keyboard user's first Tab still surfaces "Skip to content". */
.splash {
  position: fixed; inset: 0; z-index: 1900;
  display: grid; place-items: center;
  overflow: hidden; /* clip the ignition shockwave */
  background-color: var(--canvas);
  background-image: radial-gradient(var(--dot) 1px, transparent 1px);
  background-size: 26px 26px;
  background-position: -13px -13px;
  box-shadow: 0 34px 70px -22px rgba(0, 0, 0, 0.55);
  will-change: transform;
  transition: background-color var(--t); /* soften the boot-time theme swap */
  animation: splash-exit 0.75s var(--ease) calc(var(--splash-t0, 0s) + 2.2s) forwards;
}
.splash::after { /* scan edge on the lifting panel's lower lip */
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--flow);
  box-shadow: 0 0 16px 1px var(--iris);
  opacity: 0;
  animation: splash-scan 0.75s var(--ease) calc(var(--splash-t0, 0s) + 2.2s) forwards;
}
.splash__inner {
  display: flex; flex-direction: column; align-items: center;
  gap: clamp(14px, 2.4vw, 20px);
  padding-inline: var(--gutter);
  /* Sinks slower than the panel lifts and blurs out — parallax depth */
  animation: splash-inner-exit 0.75s var(--ease) calc(var(--splash-t0, 0s) + 2.2s) forwards;
}

/* Constellation stage — the core sits at the exact center of the SVG box,
   so the shockwave (a sibling centered on the stage) emits from the core */
.splash__stage { position: relative; display: block; }
.splash__net {
  display: block;
  width: min(560px, 88vw); height: auto;
  overflow: visible;
}
.splash__stop-a { stop-color: var(--iris); }
.splash__stop-b { stop-color: var(--cyan); }

/* Connectors draw outward from the core (dashoffset 1 -> 0 with
   pathLength=1); non-scaling strokes keep them hairline at every width */
.splash__edge {
  stroke: var(--line-strong); stroke-width: 1;
  stroke-dasharray: 1; stroke-dashoffset: 1;
  animation: splash-draw 0.45s var(--ease) both;
}
.splash__edge:nth-child(1) { animation-delay: calc(var(--splash-t0, 0s) + 0.38s); }
.splash__edge:nth-child(2) { animation-delay: calc(var(--splash-t0, 0s) + 0.50s); }
.splash__edge:nth-child(3) { animation-delay: calc(var(--splash-t0, 0s) + 0.62s); }
.splash__edge:nth-child(4) { animation-delay: calc(var(--splash-t0, 0s) + 0.44s); }
.splash__edge:nth-child(5) { animation-delay: calc(var(--splash-t0, 0s) + 0.56s); }
.splash__edge:nth-child(6) { animation-delay: calc(var(--splash-t0, 0s) + 0.68s); }

/* Data packets: a short bright dash sweeps each wire from the satellite
   into the core. The dash period (0.14 + 1.86 = 2) must exceed the
   pathLength of 1 — with a period of exactly 1 the repeating pattern
   puts a second dash back on the wire, stranding glowing marks at the
   core before launch and at the satellites after arrival. */
.splash__packet {
  stroke: var(--cyan); stroke-width: 2.5; stroke-linecap: round;
  stroke-dasharray: 0.14 1.86; stroke-dashoffset: -1.02;
  filter: drop-shadow(0 0 5px var(--iris));
  animation: splash-packet 0.5s cubic-bezier(0.4, 0, 0.2, 1) both;
}
.splash__packet:nth-child(1) { animation-delay: calc(var(--splash-t0, 0s) + 0.95s); }
.splash__packet:nth-child(2) { animation-delay: calc(var(--splash-t0, 0s) + 1.05s); }
.splash__packet:nth-child(3) { animation-delay: calc(var(--splash-t0, 0s) + 1.15s); }
.splash__packet:nth-child(4) { animation-delay: calc(var(--splash-t0, 0s) + 1.00s); }
.splash__packet:nth-child(5) { animation-delay: calc(var(--splash-t0, 0s) + 1.10s); }
.splash__packet:nth-child(6) { animation-delay: calc(var(--splash-t0, 0s) + 1.20s); }

.splash__sat {
  fill: var(--iris); opacity: 0.8;
  transform-box: fill-box; transform-origin: center;
  animation: splash-pop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
.splash__sat:nth-child(1) { animation-delay: calc(var(--splash-t0, 0s) + 0.15s); }
.splash__sat:nth-child(2) { animation-delay: calc(var(--splash-t0, 0s) + 0.27s); }
.splash__sat:nth-child(3) { animation-delay: calc(var(--splash-t0, 0s) + 0.39s); }
.splash__sat:nth-child(4) { animation-delay: calc(var(--splash-t0, 0s) + 0.21s); }
.splash__sat:nth-child(5) { animation-delay: calc(var(--splash-t0, 0s) + 0.33s); }
.splash__sat:nth-child(6) { animation-delay: calc(var(--splash-t0, 0s) + 0.45s); }

.splash__core {
  fill: url(#splash-flow);
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--iris) 65%, transparent));
  transform-box: fill-box; transform-origin: center;
  animation:
    splash-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) calc(var(--splash-t0, 0s) + 0.05s) both,
    splash-ignite 0.55s var(--ease) calc(var(--splash-t0, 0s) + 1.45s) both;
}
.splash__ring { /* ping echo emitted twice at ignition */
  stroke: var(--iris); stroke-width: 1; opacity: 0;
  transform-box: fill-box; transform-origin: center;
  animation: splash-ring 0.5s var(--ease) calc(var(--splash-t0, 0s) + 1.45s) 2 forwards;
}
.splash__wave { /* ignition shockwave rolling across the dot grid */
  position: absolute; left: 50%; top: 50%;
  width: 900px; height: 900px; margin: -450px 0 0 -450px;
  border-radius: 50%;
  background: radial-gradient(circle,
    transparent 60%,
    color-mix(in srgb, var(--iris) 28%, transparent) 64%,
    transparent 68%);
  opacity: 0; transform: scale(0.05);
  pointer-events: none;
  animation: splash-wave 0.85s var(--ease) calc(var(--splash-t0, 0s) + 1.5s) forwards;
}

.splash__name {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(2.1rem, 1.4rem + 3.4vw, 3.4rem);
  line-height: 1.05; letter-spacing: -0.02em; color: var(--ink);
  white-space: nowrap;
  animation: splash-name-in 0.7s var(--ease) calc(var(--splash-t0, 0s) + 1.4s) both;
}

.splash__tag {
  /* Fixed 18ch box ("/ Computer Science") keeps the layout stable while
     the inner span types on left-to-right inside it */
  display: inline-flex; width: 18ch;
  font-family: var(--font-mono); font-size: 0.95rem; color: var(--ink-3);
}
.splash__tag-type {
  overflow: hidden; white-space: nowrap; max-width: 0;
  border-right: 1.5px solid transparent;
  animation:
    splash-type 0.65s steps(18, end) calc(var(--splash-t0, 0s) + 1.5s) both,
    splash-caret 0.5s linear calc(var(--splash-t0, 0s) + 1.5s) 2;
}

@keyframes splash-pop { from { transform: scale(0); } to { transform: scale(1); } }
@keyframes splash-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes splash-packet { from { stroke-dashoffset: -1.02; } to { stroke-dashoffset: 0.16; } }
@keyframes splash-ignite {
  0%   { transform: scale(1); filter: drop-shadow(0 0 6px color-mix(in srgb, var(--iris) 65%, transparent)); }
  45%  { transform: scale(1.5); filter: drop-shadow(0 0 16px var(--iris)); }
  100% { transform: scale(1); filter: drop-shadow(0 0 9px color-mix(in srgb, var(--iris) 80%, transparent)); }
}
@keyframes splash-ring {
  0%   { transform: scale(1); opacity: 0; }
  15%  { opacity: 0.45; }
  100% { transform: scale(2.4); opacity: 0; }
}
@keyframes splash-wave {
  0%   { transform: scale(0.05); opacity: 0; }
  18%  { opacity: 0.6; }
  100% { transform: scale(2.2); opacity: 0; }
}
@keyframes splash-name-in {
  from { opacity: 0; transform: translateY(22px); filter: blur(8px); letter-spacing: 0.08em; }
  to   { opacity: 1; transform: translateY(0); filter: blur(0); letter-spacing: -0.02em; }
}
@keyframes splash-type { from { max-width: 0; } to { max-width: 18ch; } }
@keyframes splash-caret {
  0%, 49% { border-right-color: var(--cyan); }
  50%, 100% { border-right-color: transparent; }
}
@keyframes splash-scan {
  from { opacity: 0; }
  30%, 100% { opacity: 1; }
}
@keyframes splash-exit {
  from { transform: translateY(0); }
  to   { transform: translateY(-100%); visibility: hidden; }
}
@keyframes splash-inner-exit {
  from { transform: translateY(0); opacity: 1; filter: blur(0); }
  to   { transform: translateY(15vh); opacity: 0; filter: blur(5px); }
}

/* Splash → hero handoff: while body.splash-handoff is set (initSplash
   removes it once the intro settles) the hero's reveals stagger, so the
   fold assembles as the splash lifts. Scroll reveals elsewhere unaffected. */
.splash-handoff .hero__text > [data-reveal]:nth-child(1) { transition-delay: 0.05s; }
.splash-handoff .hero__text > [data-reveal]:nth-child(2) { transition-delay: 0.12s; }
.splash-handoff .hero__text > [data-reveal]:nth-child(3) { transition-delay: 0.19s; }
.splash-handoff .hero__text > [data-reveal]:nth-child(4) { transition-delay: 0.26s; }
.splash-handoff .hero__text > [data-reveal]:nth-child(5) { transition-delay: 0.33s; }
.splash-handoff .hero__text > [data-reveal]:nth-child(6) { transition-delay: 0.4s; }
.splash-handoff .hero__photo[data-reveal] { transition-delay: 0.22s; }

/* The splash is pure decoration — reduced-motion users go straight to the page */
@media (prefers-reduced-motion: reduce) {
  .splash { display: none; }
}

/* ---------- Reveal animation ---------- */
[data-reveal] { opacity: 0; transform: translateY(26px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); }
[data-reveal].is-in { opacity: 1; transform: none; }

/* ---------- Responsive ---------- */
@media (max-width: 960px) {
  .about { grid-template-columns: 1fr; }
  .grid--skills, .grid--certs { grid-template-columns: 1fr 1fr; }
  .contact { grid-template-columns: 1fr; }
}

@media (max-width: 840px) {
  .nav__links { display: none; }

  .hero__grid { grid-template-columns: 1fr; }
  .hero__photo { display: none; }
}

@media (max-width: 720px) {
  .grid--projects { grid-template-columns: 1fr; }
  .pcard--featured { grid-column: span 1; }
  .grid--skills { grid-template-columns: 1fr; }
  .grid--certs { grid-template-columns: 1fr 1fr; }
  .hero__stats { gap: clamp(10px, 3vw, 32px); }
  .xp__head { flex-direction: column; }
  .xp__meta { align-items: flex-start; text-align: left; }
}

@media (max-width: 480px) {
  .grid--certs { grid-template-columns: 1fr; }
}

@media (max-width: 420px) {
  .brand__tag { display: none; }
}

@media (max-width: 375px) {
  .hero__title { letter-spacing: -0.02em; }
  .btn { padding: 11px 18px; }
  .contact__methods a { padding: 12px 12px; }
}

/* ---------- Mobile quick-nav dock (mobile only) ----------
   A thumb-zone tab bar that gives one-tap access to the key sections —
   including Contact at the very bottom — so visitors don't have to drag
   through the full page. Desktop never renders this (display:none below). */
.dock { display: none; }

@media (max-width: 768px) {
  /* Reserve space so the fixed dock never hides the last of the footer,
     and let in-page anchors land clear of the fixed header + dock. */
  body { padding-bottom: calc(62px + env(safe-area-inset-bottom, 0px)); }
  html {
    scroll-padding-top: 84px;
    scroll-padding-bottom: calc(74px + env(safe-area-inset-bottom, 0px));
  }

  .dock {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 800;
    display: block;
    padding-bottom: env(safe-area-inset-bottom, 0px);
    background: color-mix(in srgb, var(--canvas) 88%, transparent);
    backdrop-filter: blur(18px) saturate(120%);
    -webkit-backdrop-filter: blur(18px) saturate(120%);
    border-top: 1px solid var(--line-strong);
    box-shadow: 0 -10px 30px -18px rgba(0, 0, 0, 0.55);
    transition: transform var(--t);
  }

  /* Slide the dock away while the slide-in drawer is open (kept above the
     backdrop fallback for browsers without :has). */
  body:has(#navLinks.is-open) .dock { transform: translateY(130%); }

  .dock__inner {
    max-width: var(--maxw); margin-inline: auto;
    display: flex; align-items: stretch; justify-content: space-around;
    padding-inline: 4px;
  }

  .dock__item {
    flex: 1 1 0; position: relative;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 5px; min-height: 58px; padding: 8px 4px;
    color: var(--ink-3);
    transition: color var(--t-fast), transform var(--t-fast);
    -webkit-tap-highlight-color: transparent;
  }
  .dock__item svg { width: 22px; height: 22px; flex-shrink: 0; }
  .dock__label {
    font-family: var(--font-body); font-weight: 500;
    font-size: 0.62rem; letter-spacing: 0.04em; text-transform: uppercase; line-height: 1;
  }

  /* Workflow-canvas tab indicator: a flow-gradient node bar above the active item */
  .dock__item::before {
    content: ""; position: absolute; top: 0; left: 50%;
    width: 26px; height: 3px; border-radius: 0 0 3px 3px;
    background: var(--flow);
    transform: translateX(-50%) scaleX(0); transform-origin: center;
    transition: transform var(--t-fast);
  }
  .dock__item:active { transform: scale(0.92); }
  .dock__item.is-active { color: var(--ink); }
  .dock__item.is-active::before { transform: translateX(-50%) scaleX(1); }
  .dock__item.is-active svg {
    filter: drop-shadow(0 0 8px color-mix(in srgb, var(--iris) 60%, transparent));
  }
}

/* Don't let the bar eat scarce vertical space in short landscape viewports */
@media (max-width: 768px) and (orientation: landscape) and (max-height: 460px) {
  .dock { display: none; }
  body { padding-bottom: 0; }
}

/* ---------- Tablet portrait: keep the nav in the header ----------
   Between 700–840px (iPad mini/Air/Pro portrait, Android tablets) the desktop
   links were hidden but the dock only covers ≤768px, so navigation vanished.
   Show a compact link row in the header and let it replace the dock. */
@media (min-width: 700px) and (max-width: 840px) {
  .nav__inner { gap: 12px; }
  .nav__links { display: flex; gap: 2px; }
  .nav__link { font-size: 0.85rem; padding: 7px 9px; }
  .brand__tag { display: none; }

  .dock { display: none; }
  body { padding-bottom: 0; }
  html { scroll-padding-top: 84px; scroll-padding-bottom: 0; }
}

/* ---------- Touch devices ----------
   No cursor means :hover never fires, so every motion effect would be
   invisible on phones/tablets. Mirror the hover states on :active so taps
   get the same transitions on any device, portrait or landscape. */
@media (hover: none) {
  .btn--primary:active { transform: translateY(-2px); box-shadow: var(--glow); }
  .btn--primary:active svg { transform: translateX(4px); }
  .btn--ghost:active { border-color: var(--iris); color: var(--iris); transform: translateY(-2px); }
  .theme-toggle:active { color: var(--iris); border-color: var(--iris); transform: rotate(-12deg); }
  .ncard:active, .scard:active, .ccard:active { transform: translateY(-4px); border-color: var(--line-strong); box-shadow: var(--shadow); }
  .pcard:active { transform: translateY(-5px); border-color: var(--line-strong); box-shadow: var(--shadow); }
  .pcard:active::before { transform: scaleX(1); }
  .tags li:active { transform: translateY(-3px); border-color: var(--iris); color: var(--iris); }
  .ports li:active { color: var(--iris); border-color: color-mix(in srgb, var(--iris) 45%, var(--line)); }
  .marquee__item:active { border-color: var(--iris); color: var(--iris); transform: translateY(-2px); box-shadow: var(--glow); }
  .contact__methods a:active { transform: translateX(4px); border-color: var(--iris); }
  .socials a:active { transform: translateY(-3px); color: var(--iris); border-color: var(--iris); }
  .footer__links a:active { color: var(--iris); }
}

/* ---------- Print ---------- */
@media print {
  .splash, .nav, .dock, .hero__pipeline, .theme-toggle, .footer, .contact__form-wrap, .alert-overlay, .album-fab, .album-overlay { display: none !important; }
  body { background: #fff; color: #000; }
  [data-reveal] { opacity: 1; transform: none; }
}


html, body {
  -webkit-user-select: none; /* Safari, Chrome, and iOS Safari */
  -moz-user-select: none;    /* Firefox Mobile and Desktop */
  -ms-user-select: none;     /* IE 10+ and Edge Legacy */
  user-select: none;         /* Standard syntax (Chrome, Edge, Opera) */
}

/* ---------- Memories album: floating trigger card ----------
   A node-style card pinned to the right edge. Desktop/tablet: vertically
   centered vertical card. Mobile (≤768px): compact horizontal pill above
   the quick-nav dock. */
.album-fab {
  position: fixed; right: 14px; top: 50%; z-index: 900;
  transform: translateY(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 14px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  transition: transform var(--t-fast), border-color var(--t-fast), box-shadow var(--t-fast);
}
.album-fab:hover { transform: translateY(calc(-50% - 4px)); border-color: var(--line-strong); box-shadow: var(--glow); }

.album-fab__stack { position: relative; width: 64px; height: 46px; }
.album-fab__layer {
  position: absolute; inset: 0; border-radius: 8px;
  border: 1px solid var(--line-strong); background: var(--surface-2);
}
.album-fab__layer:nth-child(1) { transform: rotate(-6deg); }
.album-fab__layer:nth-child(2) { transform: rotate(4deg); }
.album-fab__thumb {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; border-radius: 8px; border: 1px solid var(--line-strong);
}

.album-fab__text { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.album-fab__title { font-family: var(--font-display); font-weight: 600; font-size: 0.82rem; color: var(--ink); line-height: 1.2; }
.album-fab__count { font-size: 0.62rem; color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.06em; }

/* Mobile: compact pill docked above the quick-nav bar */
@media (max-width: 768px) {
  .album-fab {
    top: auto; right: 12px;
    bottom: calc(74px + env(safe-area-inset-bottom, 0px));
    transform: none;
    flex-direction: row; gap: 10px;
    padding: 8px 14px 8px 8px;
    border-radius: var(--radius-pill);
  }
  .album-fab:hover { transform: none; }
  .album-fab__stack { width: 44px; height: 32px; }
  .album-fab__text { align-items: flex-start; }
}

/* 700–768px: the tablet-portrait rule hides the dock, so drop to the corner */
@media (min-width: 700px) and (max-width: 768px) {
  .album-fab { bottom: 16px; }
}

/* Short landscape phones: dock is hidden here too */
@media (max-width: 768px) and (orientation: landscape) and (max-height: 460px) {
  .album-fab { bottom: 12px; }
}

/* Touch devices: mirror hover on tap, like the rest of the cards */
@media (hover: none) {
  .album-fab:active { border-color: var(--line-strong); box-shadow: var(--glow); }
}

/* ---------- Memories album: slideshow overlay ----------
   Same modal pattern as the alert dialog: [hidden] + .is-open fade,
   blurred canvas backdrop, node-card panel. z-index 1400 sits above the
   dock (800) and nav (1000) but below the alert (1500). */
.album-overlay {
  position: fixed; inset: 0; z-index: 1400;
  display: grid; place-items: center;
  padding: clamp(12px, 3vw, 32px);
  background: color-mix(in srgb, var(--canvas-2) 82%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  opacity: 0; transition: opacity var(--t);
}
.album-overlay[hidden] { display: none; }
.album-overlay.is-open { opacity: 1; }

.album {
  position: relative;
  width: min(1080px, 100%);
  max-height: 100%;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 22px;
  padding: clamp(16px, 3vw, 28px);
  box-shadow: var(--shadow);
  transform: scale(0.94) translateY(10px);
  transition: transform var(--t);
}
.album-overlay.is-open .album { transform: none; }

.album__close {
  position: absolute; top: 14px; right: 14px; z-index: 1;
  display: grid; place-items: center;
  width: 34px; height: 34px; border-radius: 50%;
  color: var(--ink-3);
  transition: color var(--t-fast), background var(--t-fast);
}
.album__close:hover { color: var(--ink); background: var(--surface-2); }

.album__title {
  font-family: var(--font-display); font-weight: 600; font-size: var(--step-1);
  color: var(--ink); margin-bottom: 14px; padding-right: 44px;
}
.album__eyebrow {
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--ink-3); margin-right: 8px;
}

.album__viewport { overflow: hidden; border-radius: var(--radius-sm); touch-action: pan-y; }
.album__track { display: flex; transition: transform var(--t); }

.album__slide {
  flex: 0 0 100%; min-width: 0;
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(10px, 2vw, 18px);
}

/* Landscape-only frames: portrait photos get cover-cropped */
.album__frame {
  aspect-ratio: 3 / 2;
  overflow: hidden; border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-2);
}
.album__frame img { width: 100%; height: 100%; object-fit: cover; }

.album__controls { display: flex; align-items: center; justify-content: center; gap: 18px; margin-top: 16px; }
.album__nav {
  display: grid; place-items: center;
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  color: var(--ink-2);
  transition: color var(--t-fast), border-color var(--t-fast), opacity var(--t-fast);
}
.album__nav:hover:not(:disabled) { color: var(--iris); border-color: var(--iris); }
.album__nav:disabled { opacity: 0.35; cursor: default; }

.album__dots { display: flex; gap: 9px; }
.album__dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--line-strong);
  transition: background var(--t-fast), transform var(--t-fast);
}
.album__dot.is-active { background: var(--iris); transform: scale(1.3); }

/* Portrait phones: stack the two landscape frames vertically */
@media (max-width: 640px) and (orientation: portrait) {
  .album__slide { grid-template-columns: 1fr; }
}

/* Short landscape phones: cap the panel width so both photos AND the
   prev/dots/next controls fit on screen without scrolling the panel */
@media (orientation: landscape) and (max-height: 500px) {
  .album { width: min(100%, calc((100vh - 160px) * 3)); }
  .album__title { margin-bottom: 10px; }
  .album__controls { margin-top: 10px; }
}

html {
  -webkit-tap-highlight-color: transparent;
}

a, button, input, textarea,
.btn, .theme-toggle, .nav__link, .dock__item,
.tags li, .ports li, .socials a, .contact__methods a,
.pcard, .ncard, .scard, .ccard, .marquee__item {
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}