/* ==========================================================================
   Michael Gurguis — Engineering Portfolio
   Design system ported from the "Dala" reference style, recoloured to
   electric blue and white.

   Three rules this file must never break:
     1. Headlines are weight 400. Never bold. Hierarchy = scale + tracking.
     2. Body copy is weight 200 at 18px. This is the signature.
     3. No cards. No borders, no shadows, no non-black backgrounds.
        Everything floats on pure black, separated by whitespace alone.
   ========================================================================== */

:root {
  /* Colour. Two blues, not one: the bright one is light in the animation and
     never carries small text, the deep one fills buttons and clears 4.5:1
     against white at 14px. The neutrals are biased toward the accent rather
     than pure grey, so they read as chosen. */
  --void: #000000;
  --bone-white: #ffffff;
  --ash-gray: #8b9099;
  --silver-mist: #b4bac4;
  --arc-blue: #1b62f0;
  --arc-bright: #4d8fff;
  --ice-blue: #9dc0ff;
  --deep-arc: #0d2f6b;

  /* Type */
  --font: "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
    "Segoe UI", Roboto, sans-serif;

  --text-display: clamp(52px, 9vw, 118px);
  --text-heading-lg: clamp(36px, 5.6vw, 78px);
  --text-heading: clamp(30px, 3.6vw, 48px);
  --text-heading-sm: clamp(28px, 3.2vw, 42px);
  --text-heading-xs: clamp(22px, 2vw, 27px);
  --text-heading-2xs: clamp(20px, 1.8vw, 24px);
  --text-body: 18px;
  --text-nav: 14px;
  --text-caption: 12px;

  --w-extralight: 200;
  --w-regular: 400;
  --w-semibold: 600;

  /* Spacing — 6px base unit */
  --s6: 6px;
  --s12: 12px;
  --s18: 18px;
  --s24: 24px;
  --s30: 30px;
  --s36: 36px;
  --s60: 60px;
  --s96: 96px;
  --s120: 120px;

  --page-max: 1280px;
  --gutter: clamp(24px, 5vw, 60px);
  --nav-h: 92px;

  --radius: 24px;
  --radius-full: 9999px;

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
}

/* --------------------------------------------------------------------------
   Reset
   -------------------------------------------------------------------------- */

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

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--void);
  color: var(--bone-white);
  font-family: var(--font);
  font-size: var(--text-body);
  font-weight: var(--w-extralight);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: var(--w-regular);
  line-height: 1.1;
}

p {
  margin: 0;
}

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

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

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

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

canvas {
  display: block;
}

/* A component that sets its own display wins over the user agent's
   [hidden] rule, so state it explicitly. Without this the overlay menu stays
   in the layout at full size and swallows every click on the page. */
[hidden] {
  display: none !important;
}

::selection {
  background: var(--arc-blue);
  color: var(--bone-white);
}

:focus-visible {
  outline: 2px solid var(--ice-blue);
  outline-offset: 4px;
}

.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;
}

/* --------------------------------------------------------------------------
   Type primitives
   -------------------------------------------------------------------------- */

.display {
  font-size: var(--text-display);
  letter-spacing: -0.045em;
  line-height: 0.98;
}

.h-lg {
  font-size: var(--text-heading-lg);
  letter-spacing: -0.04em;
  line-height: 1.05;
  text-wrap: balance;
}

.h {
  font-size: var(--text-heading);
  letter-spacing: -0.04em;
  line-height: 1.1;
  text-wrap: balance;
}

.h-sm {
  font-size: var(--text-heading-sm);
  letter-spacing: -0.04em;
  line-height: 1.15;
}

.h-xs {
  font-size: var(--text-heading-xs);
  letter-spacing: -0.02em;
  line-height: 1.15;
}

.h-2xs {
  font-size: var(--text-heading-2xs);
  letter-spacing: -0.02em;
  line-height: 1.25;
}

.eyebrow {
  display: block;
  font-size: var(--text-nav);
  font-weight: var(--w-semibold);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ice-blue);
  line-height: 1.2;
}

.eyebrow--muted {
  color: var(--ash-gray);
}

.lede {
  font-size: var(--text-body);
  font-weight: var(--w-extralight);
  line-height: 1.55;
  color: var(--bone-white);
}

.body {
  font-size: var(--text-body);
  font-weight: var(--w-extralight);
  line-height: 1.55;
  color: var(--silver-mist);
}

.caption {
  font-size: var(--text-caption);
  font-weight: var(--w-regular);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ash-gray);
  line-height: 1.5;
}

.measure {
  max-width: 52ch;
}

/* Availability line, with a pulsing indicator */
.status {
  display: inline-flex;
  align-items: center;
  gap: var(--s12);
  font-size: var(--text-caption);
  font-weight: var(--w-semibold);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ash-gray);
}

.status__dot {
  position: relative;
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: var(--radius-full);
  background: var(--arc-bright);
}

.status__dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: inherit;
  animation: ping 2.4s var(--ease-out) infinite;
}

@keyframes ping {
  0% {
    transform: scale(1);
    opacity: 0.7;
  }
  70%,
  100% {
    transform: scale(3.4);
    opacity: 0;
  }
}

/* --------------------------------------------------------------------------
   Layout
   -------------------------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--page-max);
  margin: 0 auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: clamp(var(--s60), 9vw, var(--s120));
  position: relative;
}

/* A section standing alone as its own page needs to clear the fixed nav */
.section--page {
  padding-top: calc(var(--nav-h) + clamp(var(--s36), 6vw, var(--s96)));
}

.section-head {
  display: flex;
  flex-direction: column;
  gap: var(--s18);
  margin-bottom: clamp(var(--s36), 5vw, var(--s60));
}

.split {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(var(--s36), 5vw, var(--s96));
  align-items: center;
}

@media (min-width: 900px) {
  .split {
    grid-template-columns: 1fr 1fr;
  }

  /* Zigzag: flip the visual to the other side */
  .split--flip .split__visual {
    order: -1;
  }
}

/* Where one column is much shorter than the other, centring leaves the short
   side floating. Align both to the top instead. */
.split--top {
  align-items: start;
}

/* --------------------------------------------------------------------------
   Buttons and links
   -------------------------------------------------------------------------- */

.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--s12);
  background: var(--arc-blue);
  color: var(--bone-white);
  font-size: var(--text-nav);
  font-weight: var(--w-semibold);
  letter-spacing: 0.025em;
  text-transform: uppercase;
  line-height: 1;
  padding: 15px 22px;
  border-radius: var(--radius-full);
  cursor: pointer;
  position: relative;
  transition: transform 0.4s var(--ease-out), background 0.35s var(--ease-out);
  will-change: transform;
}

.pill:hover {
  background: var(--arc-bright);
}

.pill__arrow {
  transition: transform 0.4s var(--ease-out);
}

.pill:hover .pill__arrow {
  transform: translateX(4px);
}

.ghost {
  display: inline-flex;
  align-items: center;
  gap: var(--s6);
  font-size: var(--text-nav);
  font-weight: var(--w-regular);
  letter-spacing: 0.025em;
  text-transform: uppercase;
  color: var(--ash-gray);
  transition: color 0.3s var(--ease-out);
}

.ghost:hover {
  color: var(--bone-white);
}

.contact-link {
  display: inline-block;
  font-size: var(--text-heading-2xs);
  font-weight: var(--w-extralight);
  letter-spacing: -0.01em;
  color: var(--bone-white);
  position: relative;
  padding-bottom: 3px;
}

.contact-link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--arc-bright);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.45s var(--ease-out);
}

.contact-link:hover::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* --------------------------------------------------------------------------
   Navigation
   -------------------------------------------------------------------------- */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  padding-block: var(--s24);
  transition: transform 0.5s var(--ease-out);
}

.nav--hidden {
  transform: translateY(-110%);
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s24);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--s12);
  font-size: var(--text-nav);
  font-weight: var(--w-regular);
  color: var(--bone-white);
  flex: none;
}

.brand__mark {
  flex: none;
  transition: transform 0.6s var(--ease-out);
}

.brand:hover .brand__mark {
  transform: rotate(90deg);
}

.nav__links {
  display: none;
  align-items: center;
  gap: clamp(var(--s18), 2vw, var(--s30));
}

/* Six tabs need real room. Below this the overlay menu takes over. */
@media (min-width: 1040px) {
  .nav__links {
    display: flex;
  }
}

.nav__link {
  font-size: var(--text-nav);
  font-weight: var(--w-semibold);
  letter-spacing: 0.025em;
  text-transform: uppercase;
  color: var(--ash-gray);
  transition: color 0.3s var(--ease-out);
  position: relative;
}

.nav__link:hover,
.nav__link[aria-current="page"] {
  color: var(--bone-white);
}

.nav__link[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -7px;
  height: 1px;
  background: var(--arc-bright);
}

.nav__end {
  display: flex;
  align-items: center;
  gap: var(--s18);
  flex: none;
}

.nav__cta {
  display: none;
}

@media (min-width: 560px) {
  .nav__cta {
    display: inline-flex;
  }
}

.nav__toggle {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 34px;
  height: 34px;
  align-items: flex-end;
}

.nav__toggle-bar {
  display: block;
  height: 1.5px;
  width: 22px;
  background: var(--bone-white);
  transition: transform 0.4s var(--ease-out), width 0.4s var(--ease-out);
}

.nav__toggle-bar:last-child {
  width: 14px;
}

.nav__toggle:hover .nav__toggle-bar:last-child {
  width: 22px;
}

.nav__toggle[aria-expanded="true"] .nav__toggle-bar:first-child {
  transform: translateY(3.25px) rotate(45deg);
}

.nav__toggle[aria-expanded="true"] .nav__toggle-bar:last-child {
  width: 22px;
  transform: translateY(-3.25px) rotate(-45deg);
}

/* Declared after .nav__toggle's own display, otherwise the later rule wins */
@media (min-width: 1040px) {
  .nav__toggle {
    display: none;
  }
}

/* Overlay menu */
.menu {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: var(--void);
  display: flex;
  align-items: center;
  opacity: 0;
  transition: opacity 0.4s var(--ease-out);
}

.menu[hidden] {
  display: none;
}

.menu.is-open {
  opacity: 1;
}

.menu__inner {
  display: flex;
  flex-direction: column;
  gap: var(--s12);
}

.menu__link {
  font-size: clamp(34px, 8vw, 60px);
  font-weight: var(--w-regular);
  letter-spacing: -0.04em;
  line-height: 1.1;
  color: var(--ash-gray);
  overflow: hidden;
  transition: color 0.3s var(--ease-out);
}

.menu__link:hover,
.menu__link[aria-current="page"] {
  color: var(--bone-white);
}

.menu__link > span {
  display: block;
  transform: translateY(110%);
  transition: transform 0.7s var(--ease-out);
  transition-delay: calc(var(--i) * 0.05s + 0.1s);
}

.menu.is-open .menu__link > span {
  transform: none;
}

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

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  /* Deliberately not align-items: center. Centring overflows equally in both
     directions once the content is taller than the box, which pushes the
     eyebrow up underneath the fixed nav. An auto block margin centres while
     still respecting the padding. */
  align-items: flex-start;
  padding-block: clamp(120px, 17vh, 176px) clamp(var(--s60), 10vh, var(--s96));
  overflow: hidden;
}

.hero__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s60);
  align-items: center;
  width: 100%;
  margin-block: auto;
  position: relative;
  z-index: 1;
}

@media (min-width: 980px) {
  .hero__grid {
    grid-template-columns: minmax(0, 1.04fr) minmax(0, 1fr);
    gap: var(--s36);
  }
}

.hero__copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s30);
  position: relative;
  z-index: 2;
}

.hero__title {
  margin-block: calc(var(--s12) * -1);
}

.hero__actions {
  display: flex;
  align-items: center;
  gap: var(--s30);
  flex-wrap: wrap;
}

/* Portrait in front, transmission line running behind it */
.hero__visual {
  position: relative;
  aspect-ratio: 1 / 1;
  width: 100%;
  max-width: 640px;
  margin-inline: auto;
}

@media (max-width: 979px) {
  .hero__visual {
    max-width: 460px;
    aspect-ratio: 3 / 4;
  }
}

/* Gradients are allowed here. The reference permits them in the logo and the
   signature visualisation, nowhere else. */
.hero__bloom {
  position: absolute;
  inset: -20%;
  background: radial-gradient(
    circle at 50% 52%,
    rgba(77, 143, 255, 0.28) 0%,
    rgba(27, 98, 240, 0.1) 34%,
    rgba(13, 47, 107, 0.06) 54%,
    transparent 72%
  );
  filter: blur(20px);
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.6s var(--ease-out);
}

.is-ready .hero__bloom {
  opacity: 1;
}



.hero__portrait {
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  width: min(66%, 380px);
  z-index: 1;
}

.hero__portrait img {
  width: 100%;
  height: auto;
  border-radius: var(--radius);
  /* The lower edge dissolves into the void, so the portrait is part of the
     scene rather than a card sitting on top of it. */
  -webkit-mask-image: linear-gradient(
    to bottom,
    #000 0%,
    #000 58%,
    rgba(0, 0, 0, 0.55) 82%,
    transparent 100%
  );
  mask-image: linear-gradient(
    to bottom,
    #000 0%,
    #000 58%,
    rgba(0, 0, 0, 0.55) 82%,
    transparent 100%
  );
}

.hero__portrait.reveal {
  transform: translateX(-50%) translateY(28px);
}

.hero__portrait.reveal.in-view {
  transform: translateX(-50%);
}

.hero__cue {
  position: absolute;
  left: var(--gutter);
  bottom: var(--s36);
  display: none;
  align-items: center;
  gap: var(--s12);
  color: var(--ash-gray);
  font-size: var(--text-caption);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

@media (min-width: 980px) {
  .hero__cue {
    display: flex;
  }
}

.hero__cue-line {
  width: 54px;
  height: 1px;
  background: linear-gradient(
    90deg,
    var(--ash-gray) 0%,
    rgba(139, 144, 153, 0) 100%
  );
  transform-origin: left;
  animation: cue 2.6s var(--ease-in-out) infinite;
}

@keyframes cue {
  0%,
  100% {
    transform: scaleX(0.35);
    opacity: 0.4;
  }
  50% {
    transform: scaleX(1);
    opacity: 1;
  }
}

/* --------------------------------------------------------------------------
   Numbers
   -------------------------------------------------------------------------- */

.numbers {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(var(--s30), 4vw, var(--s60)) var(--s24);
}

@media (min-width: 860px) {
  .numbers {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.number__value {
  font-size: var(--text-heading);
  font-weight: var(--w-regular);
  letter-spacing: -0.04em;
  line-height: 1;
  color: var(--bone-white);
  display: block;
  font-variant-numeric: tabular-nums;
}

.number__label {
  display: block;
  margin-top: var(--s12);
  font-size: var(--text-caption);
  font-weight: var(--w-semibold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ice-blue);
}

.number__note {
  display: block;
  margin-top: var(--s6);
  font-size: var(--text-caption);
  font-weight: var(--w-extralight);
  letter-spacing: 0;
  text-transform: none;
  color: var(--ash-gray);
}

/* --------------------------------------------------------------------------
   Work
   -------------------------------------------------------------------------- */

.project {
  padding-block: clamp(var(--s60), 7vw, var(--s96));
}

.project__copy {
  display: flex;
  flex-direction: column;
  gap: var(--s30);
}

.project__index {
  font-size: var(--text-caption);
  font-weight: var(--w-semibold);
  letter-spacing: 0.2em;
  color: var(--arc-bright);
}

.project__title {
  margin-top: var(--s12);
}

.project__blocks {
  display: flex;
  flex-direction: column;
  gap: var(--s24);
}

.project__block {
  display: flex;
  flex-direction: column;
  gap: var(--s6);
}

.project__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s12) var(--s18);
  padding-top: var(--s6);
}

.tag {
  font-size: var(--text-caption);
  font-weight: var(--w-regular);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ash-gray);
}

.project__visual {
  position: relative;
}

.frame {
  border-radius: var(--radius);
  overflow: hidden;
  position: relative;
}

.frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transform: scale(1.06);
  transition: transform 1.2s var(--ease-out);
}

.frame--tall {
  aspect-ratio: 4 / 5;
}

.frame--wide {
  aspect-ratio: 4 / 3;
}

.frame--square {
  aspect-ratio: 1 / 1;
}

.in-view .frame img {
  transform: scale(1);
}

.project__visual:hover .frame img {
  transform: scale(1.04);
}

.shots {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s18);
  margin-top: var(--s18);
}

.shots .frame {
  aspect-ratio: 4 / 3;
}

.shots--one {
  grid-template-columns: 1fr;
}

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

.about__portrait {
  max-width: 460px;
}

.about__copy {
  display: flex;
  flex-direction: column;
  gap: var(--s24);
}

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

.timeline {
  display: flex;
  flex-direction: column;
  gap: clamp(var(--s36), 4.5vw, var(--s60));
}

.role {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s18);
}

@media (min-width: 860px) {
  .role {
    grid-template-columns: minmax(0, 260px) minmax(0, 1fr);
    gap: var(--s60);
  }
}

.role__meta {
  display: flex;
  flex-direction: column;
  gap: var(--s6);
}

/* Company marks, rendered white so two different brand palettes do not fight
   each other or the page. The university logo keeps its own colours because it
   is the subject of its section; these are supporting detail. */
.role__logo {
  display: block;
  height: 24px;
  margin-bottom: var(--s12);
}

.role__logo img {
  height: 100%;
  width: auto;
  opacity: 0.85;
  /* Flattens any artwork to solid white, whatever it started as */
  filter: brightness(0) invert(1);
  transition: opacity 0.35s var(--ease-out);
}

.role:hover .role__logo img {
  opacity: 1;
}

.role__org {
  font-size: var(--text-heading-2xs);
  font-weight: var(--w-regular);
  letter-spacing: -0.02em;
  color: var(--bone-white);
}

.role__dates,
.role__place {
  font-size: var(--text-caption);
  font-weight: var(--w-regular);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ash-gray);
}

.role__body {
  display: flex;
  flex-direction: column;
  gap: var(--s30);
}

.post {
  display: flex;
  flex-direction: column;
  gap: var(--s12);
}

.post__title {
  font-size: var(--text-heading-xs);
  font-weight: var(--w-regular);
  letter-spacing: -0.02em;
  color: var(--bone-white);
}

.post__when {
  font-size: var(--text-caption);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--arc-bright);
  font-weight: var(--w-semibold);
}

.bullets {
  display: flex;
  flex-direction: column;
  gap: var(--s12);
}

.bullets li {
  font-size: var(--text-body);
  font-weight: var(--w-extralight);
  line-height: 1.55;
  color: var(--silver-mist);
  padding-left: var(--s24);
  position: relative;
}

.bullets li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.68em;
  width: 7px;
  height: 7px;
  background: var(--arc-bright);
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

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

.skills {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(var(--s30), 4vw, var(--s60));
}

@media (min-width: 700px) {
  .skills {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1060px) {
  .skills {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.skill-group {
  display: flex;
  flex-direction: column;
  gap: var(--s18);
}

.skill-list {
  display: flex;
  flex-direction: column;
  gap: var(--s12);
}

.skill-list li {
  display: flex;
  align-items: center;
  gap: var(--s12);
  font-size: var(--text-body);
  font-weight: var(--w-extralight);
  color: var(--silver-mist);
  line-height: 1.4;
}

.skill-list li > span {
  transition: color 0.3s var(--ease-out);
}

.skill-list li:hover > span {
  color: var(--bone-white);
}

/* Icons are drawn rather than borrowed. Vendor logos are full-colour marks in
   a dozen different styles, and dropping them on pure black would break both
   the single-accent rule and the no-cards rule this design runs on. */
.skill-emblem {
  display: block;
  color: var(--arc-bright);
  margin-bottom: var(--s6);
}

.skill-icon {
  flex: none;
  color: var(--ash-gray);
  transition: color 0.35s var(--ease-out), transform 0.45s var(--ease-out);
}

.skill-list li:hover .skill-icon {
  color: var(--arc-bright);
  transform: translateY(-2px) scale(1.1);
}

/* pathLength="100" on every shape normalises its length, so one rule draws any
   of them in regardless of the actual geometry. */
.skill-icon path,
.skill-icon circle,
.skill-emblem__svg path,
.skill-emblem__svg circle {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  transition: stroke-dashoffset 1s var(--ease-out);
  transition-delay: calc(var(--i, 0) * 0.08s + 0.15s);
}

.skill-emblem__svg path,
.skill-emblem__svg circle {
  transition-duration: 1.5s;
  transition-delay: 0.1s;
}

.in-view .skill-icon path,
.in-view .skill-icon circle,
.in-view .skill-emblem__svg path,
.in-view .skill-emblem__svg circle {
  stroke-dashoffset: 0;
}

/* --------------------------------------------------------------------------
   Education
   -------------------------------------------------------------------------- */

.edu {
  display: flex;
  flex-direction: column;
  gap: var(--s30);
}

/* The university's own mark, in its own colours. A real institutional logo
   earns the exception to the single-accent rule; recolouring it would be
   worse than leaving it alone. */
.edu__logo {
  position: relative;
  width: min(280px, 78%);
  margin-top: var(--s24);
}

/* The float lives on the image, not the wrapper. The wrapper carries .reveal,
   whose entrance also animates transform, and an animation on the same element
   would win over that transition and skip the entrance. */
.edu__logo img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: auto;
  animation: float 7s var(--ease-in-out) infinite;
}

.edu__logo-bloom {
  position: absolute;
  inset: -34%;
  background: radial-gradient(
    circle at 50% 50%,
    rgba(77, 143, 255, 0.22) 0%,
    rgba(27, 98, 240, 0.08) 42%,
    transparent 70%
  );
  filter: blur(22px);
  pointer-events: none;
}

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

.edu__degree {
  font-size: var(--text-heading-xs);
  font-weight: var(--w-regular);
  letter-spacing: -0.02em;
}

.inline-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s12) var(--s24);
}

.inline-list li {
  font-size: var(--text-body);
  font-weight: var(--w-extralight);
  color: var(--silver-mist);
}

.certs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s12) var(--s18);
}

.certs li {
  font-size: var(--text-caption);
  font-weight: var(--w-regular);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ash-gray);
}

/* --------------------------------------------------------------------------
   Contact and footer
   -------------------------------------------------------------------------- */

.contact {
  padding-block: clamp(var(--s96), 14vw, 200px);
  position: relative;
}

.contact.section--page {
  padding-top: calc(var(--nav-h) + clamp(var(--s36), 6vw, var(--s96)));
}

.contact__inner {
  display: flex;
  flex-direction: column;
  gap: clamp(var(--s30), 4vw, var(--s60));
  align-items: flex-start;
}

.contact__links {
  display: flex;
  flex-direction: column;
  gap: var(--s18);
}

.footer {
  padding-block: var(--s36) var(--s60);
}

.footer__inner {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s18) var(--s30);
  align-items: center;
  justify-content: space-between;
}

/* --------------------------------------------------------------------------
   Persistent background. Sits behind everything and keeps running across
   page changes, so the site never blinks between routes.
   -------------------------------------------------------------------------- */

/* The 3D stage. One canvas, fixed behind everything, showing whichever
   scene the section nearest the middle of the viewport asks for. */
#stage {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 2.4s var(--ease-out);
}

.is-ready #stage {
  opacity: 0.95;
}

@media (max-width: 760px) {
  .is-ready #stage {
    opacity: 0.7;
  }
}

/* The 2D circuit traces stay, well behind the 3D, as a base texture so the
   black is never flat between scenes. */
#ambient {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 2s var(--ease-out);
}

.is-ready #ambient {
  opacity: 0.7;
}

/* --------------------------------------------------------------------------
   Page transitions. The background canvas lives outside <main>, so only the
   content slides; the traces behind it never restart.
   -------------------------------------------------------------------------- */

.page {
  position: relative;
  z-index: 1;
  transition: opacity 0.28s var(--ease-in-out),
    transform 0.28s var(--ease-in-out);
}

.page.is-leaving {
  opacity: 0;
  transform: translateX(-44px);
}

.page.is-entering {
  opacity: 0;
  transform: translateX(44px);
  transition: none;
}

/* --------------------------------------------------------------------------
   Scroll reveal
   -------------------------------------------------------------------------- */

.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.9s var(--ease-out), transform 0.9s var(--ease-out);
}

.reveal.in-view {
  opacity: 1;
  transform: none;
}

.line-mask {
  display: block;
  overflow: hidden;
  padding-block: 0.08em;
  margin-block: -0.08em;
}

.line-mask > span {
  display: block;
  transform: translateY(105%);
  transition: transform 1.05s var(--ease-out);
}

.in-view .line-mask > span,
.line-mask.in-view > span {
  transform: none;
}

.reveal[style*="--d"] {
  transition-delay: var(--d);
}

.line-mask[style*="--d"] > span {
  transition-delay: var(--d);
}

/* --------------------------------------------------------------------------
   Reduced motion — everything resolves to its final state
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

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

  .reveal {
    opacity: 1;
    transform: none;
  }

  .hero__portrait.reveal {
    transform: translateX(-50%);
  }

  .line-mask > span {
    transform: none;
  }

  .frame img {
    transform: none;
  }

  .menu__link > span {
    transform: none;
  }

  .skill-icon path,
  .skill-icon circle,
  .skill-emblem__svg path,
  .skill-emblem__svg circle {
    stroke-dashoffset: 0;
  }

  .edu__logo img {
    animation: none;
  }

  .page.is-leaving,
  .page.is-entering {
    opacity: 1;
    transform: none;
  }

  .hero__bloom,
  #ambient {
    opacity: 1;
  }
}

/* --------------------------------------------------------------------------
   Reading focus. Hovering a paragraph brightens it and thickens its strokes,
   so the one you are reading stands out against the animation behind it.

   This deliberately does not change font-weight. A heavier weight makes
   every glyph wider, the lines rewrap, and the paragraph jumps under the
   cursor. Two hairline shadows either side of each stroke thicken it the way
   a bold cut does, with the letter widths, and so the layout, left alone.
   At rest the copy is still weight 200, which is the signature of the design.
   -------------------------------------------------------------------------- */

.lede,
.body,
.bullets li {
  /* Same number of shadows at rest and on hover, or it cannot animate */
  text-shadow: 0 0 0 rgba(255, 255, 255, 0), 0 0 0 rgba(255, 255, 255, 0);
  transition: color 0.35s var(--ease-out), text-shadow 0.35s var(--ease-out);
}

/* Only where there is a real pointer. On a touchscreen a tap would leave the
   paragraph stuck in its hover state until you tapped somewhere else. */
@media (hover: hover) and (pointer: fine) {
  .lede:hover,
  .body:hover,
  .bullets li:hover {
    color: var(--bone-white);
    text-shadow: 0.4px 0 0 rgba(255, 255, 255, 0.92),
      -0.4px 0 0 rgba(255, 255, 255, 0.92);
  }
}
