:root {
  --bg: #0B0F1A;
  --surface: #14171F;
  --border: rgba(231, 233, 238, 0.08);
  --border-strong: rgba(231, 233, 238, 0.16);
  --text: #E7E9EE;
  --text-muted: #9AA1AE;
  --accent: #FF7A50;
  --accent-soft: rgba(255, 122, 80, 0.12);
  --accent-glow: rgba(255, 122, 80, 0.35);
  --radius: 14px;
  --radius-sm: 8px;
  --shadow: 0 24px 60px -24px rgba(0, 0, 0, 0.65);
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --maxw: 1120px;
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --slide-ease: cubic-bezier(0.76, 0, 0.24, 1);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent);
  color: #14171F;
  padding: 0.75rem 1rem;
  border-radius: var(--radius-sm);
  font-weight: 600;
  z-index: 1000;
}
.skip-link:focus { left: 1rem; top: 1rem; }

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

/* ---------- Focus states ---------- */
/* Keyboard-only focus ring in the accent color, consistent with the hover
   language used everywhere else. Mouse/touch users never see it. */
a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}
.slide-dot:focus-visible { outline-offset: 4px; }

.section__inner {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 6rem 1.5rem;
  position: relative;
}

.eyebrow {
  color: var(--accent);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin: 0 0 0.75rem;
}

.section__title {
  font-size: clamp(1.6rem, 3vw, 2.25rem);
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 0 0 2.5rem;
  max-width: 40ch;
}

/* Centered headers: these sections' intro block (eyebrow, heading, lead
   paragraph) is moved to the center of the page as a column — text inside
   stays left-aligned, only the block itself is centered. Grids/lists
   further down keep their own natural left-aligned, full-width layout.
   (About is not in this group: its whole content shares one column, see
   the About section below.) */
.skills .eyebrow,
.projects .eyebrow,
.blog-preview .eyebrow,
.apps .eyebrow,
.certifications .eyebrow,
.contact .eyebrow {
  width: fit-content;
  margin-left: auto;
  margin-right: auto;
}
.skills .section__title,
.projects .section__title,
.blog-preview .section__title,
.apps .section__title,
.certifications .section__title,
.contact .section__title,
.contact .contact__lead,
.blog-preview .blog-lead {
  margin-left: auto;
  margin-right: auto;
}

.about { background: var(--surface); }
.skills { background: var(--surface); }
.blog-preview { background: var(--surface); }
.certifications { background: var(--surface); }

/* ---------- Nav ---------- */

.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(11, 15, 26, 0.7);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s var(--ease), background 0.3s var(--ease);
}
.nav.is-scrolled {
  border-bottom-color: var(--border);
  background: rgba(11, 15, 26, 0.9);
}

/* Set by main.js for the duration of a slide transition. backdrop-filter has
   to resample whatever's moving behind it on every frame, which is a common
   jank source on mobile GPUs; dropping it just while a section is actually
   sliding keeps the background opaque enough to still read fine. */
.js-slides .nav.is-transitioning {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.nav__inner {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 1.1rem 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.nav__brand {
  font-weight: 800;
  font-size: 1.1rem;
  letter-spacing: 0.04em;
}
.nav__brand-dot { color: var(--accent); }

.nav__links {
  display: flex;
  align-items: center;
  gap: 2rem;
}

.nav__link {
  font-size: 0.92rem;
  color: var(--text-muted);
  position: relative;
  padding: 0.25rem 0;
  transition: color 0.2s var(--ease);
}
.nav__link:hover,
.nav__link.is-active { color: var(--text); }
.nav__link.is-active { color: var(--accent); }

.nav__link--cta {
  color: var(--text);
  border: 1px solid var(--border-strong);
  padding: 0.5rem 1.1rem;
  border-radius: 999px;
  transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease), color 0.2s var(--ease);
}
.nav__link--cta:hover {
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 24px -6px var(--accent-glow);
}
.nav__link--cta.is-active { color: var(--accent); border-color: var(--accent); }

.nav__toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 36px;
  height: 36px;
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.nav__toggle span {
  display: block;
  height: 1.5px;
  width: 16px;
  margin: 0 auto;
  background: var(--text);
  transition: transform 0.25s var(--ease), opacity 0.25s var(--ease);
}
.nav__toggle.is-open span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav__toggle.is-open span:nth-child(2) { opacity: 0; }
.nav__toggle.is-open span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.85rem 1.6rem;
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.95rem;
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease), border-color 0.2s var(--ease), background 0.2s var(--ease);
}

.btn--primary {
  background: var(--accent);
  color: #170D08;
  box-shadow: 0 10px 30px -8px var(--accent-glow);
}
.btn--primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 16px 40px -10px var(--accent-glow);
}

.btn--ghost {
  border: 1px solid var(--border-strong);
  color: var(--text);
}
.btn--ghost:hover {
  border-color: var(--accent);
  color: var(--accent);
  transform: translateY(-2px);
}

/* ---------- Hero ---------- */

.hero {
  position: relative;
  overflow: hidden;
  padding-top: 2rem;
}

.hero__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.hero__glow {
  position: absolute;
  border-radius: 50%;
  filter: blur(60px);
  opacity: 0.35;
}
.hero__glow--1 {
  width: 520px;
  height: 520px;
  right: -120px;
  top: -160px;
  background: radial-gradient(circle, var(--accent) 0%, transparent 70%);
}
.hero__glow--2 {
  width: 360px;
  height: 360px;
  left: -100px;
  bottom: -140px;
  background: radial-gradient(circle, #3d5a80 0%, transparent 70%);
  opacity: 0.25;
}

.hero__grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--border) 1px, transparent 1px),
    linear-gradient(90deg, var(--border) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: linear-gradient(to bottom, black, transparent 70%);
  mask-image: linear-gradient(to bottom, black, transparent 70%);
  opacity: 0.5;
}

.hero__inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: 3rem;
  align-items: center;
  min-height: calc(100vh - 68px);
  padding-top: 3rem;
  padding-bottom: 3rem;
}

.hero__title {
  font-size: clamp(2.4rem, 5vw, 4rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 0 0 1.25rem;
  line-height: 1.05;
}

.hero__tagline {
  font-size: clamp(1.05rem, 1.6vw, 1.25rem);
  color: var(--text);
  max-width: 46ch;
  margin: 0 0 1rem;
}

.accent-text { color: var(--accent); }

.hero__sub {
  color: var(--text-muted);
  max-width: 48ch;
  margin: 0 0 2.5rem;
}

.hero__actions {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}

.hero__portrait {
  position: relative;
  justify-self: center;
  width: min(100%, 380px);
}

.hero__portrait-ring {
  position: absolute;
  inset: -18px;
  border: 1px solid var(--border-strong);
  border-radius: 24px;
  z-index: 0;
}

.hero__photo {
  position: relative;
  z-index: 1;
  width: 100%;
  height: auto;
  border-radius: 18px;
  filter: drop-shadow(0 30px 60px rgba(0, 0, 0, 0.55));
}

/* ---------- About ---------- */

.about { position: relative; overflow: hidden; }

.about__glow {
  position: absolute;
  left: 50%;
  top: 8%;
  transform: translateX(-50%);
  width: 640px;
  height: 360px;
  background: radial-gradient(ellipse at center, var(--accent) 0%, transparent 70%);
  opacity: 0.12;
  filter: blur(80px);
  pointer-events: none;
}

/* Two columns across the full content width: eyebrow, heading and stats on
   the left; text and pills on the right. */
.about__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 4rem;
  align-items: start;
}
/* Drop the body to the top of the heading (past the eyebrow's height and
   margin) so the first line of text lines up with the heading. */
.about__body { padding-top: 2.05rem; }

.about .section__title {
  font-size: clamp(2rem, 4vw, 3rem);
  line-height: 1.15;
  margin-bottom: 0;
  text-wrap: balance;
}

.about__text {
  color: var(--text-muted);
  font-size: 1.125rem;
}
.about__text + .about__text { margin-top: 0.85rem; }

.about__stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem 1.75rem;
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border);
}
/* Each stat is a link to the section that backs it up. */
.stat {
  display: block;
  max-width: 15rem;
  transition: transform 0.2s var(--ease);
}
.stat:hover { transform: translateY(-3px); }
.stat:hover .stat__label { color: var(--text); }
.stat__icon {
  width: 24px;
  height: 24px;
  color: var(--accent);
  margin-bottom: 0.4rem;
}
.stat__num {
  color: var(--accent);
  font-size: clamp(1.7rem, 2.6vw, 2.2rem);
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 0 0 0.3rem;
}
.stat__label {
  color: var(--text-muted);
  font-size: 0.85rem;
  margin: 0;
  transition: color 0.2s var(--ease);
}

.about__values {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1.25rem;
}

/* ---------- Experience / Timeline ---------- */

.timeline {
  position: relative;
  margin: 0 auto;
  max-width: 900px;
}
.timeline::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--border);
  transform: translateX(-50%);
}

.timeline__item {
  position: relative;
  width: 50%;
  padding-bottom: 2rem;
}
.timeline__item:nth-child(odd) { margin-left: 0; padding-right: 2.5rem; }
.timeline__item:nth-child(even) { margin-left: 50%; padding-left: 2.5rem; }
.timeline__item:last-child { padding-bottom: 0; }

.timeline__marker {
  position: absolute;
  top: 1.7rem;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--bg);
  border: 2px solid var(--accent);
  box-shadow: 0 0 0 4px var(--accent-soft);
  z-index: 1;
}
.timeline__item:nth-child(odd) .timeline__marker { right: -7px; }
.timeline__item:nth-child(even) .timeline__marker { left: -7px; }

.timeline__card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.6rem 1.8rem;
  transition: border-color 0.25s var(--ease), transform 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.timeline__card:hover {
  border-color: var(--border-strong);
  transform: translateY(-3px);
  box-shadow: var(--shadow);
}

.timeline__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
}

.timeline__role {
  font-size: 1.1rem;
  font-weight: 700;
  margin: 0;
}

.timeline__date {
  font-size: 0.85rem;
  color: var(--text-muted);
  white-space: nowrap;
}

.timeline__org {
  color: var(--accent);
  font-weight: 600;
  font-size: 0.92rem;
  margin: 0.25rem 0 0.85rem;
}

.timeline__desc {
  color: var(--text-muted);
  margin: 0.5rem 0 0;
}

/* ---------- Skills ---------- */

.skills { position: relative; overflow: hidden; }

.skills::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 4%;
  transform: translateX(-50%);
  width: 700px;
  height: 380px;
  background: radial-gradient(ellipse at center, var(--accent) 0%, transparent 70%);
  opacity: 0.08;
  filter: blur(90px);
  pointer-events: none;
}

.skills__list {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  width: 100%;
  max-width: 900px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.4rem 3.5rem;
  position: relative;
}

.skill__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin-bottom: 0.45rem;
  font-size: 0.88rem;
  font-weight: 600;
}

.skill__value { color: var(--text-muted); font-variant-numeric: tabular-nums; }

.skill__bar {
  height: 6px;
  border-radius: 999px;
  background: rgba(231, 233, 238, 0.1);
  overflow: hidden;
}

.skill__fill {
  display: block;
  height: 100%;
  width: calc(var(--level) * 1%);
  border-radius: 999px;
  background: var(--accent);
}

.pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

.pill {
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  padding: 0.5rem 1rem;
  font-size: 0.88rem;
  background: var(--bg);
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.pill:hover {
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 20px -8px var(--accent-glow);
}

/* ---------- Projects ---------- */

.projects__systems {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  margin-bottom: 3rem;
}

.chip {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.55rem 0.95rem;
  font-size: 0.88rem;
  color: var(--text-muted);
  background: var(--surface);
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease);
}
.chip:hover { border-color: var(--accent); color: var(--text); }

.awards,
.projects__featured {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.5rem;
}
.projects__featured { margin-bottom: 1.5rem; }

/* Small labelled divider between the projects above (chips and featured cards)
   and the highlights (award cards) below. */
.projects__divider {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin: 0.5rem 0 1.5rem;
  color: var(--accent);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.projects__divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border-strong);
}

.award-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.8rem;
  overflow: hidden;
  transition: transform 0.25s var(--ease), border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.award-card::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 100% 0%, var(--accent-soft), transparent 60%);
  opacity: 0.8;
}
.award-card:hover {
  transform: translateY(-3px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow);
}

.award-card__result {
  position: relative;
  display: inline-block;
  color: var(--accent);
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin: 0 0 0.75rem;
}

/* Featured cards: the label sits on the left and the project's logo on the
   right (wrapping under the label on narrow cards). The logos are dark on
   transparent, so they sit on a light tile to stay readable on the dark card. */
.award-card__head {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem 1rem;
  margin: 0 0 0.9rem;
}
.award-card__head .award-card__result { margin: 0; }

.award-card__logo {
  display: inline-flex;
  align-items: center;
  padding: 0.5rem 0.85rem;
  border-radius: var(--radius-sm);
  background: #F1F4F7;
}
.award-card__logo img {
  height: 42px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
}

/* Highlights: a glowing trophy badge on the right of the header so the awards
   stand out. The label is centered on the badge instead of top-aligned. */
.award-card__head--award { align-items: center; }

.award-card__trophy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  color: var(--accent);
  background: rgba(255, 122, 80, 0.18);
  border: 1px solid rgba(255, 122, 80, 0.6);
  box-shadow: 0 0 30px -4px var(--accent-glow);
  transition: box-shadow 0.25s var(--ease), transform 0.25s var(--ease);
}
.award-card__trophy svg { width: 32px; height: 32px; }
.award-card:hover .award-card__trophy {
  box-shadow: 0 0 40px -2px var(--accent-glow);
  transform: scale(1.06);
}

.award-card__title {
  position: relative;
  font-size: 1.05rem;
  margin: 0 0 0.5rem;
  max-width: 32ch;
}

.award-card__date {
  position: relative;
  color: var(--text-muted);
  font-size: 0.88rem;
  margin: 0;
}

.award-card__desc {
  position: relative;
  color: var(--text-muted);
  font-size: 0.92rem;
  margin: 0 0 1rem;
  max-width: 48ch;
}

.award-card__link {
  position: relative;
  display: inline-block;
  color: var(--accent);
  font-size: 0.92rem;
  font-weight: 600;
}
.award-card__link:hover { text-decoration: underline; }

/* ---------- Apps ---------- */

.apps__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.5rem;
}

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

.app-card__head {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1rem;
}

.app-card__icon {
  flex: none;
  width: 64px;
  height: 64px;
  border-radius: 22%;
  border: 1px solid var(--border-strong);
}

.app-card__title { font-size: 1.2rem; margin: 0; }

.app-card__tagline {
  color: var(--text-muted);
  font-size: 0.9rem;
  margin: 0.2rem 0 0;
}

.app-card__platforms {
  display: flex;
  gap: 0.5rem;
  margin: 0 0 1rem;
}
.app-card__platforms span {
  color: var(--accent);
  border: 1px solid var(--accent-soft);
  border-radius: 999px;
  padding: 0.2rem 0.7rem;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.app-card__desc {
  color: var(--text-muted);
  font-size: 0.95rem;
  margin: 0 0 1.25rem;
}

.app-card__tech {
  list-style: none;
  margin: 0 0 1.4rem;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.app-card__tech li {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.3rem 0.7rem;
  font-size: 0.8rem;
  color: var(--text-muted);
  background: var(--bg);
}

.app-card__links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.2rem;
  margin-top: auto;
}
.app-card__link {
  align-self: flex-start;
  color: var(--accent);
  font-size: 0.92rem;
  font-weight: 600;
}
.app-card__link:hover { text-decoration: underline; }

/* ---------- Certifications ---------- */

.cert-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.cert-item {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.5rem 1.5rem;
  padding: 1.15rem 0;
  border-bottom: 1px solid var(--border);
}
.cert-item:first-child { padding-top: 0; }
.cert-item:last-child { border-bottom: none; }

.cert-item__name { font-weight: 600; }
.cert-item__meta { color: var(--text-muted); font-size: 0.9rem; white-space: nowrap; }

/* ---------- Contact ---------- */

.contact { position: relative; overflow: hidden; }

.contact__glow {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translateX(-50%);
  width: 700px;
  height: 400px;
  background: radial-gradient(ellipse at center, var(--accent) 0%, transparent 70%);
  opacity: 0.15;
  filter: blur(80px);
  pointer-events: none;
}

.contact__lead {
  color: var(--text-muted);
  max-width: 52ch;
  margin: -1.5rem 0 2.5rem;
  font-size: 1.05rem;
}

.contact__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem;
  margin-bottom: 2.5rem;
}

.contact__link {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 1rem 1.2rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text-muted);
  font-size: 0.92rem;
  overflow: hidden;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease), transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.contact__link:hover {
  border-color: var(--accent);
  color: var(--text);
  transform: translateY(-2px);
  box-shadow: 0 12px 30px -14px var(--accent-glow);
}
.contact__link .icon { color: var(--accent); flex-shrink: 0; }
/* An odd number of links would leave the last one alone in the left column. */
.contact__link:last-child:nth-child(odd) { grid-column: 1 / -1; }

/* Placeholder for a profile that has no URL yet: same card, dimmed, and not a
   link. Once the URL exists, swap the <span> for an <a href="..." target="_blank"
   rel="me noopener"> and drop this modifier. */
.contact__link--pending { cursor: default; }
.contact__link--pending:hover {
  border-color: var(--border);
  color: var(--text-muted);
  transform: none;
  box-shadow: none;
}
.contact__link--pending .icon { color: var(--text-muted); }
.contact__link--pending > * { opacity: 0.5; }

.contact__resume { position: relative; }

/* ---------- Icons ---------- */

.icon { width: 20px; height: 20px; }

/* ---------- Footer ---------- */

.footer__inner {
  margin-top: 3rem;
  padding-top: 2rem;
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  color: var(--text-muted);
  font-size: 0.88rem;
}
.footer__inner p { margin: 0; }
.footer__top {
  color: var(--accent);
  font-weight: 700;
  transition: opacity 0.2s var(--ease);
}
.footer__top:hover { opacity: 0.8; }

/* ---------- Blog ---------- */

.page-footer {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 1.5rem 4rem;
}

.blog-index__title { margin-bottom: 1rem; }

.blog-lead {
  color: var(--text-muted);
  max-width: 60ch;
  font-size: 1.05rem;
  margin: 0 0 1.25rem;
}

.blog-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
}

.blog-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  transition: transform 0.25s var(--ease), border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.blog-card:hover {
  transform: translateY(-3px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow);
}

.blog-card__thumb {
  display: block;
  width: 100%;
  height: 100px;
  object-fit: cover;
  border-bottom: 1px solid var(--border);
}

.blog-card__body {
  position: relative;
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  padding: 1.25rem 1.8rem 1.25rem;
}
.blog-card__body::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 100% 0%, var(--accent-soft), transparent 60%);
  opacity: 0.8;
  pointer-events: none;
}

.blog-card__meta {
  position: relative;
  color: var(--text-muted);
  font-size: 0.8rem;
  letter-spacing: 0.02em;
  margin: 0 0 0.5rem;
}

.blog-card__title {
  position: relative;
  font-size: 1.1rem;
  line-height: 1.35;
  margin: 0 0 0.5rem;
}
.blog-card__title a:hover { color: var(--accent); }

.blog-card__desc {
  position: relative;
  color: var(--text-muted);
  font-size: 0.92rem;
  margin: 0 0 1.25rem;
  flex-grow: 1;
}

.blog-card__link {
  position: relative;
  display: inline-block;
  color: var(--accent);
  font-size: 0.9rem;
  font-weight: 600;
}
.blog-card__link:hover { text-decoration: underline; }

.blog-preview__cta {
  margin-top: 1.5rem;
  text-align: center;
}

.blog-index__more {
  margin-top: 3rem;
  color: var(--text-muted);
  font-size: 0.92rem;
}
.blog-index__more a { color: var(--accent); font-weight: 600; }
.blog-index__more a:hover { text-decoration: underline; }

/* ---------- Blog post ---------- */

/* Narrower than .section__inner's 1120px, and centered: text and images
   share this one column width, so nothing is left narrower than its box
   (matches Medium's own article layout). */
.post { max-width: 800px; margin-left: auto; margin-right: auto; }

.post__back {
  display: inline-block;
  color: var(--text-muted);
  font-size: 0.9rem;
  font-weight: 600;
  margin-bottom: 2rem;
  transition: color 0.2s var(--ease);
}
.post__back:hover { color: var(--accent); }

.post__title {
  font-size: clamp(1.8rem, 4vw, 2.5rem);
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 0 0 1rem;
}

.post__meta {
  color: var(--text-muted);
  font-size: 0.92rem;
  margin: 0 0 3rem;
}

.post-body h2 {
  font-size: 1.25rem;
  font-weight: 700;
  margin: 2.5rem 0 1rem;
}
.post-body p { margin: 0 0 1.25rem; }
.post-body ul { margin: 0 0 1.5rem; padding-left: 1.25rem; }
.post-body li { margin: 0 0 0.6rem; }
.post-body strong { color: var(--text); }
.post-body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.88em;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.1em 0.4em;
}
.post-body a { color: var(--accent); font-weight: 600; }
.post-body a:hover { text-decoration: underline; }
.post-body figure { margin: 1.75rem 0; }
.post-body img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
}
.post-body figcaption {
  color: var(--text-muted);
  font-size: 0.85rem;
  margin-top: 0.6rem;
}

.post-source {
  margin-top: 3rem;
  padding-top: 2rem;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 0.9rem;
}
.post-source a { color: var(--accent); font-weight: 600; }
.post-source a:hover { text-decoration: underline; }

/* ---------- Reveal-on-scroll ---------- */

/* Always visible. This used to hide content until an IntersectionObserver
   confirmed it had scrolled into view, but that observer wasn't reliably
   firing in every environment (seen under file://), which left content
   permanently invisible or flashing and disappearing. Simple beats clever
   here: no JS dependency for baseline content visibility, ever. */
.reveal { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .btn, .contact__link, .timeline__card, .award-card, .app-card, .pill, .blog-card { transition: none; }
}

/* ---------- Slideshow (scroll-hijacked full-screen sections) ---------- */
/* Only active once JS confirms motion is OK and adds .js-slides to <html>.
   Without it (JS disabled, or prefers-reduced-motion), the site is a normal
   scrolling single page using the rules above. */

.js-slides body {
  overflow: hidden;
  height: 100vh;
  height: 100svh;
  overscroll-behavior: none;
}

.js-slides .nav { position: fixed; width: 100%; }

.js-slides main > section {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  transform: translateY(100%);
  transition: transform 0.75s var(--slide-ease);
  z-index: 1;
  pointer-events: none;
}

/* Only the two sections actually animating (set by main.js) get the
   compositing hint, instead of all 9 full-viewport sections at once. */
.js-slides main > section.is-transitioning { will-change: transform; }

.js-slides main > section.is-before { transform: translateY(-100%); }

.js-slides main > section.is-active {
  transform: translateY(0);
  z-index: 2;
  pointer-events: auto;
}

/* Set alongside .js-slides for the first frame only. Sections start as normal
   in-flow blocks, so without this the switch to the fixed stack animates every
   non-active one sliding out of the viewport over the hero. */
.js-slides-init main > section { transition: none; }

.js-slides .section__inner {
  height: 100%;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
.js-slides .section__inner::-webkit-scrollbar { width: 6px; }
.js-slides .section__inner::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 999px;
}

/* Vertically balance short sections within the 100vh slide instead of
   leaving them pinned to the top with dead space below. Hero already
   centers itself via .hero__inner's own grid, so it's excluded here.
   "safe center" falls back to top-alignment if content ever overflows
   the viewport, so nothing is ever clipped/unreachable. */
.js-slides .section__inner:not(.hero__inner) {
  display: flex;
  flex-direction: column;
  justify-content: safe center;
}

/* Experience is expected to overflow (long timeline) and already scrolls
   internally by design — keep it top-aligned rather than centered. */
.js-slides .experience .section__inner {
  justify-content: flex-start;
}

/* Build-in: each piece of a section (heading, text, cards, pills...) enters on
   its own, staggered by --d (a step index set per element below), so the
   section looks like it assembles itself; leaving reverses the same way. */

.js-slides main > section[data-enter="left"] { --sx: -34px; }
.js-slides main > section[data-enter="right"] { --sx: 34px; }
.js-slides .hero__portrait.stagger-item { --sx: 34px; }

/* Two-column grids: an item takes its direction from which column it's
   actually in (left column enters from the left, right column from the
   right), overriding the section's overall direction. */
.js-slides .contact__link.stagger-item:nth-child(odd) { --sx: -16rem; }
.js-slides .contact__link.stagger-item:nth-child(even) { --sx: 16rem; }

/* About: each piece enters from where it sits, with a long sweep so it reads
   over the section's own slide-in. The heading column comes in from the left,
   the text column from the right, and the stats and pills rise from below
   (--sy is the vertical offset, 12px unless set). */
.js-slides .about__intro > .eyebrow.stagger-item,
.js-slides .about__intro > .section__title.stagger-item { --sx: -16rem; }
.js-slides .about__body > .about__text.stagger-item { --sx: 16rem; }
.js-slides .about__stats.stagger-item,
.js-slides .about__values.stagger-item { --sx: 0px; --sy: 4rem; }

/* Experience: the heading comes in from the left, the timeline cards from
   the side they sit on (left of the spine from the left, right of it from
   the right), and the spine itself draws downward. Same long sweep as About. */
.js-slides .experience .eyebrow.stagger-item,
.js-slides .experience .section__title.stagger-item { --sx: -16rem; }
.js-slides .timeline__item.stagger-item:nth-child(odd) { --sx: -16rem; }
.js-slides .timeline__item.stagger-item:nth-child(even) { --sx: 16rem; }

.js-slides .timeline::before {
  scale: 1 0;
  transform-origin: 50% 0;
  transition: scale 1.2s var(--slide-ease) 0.15s;
}
.js-slides main > section.is-active .timeline::before { scale: 1 1; }

/* Timeline cards below the fold wait to be scrolled to: main.js adds .is-in as
   each one comes into view, so only what fits on the page builds in when the
   slide opens. */
.js-slides main > section.is-active .timeline__item.stagger-item:not(.is-in) {
  opacity: 0;
  transform: translate(var(--sx, 0), var(--sy, 12px));
}

/* Those sweeps start far outside the 1120px column, and the section's scroll
   box clips whatever leaves it. So on wide screens the scroll box of About,
   Experience, Skills, Projects, Certifications and Contact spans the full viewport (the padding keeps the content in the
   same 1120px column), and horizontal overflow is hidden so the off-column
   start positions never show a scrollbar. */
.js-slides .about .section__inner,
.js-slides .experience .section__inner,
.js-slides .skills .section__inner,
.js-slides .projects .section__inner,
.js-slides .apps .section__inner,
.js-slides .certifications .section__inner,
.js-slides .contact .section__inner { overflow-x: hidden; }
@media (min-width: 1121px) {
  .js-slides .about .section__inner,
  .js-slides .experience .section__inner,
  .js-slides .skills .section__inner,
  .js-slides .projects .section__inner,
  .js-slides .apps .section__inner,
  .js-slides .certifications .section__inner,
  .js-slides .contact .section__inner {
    max-width: none;
    padding-left: calc((100% - 1120px) / 2 + 1.5rem);
    padding-right: calc((100% - 1120px) / 2 + 1.5rem);
  }
}

.js-slides .stagger-item {
  opacity: 0;
  transform: translate(var(--sx, 0), var(--sy, 12px));
  transition: opacity 0.6s var(--slide-ease), transform 0.6s var(--slide-ease);
  transition-delay: calc(var(--d, 0) * 130ms);
  will-change: opacity, transform;
}

.js-slides main > section.is-active .stagger-item {
  opacity: 1;
  transform: translate(0, 0);
}

.js-slides .section__inner > .stagger-item:nth-child(1) { --d: 0; }
.js-slides .section__inner > .stagger-item:nth-child(2) { --d: 1; }
.js-slides .section__inner > .stagger-item:nth-child(3) { --d: 2; }
.js-slides .section__inner > .stagger-item:nth-child(4) { --d: 3; }
.js-slides .section__inner > .stagger-item:nth-child(5) { --d: 4; }
.js-slides .section__inner > .stagger-item:nth-child(6) { --d: 5; }
.js-slides .section__inner > .stagger-item:nth-child(7) { --d: 6; }

.js-slides .timeline__item.stagger-item:nth-child(1) { --d: 2; }
.js-slides .timeline__item.stagger-item:nth-child(2) { --d: 3; }
.js-slides .timeline__item.stagger-item:nth-child(3) { --d: 4; }
.js-slides .timeline__item.stagger-item:nth-child(4) { --d: 5; }

/* Skill rows sweep in from the screen edges (left column from the left, right
   column from the right, same long sweep as About and Experience), one after
   another (--i is the row index set inline). Each bar fills from empty to its
   level once its row has landed. Without .js-slides the bars simply render at
   their final width. */
.js-slides .skill.stagger-item:nth-child(odd) { --sx: -16rem; }
.js-slides .skill.stagger-item:nth-child(even) { --sx: 16rem; }
.js-slides .skill.stagger-item {
  transition-delay: calc(300ms + var(--i, 0) * 45ms);
}
.js-slides .skill__fill {
  width: 0;
  transition: width 0.9s var(--slide-ease) calc(850ms + var(--i, 0) * 45ms);
}
.js-slides main > section.is-active .skill__fill {
  width: calc(var(--level) * 1%);
}

/* Cards sweep in from the screen edges (left card from the left, right card
   from the right) with the same long sweep as Experience. The featured row
   starts at the same times as the first Experience cards and the award cards
   follow it. */
.js-slides .award-card.stagger-item:nth-child(odd) { --sx: -16rem; }
.js-slides .award-card.stagger-item:nth-child(even) { --sx: 16rem; }
.js-slides .award-card.stagger-item:nth-child(1) { --d: 2; }
.js-slides .award-card.stagger-item:nth-child(2) { --d: 3; }
.js-slides .awards .award-card.stagger-item:nth-child(1) { --d: 4; }
.js-slides .awards .award-card.stagger-item:nth-child(2) { --d: 5; }
/* The divider fades in just before the award cards it introduces. */
.js-slides .projects .section__inner > .projects__divider.stagger-item { --d: 3; --sx: 0px; }

/* App cards enter the same way as the award cards: one from each edge. */
.js-slides .app-card.stagger-item:nth-child(odd) { --sx: -16rem; }
.js-slides .app-card.stagger-item:nth-child(even) { --sx: 16rem; }
.js-slides .app-card.stagger-item:nth-child(1) { --d: 2; }
.js-slides .app-card.stagger-item:nth-child(2) { --d: 3; }

.js-slides .chip.stagger-item,
.js-slides .cert-item.stagger-item {
  transition-delay: calc(220ms + var(--ci, 0) * 45ms);
}
.js-slides .contact__link.stagger-item {
  transition-delay: calc(420ms + var(--ci, 0) * 45ms);
}
.js-slides .chip.stagger-item:nth-child(1) { --ci: 0; }
.js-slides .chip.stagger-item:nth-child(2) { --ci: 1; }
.js-slides .chip.stagger-item:nth-child(3) { --ci: 2; }
.js-slides .chip.stagger-item:nth-child(4) { --ci: 3; }
.js-slides .chip.stagger-item:nth-child(5) { --ci: 4; }
.js-slides .chip.stagger-item:nth-child(6) { --ci: 5; }
.js-slides .chip.stagger-item:nth-child(7) { --ci: 6; }
.js-slides .chip.stagger-item:nth-child(8) { --ci: 7; }
.js-slides .chip.stagger-item:nth-child(9) { --ci: 8; }
.js-slides .chip.stagger-item:nth-child(10) { --ci: 9; }
.js-slides .chip.stagger-item:nth-child(11) { --ci: 10; }
.js-slides .chip.stagger-item:nth-child(12) { --ci: 11; }
.js-slides .chip.stagger-item:nth-child(13) { --ci: 12; }

.js-slides .cert-item.stagger-item:nth-child(1) { --ci: 0; }
.js-slides .cert-item.stagger-item:nth-child(2) { --ci: 1; }
.js-slides .cert-item.stagger-item:nth-child(3) { --ci: 2; }
.js-slides .cert-item.stagger-item:nth-child(4) { --ci: 3; }
.js-slides .cert-item.stagger-item:nth-child(5) { --ci: 4; }
.js-slides .cert-item.stagger-item:nth-child(6) { --ci: 5; }
.js-slides .cert-item.stagger-item:nth-child(7) { --ci: 6; }
.js-slides .cert-item.stagger-item:nth-child(8) { --ci: 7; }

/* Certification rows: the divider line just fades in while the title sweeps in
   from the far left and the org/date text from the far right (same long sweep
   as the cards), on the row's own start time (--ci is the row index). */
.js-slides .cert-item.stagger-item { --sx: 0px; --sy: 0px; }
.js-slides .cert-item__name,
.js-slides .cert-item__meta {
  transition: transform 0.6s var(--slide-ease);
  transition-delay: calc(220ms + var(--ci, 0) * 45ms);
  will-change: transform;
}
.js-slides .cert-item__name { transform: translateX(-16rem); }
.js-slides .cert-item__meta { transform: translateX(16rem); }
.js-slides main > section.is-active .cert-item__name,
.js-slides main > section.is-active .cert-item__meta { transform: translateX(0); }

.js-slides .contact__link.stagger-item:nth-child(1) { --ci: 0; }
.js-slides .contact__link.stagger-item:nth-child(2) { --ci: 1; }
.js-slides .contact__link.stagger-item:nth-child(3) { --ci: 2; }
.js-slides .contact__link.stagger-item:nth-child(4) { --ci: 3; }
.js-slides .contact__link.stagger-item:nth-child(5) { --ci: 4; }
.js-slides .contact__link.stagger-item:nth-child(6) { --ci: 5; }
.js-slides .contact__link.stagger-item:nth-child(7) { --ci: 6; }
.js-slides .contact__link.stagger-item:nth-child(8) { --ci: 7; }

.scroll-hint {
  display: none;
  position: absolute;
  left: 50%;
  bottom: 2rem;
  transform: translateX(-50%);
  z-index: 1;
}
.js-slides .scroll-hint { display: block; }
.scroll-hint span {
  display: block;
  width: 1px;
  height: 36px;
  background: linear-gradient(var(--accent), transparent);
  animation: scrollhint 1.8s ease-in-out infinite;
  transform-origin: top;
}
@keyframes scrollhint {
  0% { transform: scaleY(0.3); opacity: 0.25; }
  50% { transform: scaleY(1); opacity: 1; }
  100% { transform: scaleY(0.3); opacity: 0.25; }
}

.slide-dots {
  position: fixed;
  right: 1.75rem;
  top: 50%;
  transform: translateY(-50%);
  z-index: 150;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}
.slide-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 1px solid var(--border-strong);
  background: transparent;
  padding: 0;
  cursor: pointer;
  transition: background 0.25s var(--ease), border-color 0.25s var(--ease), transform 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.slide-dot:hover { border-color: var(--accent); transform: scale(1.15); }
.slide-dot.is-active {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 12px -2px var(--accent-glow);
  transform: scale(1.2);
}

@media (max-width: 700px) {
  .slide-dots { display: none; }
}

/* Mobile "more below" cue: hidden on desktop (the dot column already shows
   position/progress there), shown only under the same breakpoint the dots
   hide at, and only once JS confirms the slideshow is active. */
.slide-next-btn {
  display: none;
  position: fixed;
  right: 1.25rem;
  bottom: 1.5rem;
  z-index: 150;
  width: 46px;
  height: 46px;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid rgba(255, 122, 80, 0.5);
  background: rgba(255, 122, 80, 0.55);
  color: var(--text);
  cursor: pointer;
  box-shadow: 0 10px 30px -8px var(--accent-glow), var(--shadow);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s var(--ease);
}
/* Only shown once the active section has nothing left to scroll (main.js
   tracks this, and also keeps it hidden on the last section entirely) —
   otherwise it reads as "skip ahead" while content is still visible below. */
.slide-next-btn.is-visible { opacity: 1; pointer-events: auto; }
.slide-next-btn svg {
  width: 20px;
  height: 20px;
  animation: slidenextbob 1.8s ease-in-out infinite;
}
@keyframes slidenextbob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(3px); }
}
@media (max-width: 700px) {
  .js-slides .slide-next-btn { display: flex; }
}

@media (prefers-reduced-motion: reduce) {
  .js-slides main > section { transition: none; }
  .scroll-hint span { animation: none; }
  .slide-next-btn svg { animation: none; }
}

/* ---------- Responsive ---------- */

@media (max-width: 860px) {
  .hero__inner {
    grid-template-columns: 1fr;
    min-height: auto;
    padding-top: 2rem;
    text-align: left;
  }
  .hero__portrait { order: -1; width: min(100%, 280px); margin: 0 auto 1rem; }

  .nav__links {
    position: fixed;
    inset: 68px 0 0 0;
    height: calc(100vh - 68px);
    background: rgba(11, 15, 26, 0.98);
    backdrop-filter: blur(12px);
    flex-direction: column;
    justify-content: flex-start;
    align-items: flex-start;
    gap: 0;
    padding: 1rem 1.5rem;
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s var(--ease), transform 0.25s var(--ease);
  }
  .nav__links.is-open {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }
  .nav__link {
    width: 100%;
    padding: 1rem 0;
    border-bottom: 1px solid var(--border);
    font-size: 1rem;
  }
  .nav__link--cta {
    margin-top: 1rem;
    text-align: center;
    border-radius: var(--radius-sm);
  }
  .nav__toggle { display: flex; }

  .skills__list { grid-template-columns: 1fr; gap: 1.25rem; }
  .awards, .projects__featured { grid-template-columns: 1fr; }
  .apps__grid { grid-template-columns: 1fr; }
  .contact__grid { grid-template-columns: 1fr; }
  .blog-grid { grid-template-columns: 1fr; }
  .cert-item { flex-direction: column; gap: 0.25rem; }
  .cert-item__meta { white-space: normal; }

  /* About: back to a single column in the original reading order
     (heading, text, stats, pills) by flattening the two column wrappers. */
  .about__grid { display: flex; flex-direction: column; }
  .about__intro, .about__body { display: contents; }
  .about .section__title { margin-bottom: 1.5rem; }
  .about__stats {
    order: 1;
    justify-content: flex-start;
    gap: 1.5rem 2.5rem;
    margin-top: 1.75rem;
  }
  .about__values { order: 2; }

  .timeline { max-width: none; }
  .timeline::before { left: 6px; transform: none; }
  .timeline__item,
  .timeline__item:nth-child(odd),
  .timeline__item:nth-child(even) {
    width: 100%;
    margin-left: 0;
    padding-left: 2rem;
    padding-right: 0;
  }
  .timeline__item:nth-child(odd) .timeline__marker,
  .timeline__item:nth-child(even) .timeline__marker {
    left: 0;
    right: auto;
  }

  /* The stagger-in build ins are tuned for desktop GPUs; on mobile the same
     delays stack up well past the JS input lock (main.js's ANIM_MS), so a
     section still looks mid-build when the next transition starts. Shorten
     the step and base delays so content settles closer to the slide itself. */
  .js-slides .stagger-item { transition-delay: calc(var(--d, 0) * 70ms); }
  .js-slides .skill.stagger-item { transition-delay: calc(150ms + var(--i, 0) * 30ms); }
  .js-slides .skill__fill { transition-delay: calc(450ms + var(--i, 0) * 30ms); }
  .js-slides .chip.stagger-item,
  .js-slides .cert-item.stagger-item { transition-delay: calc(120ms + var(--ci, 0) * 30ms); }
  .js-slides .cert-item__name,
  .js-slides .cert-item__meta { transition-delay: calc(120ms + var(--ci, 0) * 30ms); }
  .js-slides .contact__link.stagger-item { transition-delay: calc(220ms + var(--ci, 0) * 30ms); }
}

@media (max-width: 480px) {
  .section__inner { padding: 6rem 1.25rem 4rem; }
  .hero__actions { flex-direction: column; align-items: stretch; }
  .hero__actions .btn { width: 100%; }
}
