/* ==========================================================================
   MONISH YEMUL - PORTFOLIO STYLESHEET
   Data Analyst - Archibus & IWMS
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,400&family=JetBrains+Mono:wght@400;500;600;700&display=swap');

:root {
  /* Color Palette - Dark Mode (Default) */
  --bg-primary: #08070d;
  --bg-secondary: #100e18;
  --bg-card: rgba(255, 255, 255, 0.032);
  --bg-card-hover: rgba(255, 255, 255, 0.06);
  --bg-glass: rgba(10, 9, 16, 0.82);
  --bg-footer: #060509;
  --bg-input: rgba(255, 255, 255, 0.02);
  --bg-pill: rgba(255, 255, 255, 0.045);
  
  --border-color: rgba(255, 255, 255, 0.09);
  --border-highlight: rgba(6, 182, 212, 0.35);

  /* v2 tokens — see the design-system block at the end of this file. */
  --wash-color: rgba(124, 58, 237, 0.20);
  --display-glow: rgba(255, 255, 255, 0.10);
  --pill-solid-bg: #f4f4f5;
  --pill-solid-hover: #ffffff;
  --pill-solid-text: #0b0a10;
  
  --text-primary: #f3f4f6;
  --text-secondary: #9ca3af;
  --text-muted: #6b7280;
  --text-heading: #ffffff;
  
  --accent-cyan: #06b6d4;
  --accent-indigo: #6366f1;
  --accent-emerald: #10b981;
  --accent-amber: #f59e0b;
  --accent-purple: #8b5cf6;
  
  --badge-cyan-bg: rgba(6, 182, 212, 0.1);
  --badge-cyan-text: #22d3ee;
  --badge-cyan-border: rgba(6, 182, 212, 0.3);
  
  --badge-amber-bg: rgba(245, 158, 11, 0.12);
  --badge-amber-text: #fbbf24;
  --badge-amber-border: rgba(245, 158, 11, 0.35);
  
  --gradient-brand: linear-gradient(135deg, #06b6d4 0%, #3b82f6 50%, #6366f1 100%);
  --gradient-accent: linear-gradient(135deg, #10b981 0%, #06b6d4 100%);
  --gradient-gold: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
  
  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 8px 30px rgba(0, 0, 0, 0.5);
  --shadow-glow: 0 0 25px rgba(6, 182, 212, 0.25);
  --shadow-gold-glow: 0 0 25px rgba(245, 158, 11, 0.25);

  /* Avatar ring glow. Two tokens, not one hardcoded shadow, because the
     hero entrance blooms the ring and has to settle on the RESTING value —
     and that resting value differs per theme. */
  --avatar-shadow-rest: 0 0 45px rgba(6, 182, 212, 0.3);
  --avatar-shadow-peak: 0 0 80px rgba(6, 182, 212, 0.6);
  
  --font-main: 'Plus Jakarta Sans', sans-serif;
  --font-mono: 'JetBrains Mono', monospace;
}

/* Light Theme Variables */
body.light-theme {
  --bg-primary: #f8fafc;
  --bg-secondary: #ffffff;
  --bg-card: #ffffff;
  --bg-card-hover: #f1f5f9;
  --bg-glass: rgba(255, 255, 255, 0.95);
  --bg-footer: #e2e8f0;
  --bg-input: #ffffff;
  --bg-pill: #e2e8f0;
  
  --border-color: #e2e8f0;
  --border-highlight: rgba(6, 182, 212, 0.6);

  --wash-color: rgba(124, 58, 237, 0.10);
  --display-glow: rgba(15, 23, 42, 0.06);
  --pill-solid-bg: #0f172a;
  --pill-solid-hover: #1e293b;
  --pill-solid-text: #ffffff;
  
  --text-primary: #0f172a;
  --text-secondary: #334155;
  --text-muted: #64748b;
  --text-heading: #0f172a;
  
  --accent-cyan: #0284c7;
  --accent-indigo: #4338ca;
  --accent-emerald: #059669;
  --accent-amber: #b45309;
  
  --badge-cyan-bg: #e0f2fe;
  --badge-cyan-text: #0369a1;
  --badge-cyan-border: #7dd3fc;
  
  --badge-amber-bg: #fef3c7;
  --badge-amber-text: #92400e;
  --badge-amber-border: #fcd34d;
  
  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.04);
  --shadow-md: 0 10px 30px rgba(0, 0, 0, 0.08);
  --shadow-glow: 0 0 25px rgba(6, 182, 212, 0.15);

  --avatar-shadow-rest: 0 12px 40px rgba(2, 132, 199, 0.18);
  --avatar-shadow-peak: 0 16px 64px rgba(2, 132, 199, 0.38);
}

/* Base Reset & Typography */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  /* The 80px header is fixed, so an un-offset anchor jump parks the target
     section under it. This also fixes where keyboard focus lands. */
  scroll-padding-top: 6rem;
  font-family: var(--font-main);
  background-color: var(--bg-primary);
  color: var(--text-primary);
  transition: background-color 0.3s ease, color 0.3s ease;
}

body {
  overflow-x: hidden;
  line-height: 1.6;
  background-color: var(--bg-primary) !important;
  color: var(--text-primary) !important;
  transition: background-color 0.3s ease, color 0.3s ease;
}

/* Custom Scrollbar */
::-webkit-scrollbar {
  width: 8px;
}
::-webkit-scrollbar-track {
  background: var(--bg-primary);
}
::-webkit-scrollbar-thumb {
  background: #374151;
  border-radius: 4px;
}
body.light-theme ::-webkit-scrollbar-thumb {
  background: #cbd5e1;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--accent-cyan);
}

/* Glassmorphism Effect */
.glass-card {
  background: var(--bg-card);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--border-color);
  border-radius: 1rem;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.glass-card:hover {
  border-color: var(--border-highlight);
  box-shadow: var(--shadow-glow);
  transform: translateY(-3px);
}

/* --------------------------------------------------------------------------
   ROUTE CARDS - the three "where do you want to go" cards under the hero.
   Row on phones so three cards read as a short list rather than three tall
   blocks to scroll past; column from md up, where there is width for it.
   -------------------------------------------------------------------------- */
.route-card {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding: 1.125rem 1.25rem;
  background: var(--bg-card);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--border-color);
  border-radius: 1rem;
  text-decoration: none;
  transition: border-color 0.3s ease, box-shadow 0.3s ease, transform 0.3s ease;
}

/* Per-card accent as a variable, so one hover rule serves all three and light
   mode needs no separate override. */
.route-cyan    { --route-accent: rgba(6, 182, 212, 0.5); }
.route-emerald { --route-accent: rgba(16, 185, 129, 0.5); }
.route-indigo  { --route-accent: rgba(99, 102, 241, 0.5); }

.route-card:hover {
  border-color: var(--route-accent, var(--border-highlight));
  box-shadow: var(--shadow-glow);
  transform: translateY(-3px);
}

.route-icon {
  flex-shrink: 0;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 0.875rem;
  border: 1px solid;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.05rem;
}

.route-body {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 0; /* lets long words wrap instead of widening the grid column */
}

.route-title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-heading);
  line-height: 1.35;
}

.route-text {
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--text-secondary);
}

.route-link {
  font-size: 0.875rem;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.1rem;
}

.route-link i {
  font-size: 0.75rem;
  transition: transform 0.25s ease;
}

.route-card:hover .route-link i {
  transform: translateX(3px);
}

@media (min-width: 768px) {
  .route-card {
    flex-direction: column;
    gap: 0.875rem;
    padding: 1.5rem;
  }
}

.glass-nav {
  background: var(--bg-glass);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-bottom: 1px solid var(--border-color);
}

/* Gradient Text Utilities */
.text-gradient {
  background: var(--gradient-brand);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.text-gradient-emerald {
  background: var(--gradient-accent);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.text-gradient-gold {
  background: var(--gradient-gold);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* Glowing Border for Profile & Hero */
/* Circular portrait: a gradient ring wrapping the photo.
   The padding is the visible ring thickness; both the wrapper and the image
   are fully rounded so the ring reads as a clean circle. */
.avatar-glow {
  position: relative;
  display: block;
  border-radius: 50%;
  padding: 5px;
  background: linear-gradient(135deg, #06b6d4, #6366f1, #10b981);
  box-shadow: var(--avatar-shadow-rest);
}

body.light-theme .avatar-glow {
  background: linear-gradient(135deg, #0284c7, #4f46e5, #059669);
}

/* Circular window that clips the photo, sitting inside the gradient ring. */
.avatar-clip {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  overflow: hidden;
  background-color: #ffffff; /* matches the photo's studio backdrop while loading */
}


.avatar-glow img {
  display: block;
  object-fit: cover;

  /*
   * Framing, measured against the real 681x1024 photo (head top at 7.6%,
   * shoulder line at 38.2%, subject horizontally centred):
   *
   * - A square crop discards ~33% of the height, and the face sits in the top
   *   third, so the crop is pulled to the top. Anything lower decapitates him.
   * - At 1:1 he fills only about half the circle, leaving a lot of studio
   *   white, so the image is scaled to 115% and pulled back by half the
   *   overflow (-7.5%) to stay centred. .avatar-clip cuts the excess.
   * - max-width:none is REQUIRED. Tailwind Preflight applies
   *   `img { max-width: 100% }`, which silently clamped the width while the
   *   height still grew — the box came out 342x417 instead of 417x417 and
   *   shoved him left, leaving a white gap down the right of the circle.
   *
   * Re-measure if the photo is ever replaced.
   */
  max-width: none;
  width: 108%;
  height: 108%;
  margin-left: -4%;
  margin-top: -4%;
  object-position: 50% 0%;
}

/* Interactive Badges */
.badge-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.85rem;
  border-radius: 9999px;
  font-size: 0.825rem;
  font-weight: 600;
  border: 1px solid var(--border-color);
  background: var(--bg-pill);
}

.badge-cyan {
  background: var(--badge-cyan-bg);
  color: var(--badge-cyan-text);
  border-color: var(--badge-cyan-border);
}

.badge-onsite {
  background: var(--badge-amber-bg);
  border-color: var(--badge-amber-border);
  color: var(--badge-amber-text);
  box-shadow: var(--shadow-gold-glow);
  animation: pulse-gold 3s infinite;
}

@keyframes pulse-gold {
  0%, 100% {
    box-shadow: 0 0 15px rgba(245, 158, 11, 0.2);
  }
  50% {
    box-shadow: 0 0 28px rgba(245, 158, 11, 0.45);
  }
}

/* Tech Pill Badges */
.tech-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0.25rem 0.65rem;
  border-radius: 0.375rem;
  background: rgba(6, 182, 212, 0.1);
  color: #22d3ee;
  border: 1px solid rgba(6, 182, 212, 0.25);
  transition: all 0.2s ease;
}

body.light-theme .tech-tag {
  background: #f0fdf4;
  color: #0369a1;
  border: 1px solid #bae6fd;
}

.tech-tag:hover {
  transform: translateY(-1px);
}

/* Custom Buttons */
.btn-primary {
  background: var(--gradient-brand);
  color: #ffffff !important;
  font-weight: 600;
  padding: 0.75rem 1.75rem;
  border-radius: 0.75rem;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  transition: all 0.3s ease;
  box-shadow: 0 4px 15px rgba(6, 182, 212, 0.3);
  text-decoration: none;
  border: none;
  cursor: pointer;
}

.btn-primary:hover {
  box-shadow: 0 6px 25px rgba(6, 182, 212, 0.5);
  transform: translateY(-2px);
}

.btn-secondary {
  background: var(--bg-card);
  color: var(--text-primary);
  border: 1px solid var(--border-color);
  font-weight: 600;
  padding: 0.75rem 1.75rem;
  border-radius: 0.75rem;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  transition: all 0.3s ease;
  text-decoration: none;
  cursor: pointer;
}

.btn-secondary:hover {
  background: var(--bg-card-hover);
  border-color: var(--border-highlight);
  color: var(--accent-cyan);
  transform: translateY(-2px);
}


/* Modal Popup Styles */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.75);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
  padding: 1.5rem;
}

.modal-backdrop.active {
  opacity: 1;
  pointer-events: auto;
}

.modal-content {
  background: var(--bg-secondary);
  border: 1px solid var(--border-highlight);
  border-radius: 1.25rem;
  width: 100%;
  max-width: 800px;
  max-height: 90vh;
  overflow-y: auto;
  box-shadow: var(--shadow-md);
  transform: scale(0.95) translateY(20px);
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.modal-backdrop.active .modal-content {
  transform: scale(1) translateY(0);
}

/* Toast Notifications */
.toast-container {
  position: fixed;
  bottom: 2rem;
  right: 2rem;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.toast {
  background: var(--bg-card);
  border: 1px solid var(--accent-cyan);
  backdrop-filter: blur(12px);
  color: var(--text-primary);
  padding: 0.85rem 1.25rem;
  border-radius: 0.75rem;
  box-shadow: var(--shadow-glow);
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.9rem;
  animation: slideInRight 0.3s ease forwards;
}

@keyframes slideInRight {
  from {
    transform: translateX(100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

/* Animated Gradient Orbs
   position:fixed, not absolute: an absolutely-positioned element resolves
   against the viewport, so body{overflow-x:hidden} never clipped these and
   the orb at right:-150px pushed the whole page 150px wider than the screen. */
/* The orbs live inside a fixed, clipping layer rather than being fixed
   themselves.
   ⚠️ body { overflow-x: hidden } does NOT clip a position: fixed child — it is
   laid out against the viewport and escapes the body entirely, so
   .glow-orb-purple at right: -150px widened the document by 3px at 320px.
   Clipping at the html level fixes that but breaks the scroll-reveal system
   (80 elements stayed invisible), so the clip belongs here, on a wrapper that
   owns nothing but decoration. */
.glow-layer {
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

.glow-orb {
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  opacity: 0.25;
  pointer-events: none;
  z-index: 0;
  transition: opacity 0.3s ease;
}

.glow-orb-cyan {
  width: 400px;
  height: 400px;
  background: #06b6d4;
  top: 10%;
  left: -100px;
}

.glow-orb-purple {
  width: 450px;
  height: 450px;
  background: #6366f1;
  top: 40%;
  right: -150px;
}

.glow-orb-gold {
  width: 350px;
  height: 350px;
  background: #f59e0b;
  bottom: 20%;
  left: 20%;
  opacity: 0.15;
}

/* ==========================================================================
   EXPLICIT LIGHT THEME OVERRIDES (High Contrast, Pixel-Perfect)
   ========================================================================== */

body.light-theme {
  background-color: #f8fafc !important;
  color: #0f172a !important;
}

body.light-theme .glow-orb {
  opacity: 0.08 !important;
}

/* Light Theme Navigation */
body.light-theme .glass-nav {
  background: rgba(255, 255, 255, 0.96) !important;
  border-color: #e2e8f0 !important;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.04);
}

body.light-theme .nav-link {
  color: #334155 !important;
  font-weight: 600;
}

body.light-theme .nav-link:hover,
body.light-theme .nav-link.text-cyan-400 {
  color: #0284c7 !important;
}

body.light-theme #theme-toggle,
body.light-theme #mobile-menu-btn,
body.light-theme #palette-trigger {
  background-color: #f1f5f9 !important;
  border-color: #cbd5e1 !important;
  color: #0f172a !important;
}

body.light-theme #theme-toggle:hover,
body.light-theme #palette-trigger:hover {
  color: #0284c7 !important;
  border-color: #0284c7 !important;
}


/* Light Theme Typography Overrides */
body.light-theme h1,
body.light-theme h2,
body.light-theme h3,
body.light-theme h4,
body.light-theme .text-white {
  color: #0f172a !important;
}

body.light-theme .text-gray-100 {
  color: #0f172a !important;
}

body.light-theme .text-gray-200 {
  color: #1e293b !important;
}

body.light-theme .text-gray-300 {
  color: #334155 !important;
}

body.light-theme .text-gray-400 {
  color: #475569 !important;
}

body.light-theme .text-gray-500 {
  color: #64748b !important;
}

body.light-theme .text-gray-600 {
  color: #64748b !important;
}

/* Light Theme Hero Special Overrides */
body.light-theme #typewriter-text {
  color: #0284c7 !important;
  border-color: #0284c7 !important;
}

body.light-theme .text-cyan-400 {
  color: #0369a1 !important;
}

body.light-theme .text-indigo-400 {
  color: #4338ca !important;
}

body.light-theme .text-emerald-400 {
  color: #047857 !important;
}

body.light-theme .text-amber-400 {
  color: #b45309 !important;
}

body.light-theme .text-purple-400 {
  color: #6d28d9 !important;
}

/* Light Theme Badges & Pills */
body.light-theme .badge-pill {
  background: #e0f2fe !important;
  color: #0369a1 !important;
  border: 1px solid #7dd3fc !important;
}

body.light-theme .badge-cyan,
body.light-theme .bg-cyan-500\/10 {
  background-color: #e0f2fe !important;
  color: #0369a1 !important;
}

body.light-theme .border-cyan-500\/30,
body.light-theme .border-cyan-500\/20 {
  border-color: #7dd3fc !important;
}

body.light-theme .badge-onsite {
  background: #fef3c7 !important;
  color: #92400e !important;
  border: 1px solid #fcd34d !important;
  box-shadow: 0 0 15px rgba(245, 158, 11, 0.15) !important;
}

body.light-theme .bg-amber-500\/10,
body.light-theme .bg-amber-500\/20 {
  background-color: #fef3c7 !important;
  color: #92400e !important;
}

body.light-theme .border-amber-500\/30,
body.light-theme .border-amber-500\/40,
body.light-theme .border-amber-500\/20 {
  border-color: #fcd34d !important;
}

body.light-theme .bg-indigo-500\/10,
body.light-theme .bg-indigo-600\/10 {
  background-color: #e0e7ff !important;
  color: #4338ca !important;
}

body.light-theme .border-indigo-500\/20,
body.light-theme .border-indigo-500\/30,
body.light-theme .border-indigo-500\/40 {
  border-color: #c7d2fe !important;
}

body.light-theme .bg-emerald-500\/10,
body.light-theme .bg-emerald-600\/10 {
  background-color: #d1fae5 !important;
  color: #047857 !important;
}

body.light-theme .border-emerald-500\/20,
body.light-theme .border-emerald-500\/30,
body.light-theme .border-emerald-500\/40 {
  border-color: #6ee7b7 !important;
}

body.light-theme .border-purple-500\/20,
body.light-theme .border-purple-500\/30,
body.light-theme .border-purple-500\/40 {
  border-color: #d8b4fe !important;
}

body.light-theme .bg-blue-500\/10,
body.light-theme .bg-blue-600\/10 {
  background-color: #dbeafe !important;
  color: #1d4ed8 !important;
}

body.light-theme .bg-purple-500\/10 {
  background-color: #f3e8ff !important;
  color: #6d28d9 !important;
}

body.light-theme .bg-red-500\/10 {
  background-color: #fee2e2 !important;
  color: #b91c1c !important;
}

body.light-theme .bg-orange-500\/10 {
  background-color: #ffedd5 !important;
  color: #c2410c !important;
}

body.light-theme .bg-yellow-500\/10 {
  background-color: #fef9c3 !important;
  color: #854d0e !important;
}

/* Light Theme Cards & Containers */
body.light-theme .glass-card {
  background: #ffffff !important;
  border-color: #e2e8f0 !important;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05) !important;
}

body.light-theme .route-card {
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05) !important;
}

body.light-theme .route-card:hover {
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1) !important;
}

body.light-theme .glass-card:hover {
  border-color: #0284c7 !important;
  box-shadow: 0 10px 30px rgba(2, 132, 199, 0.12) !important;
}


body.light-theme .btn-secondary {
  background: #ffffff !important;
  color: #0f172a !important;
  border-color: #cbd5e1 !important;
}

body.light-theme .btn-secondary:hover {
  background: #f8fafc !important;
  border-color: #0284c7 !important;
  color: #0284c7 !important;
}

/* Light Theme Contact Form & Inputs */
body.light-theme .bg-gray-900\/60 {
  background-color: #ffffff !important;
  border-color: #e2e8f0 !important;
  box-shadow: 0 4px 25px rgba(0, 0, 0, 0.04);
}

body.light-theme input,
body.light-theme textarea {
  background-color: #f8fafc !important;
  border-color: #cbd5e1 !important;
  color: #0f172a !important;
}

body.light-theme input::placeholder,
body.light-theme textarea::placeholder {
  color: #94a3b8 !important;
}

body.light-theme input:focus,
body.light-theme textarea:focus {
  border-color: #0284c7 !important;
  background-color: #ffffff !important;
}

body.light-theme .bg-white\/5 {
  background-color: #f8fafc !important;
  border-color: #e2e8f0 !important;
}

body.light-theme .border-gray-800,
body.light-theme .border-gray-800\/80,
body.light-theme .border-gray-700 {
  border-color: #e2e8f0 !important;
}

body.light-theme .divide-gray-800 > * + * {
  border-color: #e2e8f0 !important;
}

/* Light Theme Modal */
body.light-theme .modal-content {
  background-color: #ffffff !important;
  border-color: #e2e8f0 !important;
  color: #0f172a !important;
}

body.light-theme #modal-close-btn {
  background-color: #f1f5f9 !important;
  color: #475569 !important;
}

body.light-theme #modal-close-btn:hover {
  background-color: #e2e8f0 !important;
  color: #0f172a !important;
}

body.light-theme .modal-content .text-gray-300 {
  color: #334155 !important;
}

body.light-theme .bg-red-500\/5 {
  background-color: #fff1f2 !important;
  border-color: #fecdd3 !important;
}

body.light-theme .text-red-400 {
  color: #be123c !important;
}

body.light-theme .bg-emerald-500\/5 {
  background-color: #ecfdf5 !important;
  border-color: #a7f3d0 !important;
}

/* Light Theme Footer */
body.light-theme footer {
  background-color: #f1f5f9 !important;
  border-color: #e2e8f0 !important;
}

/* ==========================================================================
   ANTI-FLASH THEME BOOTSTRAP
   The <head> script adds .pre-light to <html> before first paint so a
   light-theme visitor never sees a dark flash while JS boots.
   ========================================================================== */
html.pre-light,
html.pre-light body {
  background-color: #f8fafc !important;
  color: #0f172a !important;
}

/* ==========================================================================
   ACCESSIBILITY
   ========================================================================== */

/* Skip link - visible only when focused by keyboard */
.skip-link {
  position: absolute;
  left: 50%;
  top: -100px;
  transform: translateX(-50%);
  z-index: 9999;
  background: var(--accent-cyan);
  color: #0b0f19;
  font-weight: 700;
  font-size: 0.85rem;
  padding: 0.75rem 1.5rem;
  border-radius: 0 0 0.75rem 0.75rem;
  text-decoration: none;
  transition: top 0.2s ease;
}

.skip-link:focus {
  top: 0;
  outline: 3px solid #ffffff;
  outline-offset: 2px;
}

/* Consistent, visible focus ring for keyboard users only */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--accent-cyan);
  outline-offset: 3px;
  border-radius: 0.5rem;
}

/* Screen-reader-only helper */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   SCROLL PROGRESS BAR
   ========================================================================== */
#scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  width: 0%;
  background: var(--gradient-brand);
  box-shadow: 0 0 12px rgba(6, 182, 212, 0.7);
  z-index: 60;
  transition: width 0.1s linear;
  pointer-events: none;
}

/* ==========================================================================
   SCROLL REVEAL ANIMATIONS
   Elements start hidden and fade up when they enter the viewport.
   .reveal-ready is added by JS only when IntersectionObserver is supported,
   so content stays visible if JS fails or is disabled.
   ========================================================================== */
.reveal-ready .reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1),
              transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: opacity, transform;
}

.reveal-ready .reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* ==========================================================================
   BACK TO TOP BUTTON
   ========================================================================== */
.back-to-top {
  position: fixed;
  bottom: 1.75rem;
  left: 1.75rem;
  width: 3rem;
  height: 3rem;
  border-radius: 0.9rem;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 900;
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: all 0.3s ease;
  box-shadow: var(--shadow-sm);
}

.back-to-top.visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.back-to-top:hover {
  color: var(--accent-cyan);
  border-color: var(--border-highlight);
  box-shadow: var(--shadow-glow);
  transform: translateY(-3px);
}

/* ==========================================================================
   ACCENT BUTTON (emerald, distinct from the primary CTA)
   ========================================================================== */
.btn-accent {
  background: rgba(16, 185, 129, 0.12);
  color: #34d399;
  border: 1px solid rgba(16, 185, 129, 0.35);
  font-weight: 600;
  padding: 0.75rem 1.75rem;
  border-radius: 0.75rem;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  transition: all 0.3s ease;
  text-decoration: none;
  cursor: pointer;
}

.btn-accent:hover {
  background: rgba(16, 185, 129, 0.2);
  border-color: rgba(16, 185, 129, 0.6);
  box-shadow: 0 6px 22px rgba(16, 185, 129, 0.28);
  transform: translateY(-2px);
}

body.light-theme .btn-accent {
  background: #d1fae5;
  color: #047857;
  border-color: #6ee7b7;
}

body.light-theme .btn-accent:hover {
  background: #a7f3d0;
}

/* ==========================================================================
   KEYBOARD HINT CHIPS
   ========================================================================== */
.kbd-hint {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  font-weight: 600;
  line-height: 1;
  padding: 0.25rem 0.4rem;
  border-radius: 0.3rem;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--border-color);
  color: var(--text-muted);
  white-space: nowrap;
}

body.light-theme .kbd-hint {
  background: #e2e8f0;
  border-color: #cbd5e1;
  color: #475569;
}

/* ==========================================================================
   COMMAND PALETTE (Ctrl / Cmd + K)
   ========================================================================== */
.palette-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  z-index: 1100;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 6rem 1.5rem 1.5rem;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.palette-backdrop.active {
  opacity: 1;
  pointer-events: auto;
}

.palette-panel {
  width: 100%;
  max-width: 620px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-highlight);
  border-radius: 1rem;
  box-shadow: var(--shadow-md), var(--shadow-glow);
  overflow: hidden;
  transform: translateY(-14px) scale(0.98);
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}

.palette-backdrop.active .palette-panel {
  transform: translateY(0) scale(1);
}

.palette-search {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border-color);
}

.palette-search input {
  flex: 1;
  padding: 0.5rem 0;
  background: transparent;
  border: none;
  outline: none;
  color: var(--text-primary);
  font-size: 0.95rem;
  font-family: var(--font-main);
  min-width: 0;
}

.palette-search input::placeholder {
  color: var(--text-muted);
}

.palette-results {
  list-style: none;
  margin: 0;
  padding: 0.5rem;
  max-height: 340px;
  overflow-y: auto;
}

.palette-item {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.7rem 0.85rem;
  border-radius: 0.6rem;
  cursor: pointer;
  color: var(--text-secondary);
  font-size: 0.875rem;
  transition: background 0.12s ease, color 0.12s ease;
}

.palette-item .palette-icon {
  width: 2rem;
  height: 2rem;
  border-radius: 0.5rem;
  background: rgba(6, 182, 212, 0.1);
  color: var(--accent-cyan);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8rem;
  flex-shrink: 0;
}

.palette-item .palette-label {
  font-weight: 600;
  color: var(--text-primary);
}

.palette-item .palette-desc {
  font-size: 0.72rem;
  color: var(--text-muted);
  font-family: var(--font-mono);
}

.palette-item.selected {
  background: rgba(6, 182, 212, 0.12);
}

body.light-theme .palette-item.selected {
  background: #e0f2fe;
}

.palette-empty {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--text-muted);
  font-size: 0.85rem;
}

.palette-footer {
  display: flex;
  gap: 1.25rem;
  padding: 0.65rem 1.25rem;
  border-top: 1px solid var(--border-color);
  font-size: 0.7rem;
  color: var(--text-muted);
  font-family: var(--font-mono);
}

.palette-footer span {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

@media (max-width: 640px) {
  .palette-footer { display: none; }
  .palette-backdrop { padding-top: 3rem; }
}

/* ==========================================================================
   REDUCED MOTION
   Honour the OS "reduce motion" setting: kill decorative animation but keep
   everything readable and reachable.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .reveal-ready .reveal {
    opacity: 1 !important;
    transform: none !important;
  }

  .glass-card:hover,
  .route-card:hover,
  .btn-primary:hover,
  .btn-secondary:hover,
  .btn-accent:hover,
  .back-to-top:hover,
  .tech-tag:hover {
    transform: none !important;
  }
}

/* ==========================================================================
   PRINT STYLESHEET
   Ctrl+P produces a clean, ink-friendly summary instead of a dark screenshot.
   ========================================================================== */
@media print {
  .glow-orb,
  header,
  #scroll-progress,
  .back-to-top,
  .palette-backdrop,
  .modal-backdrop,
  .toast-container,
  #contact form,
  .skip-link {
    display: none !important;
  }

  html, body {
    background: #ffffff !important;
    color: #000000 !important;
  }

  main { padding-top: 0 !important; }

  .glass-card {
    background: #ffffff !important;
    border: 1px solid #cccccc !important;
    box-shadow: none !important;
    break-inside: avoid;
    page-break-inside: avoid;
  }

  h1, h2, h3, h4, .text-white { color: #000000 !important; }
  .text-gray-300, .text-gray-400 { color: #333333 !important; }

  .text-gradient {
    -webkit-text-fill-color: #0369a1 !important;
    color: #0369a1 !important;
  }

  section { padding: 1rem 0 !important; }
}

/* Code showcase header strip: bg-black/20 reads as heavy mid-grey in light mode. */
body.light-theme .bg-black\/20 {
  background-color: #f1f5f9 !important;
}

/* ==========================================================================
   HERO ROLE LINE ("I'm <typed phrase>")
   Reserves the height the LONGEST rotating phrase needs, so the paragraph
   below never jumps as the typewriter grows and shrinks.

   The values below were measured in-browser against the longest phrase in
   the rotation ("a Business Intelligence Developer"). The line wraps to two
   lines only at the two awkward widths where the font size has stepped up
   but the column has not yet widened.

     >= 1280px  36px font, 1 line
        1024px  36px font, 2 lines  <- column still narrow
      640-1023  30px font, 1 line
       < 640px  24px font, 2 lines

   If you change the phrase list in main.js, re-measure rather than guess.
   ========================================================================== */
.hero-role-line {
  min-height: 2.7em;
}

@media (min-width: 640px) {
  .hero-role-line { min-height: 1.3em; }
}

@media (min-width: 1024px) {
  .hero-role-line { min-height: 2.3em; }
}

@media (min-width: 1280px) {
  .hero-role-line { min-height: 1.25em; }
}

/* ==========================================================================
   SKILL STACK (#skills)

   Static, grouped rows: discipline label on the left, its chips on the right.

   ⚠️ This REPLACED an auto-scrolling marquee (owner-set, 2026-09-02). Chips
   that slide past cannot be read — that is the honest failure mode of a
   marquee, and the owner hit it immediately. The layout also does something
   the band could not: it tells a reader which discipline each skill belongs
   to, so a recruiter filling a BI role can find the BI row instead of waiting
   for it to come round. Nothing here animates. Do not reintroduce the marquee.
   ========================================================================== */
.skill-stack {
  display: flex;
  flex-direction: column;
}

.skill-line {
  display: grid;
  /* Label column is fixed so every chip block starts on the same vertical
     line — a ragged left edge is what makes a list like this hard to scan. */
  grid-template-columns: 15rem 1fr;
  gap: 1.5rem;
  padding: 1.5rem 0;
  border-top: 1px solid var(--border-color);
}

.skill-line:last-child {
  border-bottom: 1px solid var(--border-color);
}

.skill-line-label {
  position: relative;
  align-self: start;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.5;
  color: var(--line-accent, var(--text-primary));
  padding: 0.45rem 0 0.15rem 0.9rem;
}

/* A short accent bar down the left edge, replacing the old '//' prefix. It
   carries the row's colour and gives the label a hard left edge to align to. */
.skill-line-label::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.55rem;
  bottom: 0.25rem;
  width: 3px;
  border-radius: 2px;
  background: var(--line-accent, var(--accent-cyan));
}

.skill-line-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-content: flex-start;
}

.skill-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  white-space: nowrap;
  padding: 0.6rem 1rem;
  border-radius: 999px;
  border: 1px solid var(--border-color);
  background: var(--bg-pill);
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.2;
  transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.skill-chip:hover {
  color: var(--text-heading);
  border-color: var(--chip-accent);
  background: var(--bg-card-hover);
}

.skill-dot {
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 50%;
  flex: 0 0 auto;
  background: var(--chip-accent);
}

/* Accent per discipline. Rows are already grouped, so the dot is a secondary
   cue here rather than the only one — but it still separates the sub-groups
   inside a mixed row (Excel inside "BI, Reporting & Excel", tooling inside
   "Web Development & Tools"). */
.skill-chip-cyan    { --chip-accent: #22d3ee; }
.skill-chip-emerald { --chip-accent: #10b981; }
.skill-chip-violet  { --chip-accent: #a78bfa; }
.skill-chip-green   { --chip-accent: #4ade80; }
.skill-chip-blue    { --chip-accent: #60a5fa; }
.skill-chip-amber   { --chip-accent: #fbbf24; }
.skill-chip-sky     { --chip-accent: #38bdf8; }
.skill-chip-rose    { --chip-accent: #fb7185; }
.skill-chip-gold    { --chip-accent: #f59e0b; }
.skill-chip-indigo  { --chip-accent: #818cf8; }
.skill-chip-slate   { --chip-accent: #94a3b8; }

/* Row-label colours, referenced by the inline --line-accent in the markup. */
:root {
  --chip-cyan: #22d3ee;
  --chip-violet: #a78bfa;
  --chip-emerald: #10b981;
  --chip-slate: #94a3b8;
  --chip-blue: #60a5fa;
  --chip-amber: #fbbf24;
  --chip-sky: #38bdf8;
  --chip-rose: #fb7185;
  --chip-gold: #f59e0b;
  --chip-indigo: #818cf8;
}

/* The chip itself needs no light-theme override — it is built from the theme
   variables. The accents do: the dark tints are chosen against #08070d and
   several of them wash out on white. */
body.light-theme {
  --chip-cyan: #0891b2;
  --chip-violet: #7c3aed;
  --chip-emerald: #059669;
  --chip-slate: #475569;
  --chip-blue: #2563eb;
  --chip-amber: #b45309;
  --chip-sky: #0284c7;
  --chip-rose: #e11d48;
  --chip-gold: #b45309;
  --chip-indigo: #4f46e5;
}

body.light-theme .skill-chip-cyan    { --chip-accent: #0891b2; }
body.light-theme .skill-chip-emerald { --chip-accent: #059669; }
body.light-theme .skill-chip-violet  { --chip-accent: #7c3aed; }
body.light-theme .skill-chip-green   { --chip-accent: #16a34a; }
body.light-theme .skill-chip-blue    { --chip-accent: #2563eb; }
body.light-theme .skill-chip-amber   { --chip-accent: #d97706; }
body.light-theme .skill-chip-sky     { --chip-accent: #0284c7; }
body.light-theme .skill-chip-rose    { --chip-accent: #e11d48; }
body.light-theme .skill-chip-gold    { --chip-accent: #b45309; }
body.light-theme .skill-chip-indigo  { --chip-accent: #4f46e5; }
body.light-theme .skill-chip-slate   { --chip-accent: #475569; }

/* Below lg the fixed label column is more than the text needs, so the label
   stacks above its chips instead. */
@media (max-width: 1023px) {
  .skill-line {
    grid-template-columns: 1fr;
    gap: 0.85rem;
    padding: 1.25rem 0;
  }
  .skill-line-label { padding-top: 0; padding-bottom: 0.1rem; }
}

@media (max-width: 640px) {
  .skill-chip { padding: 0.5rem 0.8rem; font-size: 0.75rem; gap: 0.4rem; }
  .skill-line-chips { gap: 0.4rem; }
  .skill-line-label { font-size: 0.75rem; }
}


/* ==========================================================================
   CLICKABLE CONTACT CARDS
   LinkedIn / GitHub / WhatsApp cards are a single <a> wrapping the whole row,
   so the entire card is the hit target and no URL needs to be displayed.
   Email and phone stay as <div>s because they carry two actions (open the
   client, or copy the value) and a <button> cannot live inside an <a>.
   ========================================================================== */
.contact-card {
  text-decoration: none;
  color: inherit;
}

.contact-card:hover {
  background: rgba(255, 255, 255, 0.08);
}

body.light-theme .contact-card:hover {
  background: #f1f5f9 !important;
}

.contact-card:focus-visible {
  outline: 2px solid var(--accent-cyan);
  outline-offset: 3px;
}

/* ==========================================================================
   MOBILE INPUT ZOOM GUARD

   iOS Safari zooms the whole page whenever a focused input has a font-size
   below 16px, and it does not zoom back out — the visitor is left on a
   magnified, horizontally-scrolling page after tapping the contact form. The
   fields are text-sm (14px), so this raises them on small screens only;
   desktop keeps the smaller type.
   ========================================================================== */

@media (max-width: 640px) {
  input[type="text"],
  input[type="email"],
  input[type="tel"],
  textarea,
  #palette-input {
    font-size: 16px !important;
  }
}


/* ==========================================================================
   EMAIL ADDRESS ON VERY NARROW SCREENS

   'yemulmonish@gmail.com' is one unbreakable token. On a 320px screen its
   min-content width pushed the contact card, and with it the whole page, 3px
   past the viewport — and because the layout viewport then grows, every
   position: fixed element (header, modal, palette) grew with it.

   It wraps instead of truncating: §6 prints this value on purpose, so people
   can read it to copy by hand. An ellipsis would defeat that.
   ========================================================================== */

@media (max-width: 400px) {
  .contact-email {
    overflow-wrap: anywhere;
    word-break: break-word;
  }
}

/* ==========================================================================
   DESIGN SYSTEM v2 — "terminal console" restructure (2026-09-02)

   The owner supplied reference screenshots of a portfolio built around a
   near-black violet-tinted ground, mono `// LABEL` eyebrows, oversized display
   headings and soft-cornered node cards, and asked for this site rebuilt in
   that language with his own content.

   What is deliberately NOT copied: the reference's full-bleed hero photograph.
   profile.jpg is shot on flat studio white (§11), so bleeding it into a black
   page would put a hard white rectangle across the fold. It sits in a framed
   card instead — the same treatment the reference itself uses further down.

   Everything here is built from the theme variables, so light mode follows
   without a parallel set of !important overrides.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Section wash — the violet bloom behind each section heading.
   Width is capped at 100% and it is pointer-events:none, so it can never
   widen the document (§19) or eat a click.
   -------------------------------------------------------------------------- */
.wash {
  position: relative;
  isolation: isolate;
}

.wash::before {
  content: '';
  position: absolute;
  top: -6rem;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 1100px;
  height: 460px;
  border-radius: 50%;
  background: radial-gradient(ellipse at center, var(--wash-color) 0%, transparent 68%);
  filter: blur(38px);
  pointer-events: none;
  z-index: -1;
}

/* --------------------------------------------------------------------------
   Eyebrow — the `⊙ // SECTION LABEL` pill above every heading.
   -------------------------------------------------------------------------- */
.eyebrow {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--label-accent, var(--accent-cyan));
  white-space: nowrap;
}

/* A short rule under the label instead of the old dot-and-slashes pill. It
   anchors the label to the heading below it without adding another shape. */
.eyebrow::after {
  content: '';
  width: 2.25rem;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  opacity: 0.5;
}

/* --------------------------------------------------------------------------
   Display type — the oversized section headings.
   clamp() rather than breakpoint classes: these run from a phone to 1920 and
   a stepped scale left visible jumps at the edges.
   -------------------------------------------------------------------------- */
.display {
  font-weight: 800;
  letter-spacing: -0.035em;
  line-height: 1.02;
  color: var(--text-heading);
  text-shadow: 0 0 40px var(--display-glow);
}

.display-xl { font-size: clamp(2.75rem, 9vw, 6.5rem); text-transform: uppercase; }
.display-lg { font-size: clamp(1.9rem, 5vw, 3.4rem); }

/* --------------------------------------------------------------------------
   Node card — the `// ROOT 01` capability cards, and the general panel shape.
   -------------------------------------------------------------------------- */
.node-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 1.5rem;
  border-radius: 1.25rem;
  border: 1px solid var(--border-color);
  background: var(--bg-card);
  transition: border-color 0.25s ease, transform 0.25s ease, box-shadow 0.25s ease;
}

.node-card:hover {
  border-color: var(--node-accent, var(--border-highlight));
  transform: translateY(-3px);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.35);
}

.node-head {
  display: flex;
  align-items: center;
  margin-bottom: 1.75rem;
}

.node-index {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

.node-title {
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--text-heading);
  line-height: 1.25;
  margin-bottom: 0.6rem;
}

.node-text {
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--text-secondary);
}

/* Pinned to the bottom so the tag lines up across a row of unequal cards. */
.node-tag {
  margin-top: auto;
  padding-top: 1.5rem;
}

.node-tag > span {
  display: inline-block;
  padding: 0.4rem 0.8rem;
  border-radius: 0.55rem;
  border: 1px solid var(--border-color);
  background: var(--bg-pill);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  color: var(--text-secondary);
}

/* --------------------------------------------------------------------------
   Pill buttons — the reference's white-filled primary and outline secondary.
   -------------------------------------------------------------------------- */
.pill-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  padding: 0.7rem 1.5rem;
  border-radius: 999px;
  font-size: 0.875rem;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

.pill-btn:hover { transform: translateY(-2px); }

.pill-solid {
  background: var(--pill-solid-bg);
  color: var(--pill-solid-text);
  border: 1px solid var(--pill-solid-bg);
}

.pill-solid:hover { background: var(--pill-solid-hover); border-color: var(--pill-solid-hover); }

.pill-ghost {
  background: var(--bg-pill);
  color: var(--text-primary);
  border: 1px solid var(--border-color);
}

.pill-ghost:hover {
  border-color: var(--text-secondary);
  background: var(--bg-card-hover);
}

/* --------------------------------------------------------------------------
   Profile frame — the portrait card with the availability strip along the
   bottom. Replaces the circular avatar; the studio-white background reads as
   an intentional card here rather than as a glowing disc (§11).
   -------------------------------------------------------------------------- */
.profile-frame {
  position: relative;
  border-radius: 1.5rem;
  overflow: hidden;
  border: 1px solid var(--border-color);
  background: var(--bg-secondary);
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.45);
}

.profile-frame img {
  display: block;
  width: 100%;
  height: auto;
  /* profile.jpg is 681x1024 with the head at 7.6% and the shoulder line at
     38.2% (§11). A 4:5 window keeps the whole upper body without the empty
     lower third; the top anchor is what keeps his head in frame. */
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 50% 12%;
  max-width: none;
}

.profile-status {
  position: absolute;
  left: 0.85rem;
  right: 0.85rem;
  bottom: 0.85rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 0.9rem;
  border-radius: 0.85rem;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(8, 7, 14, 0.72);
  backdrop-filter: blur(10px);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #f3f4f6;
}

.profile-status .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #22c55e;
  box-shadow: 0 0 10px #22c55e;
  flex: 0 0 auto;
}

/* --------------------------------------------------------------------------
   Stat tiles — the three small cards under the profile paragraph.
   -------------------------------------------------------------------------- */
.stat-tile {
  padding: 1rem 1.1rem;
  border-radius: 0.9rem;
  border: 1px solid var(--border-color);
  background: var(--bg-card);
  transition: border-color 0.25s ease;
}

.stat-tile:hover { border-color: var(--border-highlight); }

.stat-tile .val {
  display: block;
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--text-heading);
  line-height: 1.25;
}

.stat-tile .key {
  display: block;
  margin-top: 0.25rem;
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Contact — the live payload preview and the form fields.
   -------------------------------------------------------------------------- */
.payload-box {
  margin-top: 1.75rem;
  padding: 1.25rem;
  border-radius: 1rem;
  border: 1px solid var(--border-color);
  background: var(--bg-input);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  line-height: 2;
  overflow-x: auto;
}

.payload-box .k { color: var(--text-secondary); }
.payload-box .c { color: var(--text-muted); }
/* Placeholder state vs a value the visitor has actually typed. */
.payload-box .v { color: var(--text-muted); font-style: italic; }
.payload-box .v.filled { color: var(--accent-cyan); font-style: normal; }

.field {
  width: 100%;
  padding: 0.9rem 1.1rem;
  border-radius: 0.85rem;
  border: 1px solid var(--border-color);
  background: var(--bg-input);
  color: var(--text-primary);
  font-size: 1rem;
  transition: border-color 0.2s ease, background 0.2s ease;
}

.field::placeholder { color: var(--text-muted); }

.field:focus {
  outline: none;
  border-color: var(--accent-cyan);
  background: var(--bg-card-hover);
}

textarea.field { resize: none; }

/* The consent checkbox. accent-color styles the native control, which stays
   keyboard-operable and needs no JS. */
.consent {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  line-height: 1.5;
  cursor: pointer;
}

.consent input {
  width: 1.05rem;
  height: 1.05rem;
  margin-top: 0.1rem;
  flex: 0 0 auto;
  accent-color: var(--accent-cyan);
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   Nav wordmark — the name alone. The trailing cyan accent dot was removed on
   2026-09-03; inline-flex stays so the anchor keeps hugging its text.
   -------------------------------------------------------------------------- */
.wordmark {
  display: inline-flex;
  align-items: baseline;
  font-size: 1.15rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--text-heading);
}

/* --------------------------------------------------------------------------
   Hero scroll cue.
   -------------------------------------------------------------------------- */
.scroll-cue {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.scroll-cue i { animation: cue-bob 2.2s ease-in-out infinite; }

@keyframes cue-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(4px); }
}

@media (prefers-reduced-motion: reduce) {
  .scroll-cue i { animation: none; }
}

/* --------------------------------------------------------------------------
   Skill chips, restyled to the reference's outline-mono pill.
   The marquee mechanics in the block above are unchanged.
   -------------------------------------------------------------------------- */
.skill-chip {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  border-radius: 999px;
  padding: 0.7rem 1.15rem;
  background: var(--bg-pill);
}

@media (max-width: 640px) {
  .skill-chip { font-size: 0.6875rem; padding: 0.55rem 0.85rem; }
}

/* ==========================================================================
   HERO ENTRANCE — plays once, on every load / refresh
   --------------------------------------------------------------------------
   Pure CSS on purpose. The scroll-reveal system (see SCROLL REVEAL above) is
   JS-gated and never touches the hero: nothing in its selector list matches
   here, and hand-tagging .reveal on an unobserved element is exactly the bug
   that left the route cards invisible for a day. A keyframe with
   `animation-fill-mode: both` cannot get stuck — it runs whenever the
   stylesheet paints, with or without JS.

   Order matters more than the individual effects. The eye is led:
     portrait lands -> badge -> name -> role -> value copy -> offer -> CTAs
   Stacked on a phone the portrait is order-first, so the same delays still
   read top-to-bottom.

   Reduced motion is handled by the global block above: every duration there
   collapses to 0.01ms, and because each animation here uses `both`, the
   element snaps straight to its resting frame. Nothing can stay hidden.
   ========================================================================== */

/* --- Text column: staggered rise. Delay is per-element via --hero-delay. --- */
.hero-in {
  animation: hero-rise 0.9s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: var(--hero-delay, 0s);
  will-change: opacity, transform;
}

@keyframes hero-rise {
  from {
    opacity: 0;
    transform: translateY(20px);
    /* A short defocus reads as "settling into place" rather than "sliding in",
       which suits a portrait page better than a pure slide. Kept small: blur
       on large headline type is expensive to composite. */
    filter: blur(5px);
  }
  to {
    opacity: 1;
    transform: none;
    filter: blur(0);
  }
}

/* --- The name: the brand gradient zooms and slides into its resting frame ---
   The `to` frame is 100%/0% 50%, which for a box-sized linear-gradient is
   pixel-identical to the un-animated `.text-gradient`. That is the whole
   trick: the resting look is untouched, so nothing snaps when it finishes. */
.hero-name {
  animation: hero-name-settle 1.5s cubic-bezier(0.4, 0, 0.2, 1) 0.45s both;
}

@keyframes hero-name-settle {
  from { background-size: 300% 100%; background-position: 100% 50%; }
  to   { background-size: 100% 100%; background-position: 0% 50%; }
}

/* --- Portrait: scale up out of a soft blur, with the glow blooming ---------
   Two animations on one element (comma-separated, NOT two rules) because a
   second rule would silently replace the first. */
.hero-avatar {
  /* Clips the rotating ::after below. A square box rotated 30deg has a
     bounding box 1.37x wider than the circle it draws inside, and layout
     overflow counts even at opacity 0 — that added 24-37px of horizontal
     scroll at every width. The element's OWN box-shadow (the bloom) paints
     outside the padding box and is not affected by this. */
  overflow: hidden;
  animation:
    hero-avatar-in 1.1s cubic-bezier(0.16, 1, 0.3, 1) 0.05s both,
    hero-avatar-bloom 1.9s ease-out 0.05s both;
  will-change: opacity, transform;
}

@keyframes hero-avatar-in {
  from { opacity: 0; transform: scale(0.9); filter: blur(6px); }
  to   { opacity: 1; transform: scale(1);   filter: blur(0); }
}

/* Ends on --avatar-shadow-rest, which is what .avatar-glow paints anyway, so
   the fill-mode `both` end state matches the static style in BOTH themes. */
@keyframes hero-avatar-bloom {
  0%   { box-shadow: 0 0 0 rgba(6, 182, 212, 0); }
  40%  { box-shadow: var(--avatar-shadow-peak); }
  100% { box-shadow: var(--avatar-shadow-rest); }
}

/* --- A light traces once around the gradient ring --------------------------
   inset:0 with a 5px border puts the arc exactly ON the ring (the ring IS the
   5px padding), so it never extends past the circle. That is deliberate: at
   320px the portrait already fills its column, and an outset decoration would
   widen the document — the same class of bug as the off-canvas drawer. */
.hero-avatar::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 5px solid transparent;
  border-top-color: rgba(255, 255, 255, 0.95);
  border-right-color: rgba(255, 255, 255, 0.4);
  pointer-events: none;
  animation: hero-ring-trace 1.35s cubic-bezier(0.45, 0, 0.25, 1) 0.25s both;
}

@keyframes hero-ring-trace {
  0%   { transform: rotate(-40deg); opacity: 0; }
  15%  { opacity: 1; }
  65%  { opacity: 1; }
  100% { transform: rotate(390deg); opacity: 0; }
}

/* --- Photo push-in ---------------------------------------------------------
   Origin sits near the head (see the framing notes on .avatar-glow img: head
   top at 7.6%) so the face stays put while the crop relaxes. .avatar-clip's
   overflow:hidden contains the extra 6%. */
.hero-avatar .avatar-clip img {
  transform-origin: 50% 22%;
  animation: hero-photo-in 1.6s cubic-bezier(0.16, 1, 0.3, 1) 0.05s both;
}

@keyframes hero-photo-in {
  from { transform: scale(1.06); }
  to   { transform: scale(1); }
}

/* --- Idle float, once the entrance has finished ----------------------------
   On the wrapper, not on .hero-avatar, because that element's transform is
   already owned by the entrance. Slow and shallow on purpose — enough to stop
   the page reading as a screenshot, not enough to pull the eye off the copy. */
.hero-avatar-float {
  animation: hero-float 7s ease-in-out 1.5s infinite;
}

@keyframes hero-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-8px); }
}

@media (prefers-reduced-motion: reduce) {
  .hero-avatar-float { animation: none; }
  .hero-avatar::after { display: none; }
}
