/* =============================================================================
   THEME GRADE  —  assets/theme-grade.css
   -----------------------------------------------------------------------------
   BAKED GRADE A — "Aurora".

   This file IS the site's colour grade now: there is no html[data-theme]
   attribute, no switcher, no query parameter.  Every rule applies
   unconditionally, so what ships is exactly what the owner approved as A.

   ADDITIVE ONLY — not one line of the site's original CSS is edited or
   removed.  Every selector is written as `html <selector>` (or `:root` for the
   custom properties) on purpose: the two extra component stylesheets
   (Navbar-*.css / MainContainer-*.css) are injected into <head> at runtime by
   the module loader, so they land AFTER this file in document order.  The
   `html ` prefix lifts this file's specificity one level so the grade still
   wins every cascade tie regardless of load order.

   The site already carries two custom properties, --accentColor and
   --backgroundColor, used in 35 places.  Redefining them does most of the
   recolouring for free and, critically, keeps every opaque mask
   (.character-model::before/:after, .work-link, .loading-marquee span::before)
   the exact same colour as the page — so there are no seams.

   Colour order of appearance:
     1. sRGB hex tokens      (always work)
     2. oklch()              (inside @supports — wide-gamut screens)
     3. color(display-p3 …)  (glow / accent highlights ONLY, inside @supports)

   Nothing here relies on display-p3; it is a progressive enhancement layered
   on top of a fully working sRGB value.

   ONE DELIBERATE EXCEPTION — --backgroundColor stays plain sRGB hex, always.
   It is the only token in this file that a JavaScript animation engine reads
   as a COLOUR VALUE.  assets/initialFX-*.js (a guarded file this grade must
   never edit) runs

       gsap.to("body", { backgroundColor: "#0a0e17", duration: .5, delay: 1 })

   and GSAP resolves the tween's START value from the computed background of
   <body>, which is var(--backgroundColor).  GSAP cannot parse oklch() or
   color(display-p3 …): when it met oklch(0.150 0.021 264.3) it fell back to
   a guessed sRGB triple and the page flashed through a BLUE intermediate
   (measured: rgba(9, 12, 53, .88)) that the original site never showed,
   because the original token was plain hex.

   So --backgroundColor is pinned to #0a0e17 — the exact colour initialFX
   tweens body TO.  Start and end are then the same plain hex, so the tween
   interpolates between two identical colours and cannot pass through any hue
   at all.  It also means every opaque mask built from this token
   (.character-model::before/:after, .nav-fade, .work-link) now sits on
   precisely the colour the page settles at, instead of 1.02:1 beside it.

   Everything else keeps its treatment: the accent hierarchy, the surfaces and
   the lines still upgrade to oklch()/display-p3 where supported, and the
   aurora glows, grain and vignette keep their rgba/SVG values.  Nothing in
   that set is interpolated by a colour engine — the compositor paints them
   directly — so none of them can reproduce the flash.
   ============================================================================= */


/* -----------------------------------------------------------------------------
   1.  TOKENS — sRGB hex.  This block is the universal fallback.
   ----------------------------------------------------------------------------- */

:root {
  /* A — "Aurora": deep blue-black, cool tinted neutrals, teal→cyan→violet */
  /* Pinned to plain hex: GSAP reads this value on <body> to start its tween.
     See the "ONE DELIBERATE EXCEPTION" note in the header. */
  --backgroundColor:   #0a0e17;
  --text:              #eef2f6;   /*                    (17.2:1 on bg) */
  --text-muted:        #9aa7b4;   /*                     (7.9:1 on bg) */
  --accentColor:       #5eead4;   /* primary teal        (13.1:1 on bg) */
  --grade-accent-2:    #67e8f9;   /* secondary cyan      (13.3:1 on bg) */
  --grade-accent-3:    #a78bfa;   /* tertiary violet      (7.1:1 on bg) */
  --grade-surface:     #0d1421;
  --grade-line:        #1d2836;
  --grade-glass:       rgba(94, 234, 212, .05);
  --grade-glass-hi:    rgba(94, 234, 212, .09);
  --grade-border:      rgba(255, 255, 255, .09);
  --grade-border-hi:   rgba(94, 234, 212, .38);
  --grade-glow-1:      rgba(94, 234, 212, .14);
  --grade-glow-2:      rgba(167, 139, 250, .12);
  --grade-glow-3:      rgba(103, 232, 249, .10);
  --grade-cta-fill:    #0b1620;
  --grade-hover-tint:  rgba(94, 234, 212, .20);
  --grade-hover-glow:  rgba(94, 234, 212, .32);
}


/* -----------------------------------------------------------------------------
   2.  oklch() — replaces the hex above where oklch is supported.
       Same colour, expressed perceptually so the hues stay balanced on
       wide-gamut displays.

       --backgroundColor is deliberately ABSENT from this block.  It is the
       one token an animation engine parses as a colour value: initialFX
       tweens <body>'s background to the plain hex "#0a0e17", and GSAP
       cannot read oklch(), so upgrading the token made the intro tween
       flash through a blue intermediate.  It stays pinned to hex in
       section 1.  Nothing is lost visually — oklch(0.150 0.021 264.3) is
       simply this same #0a0e17 expressed perceptually.
   ----------------------------------------------------------------------------- */

@supports (color: oklch(0 0 0)) {
  :root {
    --text:              oklch(0.959 0.007 247.9);
    --text-muted:        oklch(0.722 0.024 248.2);
    --accentColor:       oklch(0.855 0.125 181.1);
    --grade-accent-2:    oklch(0.865 0.115 207.1);
    --grade-accent-3:    oklch(0.709 0.159 293.5);
    --grade-surface:     oklch(0.191 0.029 262.3);
    --grade-line:        oklch(0.273 0.030 254.7);
  }
}


/* -----------------------------------------------------------------------------
   3.  color(display-p3 …) — GLOW AND ACCENT HIGHLIGHTS ONLY.
       Never used for a surface, never used for text, never load-bearing:
       if a browser does not support it the oklch/hex value above already
       gives the correct colour.
   ----------------------------------------------------------------------------- */

@supports (color: color(display-p3 0 0 0)) {
  :root {
    --accentColor:    color(display-p3 0.5252 0.9059 0.8327);
    --grade-accent-2: color(display-p3 0.5418 0.8986 0.9654);
    --grade-accent-3: color(display-p3 0.6372 0.5492 0.9526);
  }
}


/* -----------------------------------------------------------------------------
   4.  BACKGROUND DEPTH — aurora glows + grain + vignette.
       ONE background painted on body (glows, grain, vignette), so every
       section draws from the same surface.  .work-section and .contact-section
       stay TRANSPARENT — verified: the 3D character cannot reach them at
       1440 / 1024 / 390 — which is what guarantees zero seams rather than
       trying to repaint the gradient inside each box (which the scroll
       transform would break).
   ----------------------------------------------------------------------------- */

html {
  --grade-grain: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/></filter><rect width='140' height='140' filter='url(%23n)' opacity='0.035'/></svg>");
}

/* The glows, the grain and the vignette are all layers of ONE background on
   body.  They cannot live on a z-index:-1 pseudo-element: html's own
   background-color is opaque, so it would simply paint over them.  Because
   there is only one background, and .work-section / .contact-section are
   transparent, every section draws from the same surface — no seams.

   background-color MUST stay a var() pointing at the pinned hex token: this
   declaration is the START value of initialFX's gsap.to("body", …) tween, so
   it has to resolve to something GSAP can parse.  Only background-image is
   free to use the wide-gamut tokens — the compositor paints those directly
   and no colour engine has to interpolate them. */
html body {
  background-color: var(--backgroundColor);
  background-image:
    radial-gradient(1100px 720px at 6% -8%,   var(--grade-glow-1) 0%, transparent 62%),
    radial-gradient(980px 680px  at 96% -4%,  var(--grade-glow-2) 0%, transparent 64%),
    radial-gradient(1200px 820px at 50% 112%, var(--grade-glow-3) 0%, transparent 62%),
    var(--grade-grain),
    radial-gradient(140% 110% at 50% 40%, transparent 52%, rgba(0, 0, 0, .45) 100%);
  background-repeat: no-repeat, no-repeat, no-repeat, repeat, no-repeat;
  background-size: 100% 100%, 100% 100%, 100% 100%, 140px 140px, 100% 100%;
}

/* These two were opaque var(--backgroundColor) specifically to occlude the
   character.  The character cannot reach them:
     · 1024 / 390 — .character-model is position:absolute inside
       .landing-section, so it scrolls away with the hero (measured
       offsetParent = .landing-section; Work starts 3173px / 4031px below it).
     · 1440 — .character-model is position:fixed, but Fe() scrubs its y from
       0% to -100% across .whatIDO ("top top" → "bottom top").  Career +
       Education sit between .whatIDO and .work-section (2261px at 1440), so
       the container is a full viewport-height above the viewport before the
       first pixel of Work can enter it.
   Transparency is therefore safe, and it is what lets the single background
   run through them without a colour jump. */
html .work-section,
html .contact-section {
  background-color: transparent;
}

/* The two masks that blend the character into the page must still paint an
   opaque graded colour, or the 3D canvas would show through them. */
html .character-model::before {
  background-color: var(--backgroundColor);
}
html .character-model::after {
  background-image: linear-gradient(to bottom, transparent, var(--backgroundColor) 70%);
}
/* .nav-fade is the sticky top scrim that GSAP fades in over the header
   (position:fixed, 130px tall, z-index:14, pointer-events:none).  It used to
   paint a FLAT --backgroundColor gradient.  On the original site that is
   invisible, because the page behind it IS flat --backgroundColor — but the
   grade paints aurora glows back there, so the flat plate flattened them into
   a visible dark band.  Measured: a 5-9 RGB-unit step between the band and the
   page just below it (1440: (9,13,21) in-band vs (13,18,27) below).

   It is now a colour-NEUTRAL fade: no paint of its own, only a blur of what is
   already behind it, masked so the effect dissolves to nothing by the bottom
   of the box.  Nothing moves — position, size, z-index, pointer-events and the
   opacity GSAP animates are all untouched, so the Navbar's own animation still
   drives exactly what it drove before. */
html .nav-fade {
  background-image: none;
  -webkit-backdrop-filter: blur(6px) saturate(1.1);
  backdrop-filter: blur(6px) saturate(1.1);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, transparent 100%);
}

/* Fallback for engines without backdrop-filter: the old gradient kept, but at
   LOW alpha instead of opaque, so a hard band can never form.  At the peak
   alpha below the page moves by <= 2 RGB units even over the brightest glow
   the grade paints (18,22,33):  0.18*(10,14,23) + 0.82*(18,22,33)
   = (16.6, 20.6, 31.2)  ->  step of 2. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  html .nav-fade {
    background-image: linear-gradient(0deg, rgba(10, 14, 23, 0) 0%, rgba(10, 14, 23, .18) 100%);
    -webkit-mask-image: none;
    mask-image: none;
  }
}


/* -----------------------------------------------------------------------------
   5.  RECOLOUR — every hard-coded teal / cyan / purple in the site.
       Colour only.  No size, position, geometry, timing or behaviour changes.
   ----------------------------------------------------------------------------- */

/* --- page chrome ----------------------------------------------------------- */
:root {
  color: var(--text);
}

/* The header's own painted plate is removed.  The original site painted
   rgba(10,14,23,.18) here, invisible only because the page behind it was
   exactly that colour; over the grade's glows any flat tint reads as a
   rectangle, and this grade had darkened it to rgba(8,10,16,.30) — nearly
   twice the opacity.  The strip scan found a discrete 3-unit horizontal step
   at y=97px, which is precisely this element's bottom edge (its box is
   1354x97 at 1440).  Legibility is carried by the text-shadow and by
   .nav-fade's blur, not by a painted panel, so nothing is lost. */
html .header {
  background-color: transparent;
  text-shadow: 0 1px 4px rgba(0, 0, 0, .8);
}
html .header ul li,
html .header ul li a {
  color: var(--text);
}

/* the scroll progress strip (item 13) */
html .scroll-progress {
  background: linear-gradient(90deg, var(--accentColor) 0%, var(--grade-accent-2) 100%);
}

/* --- hero ------------------------------------------------------------------ */
html .landing-intro h2,
html .landing-info h3 {
  color: var(--accentColor);
}
html h2.landing-info-h2 {
  color: var(--grade-accent-2);
}
html .landing-circle2 {
  background-color: var(--grade-accent-2);
  box-shadow: inset -50px 40px 50px color-mix(in srgb, var(--accentColor) 60%, transparent);
}
html .character-rim {
  background-color: var(--grade-accent-2);
  box-shadow: inset 66px 35px 85px color-mix(in srgb, var(--accentColor) 65%, transparent);
}

/* the cursor blob — colour only, the component itself is untouched */
html .cursor-main {
  background-color: var(--grade-accent-3);
  box-shadow: 0 0 30px color-mix(in srgb, var(--grade-accent-3) 80%, transparent);
}

/* --- about / what i do ----------------------------------------------------- */
html .about-me h3 {
  color: var(--accentColor);
}
html .do-h2 {
  color: var(--accentColor);
}
html .what-header-text h3 {
  color: var(--text);
}
html .what-header-text h4,
html .what-chevron {
  color: var(--accentColor);
}
html .what-content p {
  color: var(--text-muted);
}
html .what-tags {
  color: var(--text-muted);
}
html .what-corner,
html .what-accordion::after {
  border-color: var(--accentColor);
}
html .what-content.open {
  background: var(--grade-glass-hi);
}
html .what-content:hover {
  background: var(--grade-glass-hi);
}
html .what-content:hover {
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accentColor) 22%, transparent),
              0 0 26px color-mix(in srgb, var(--accentColor) 14%, transparent);
}

/* --- career / education ----------------------------------------------------
    Only the gradient colours and the dot glow colours change.  Width, height,
    position, border-radius and the animation's duration / timing / iteration
    count are all left exactly as they are.                              */
html .career-section h2,
html .education-section h2 {
  background: linear-gradient(0deg, var(--accentColor), var(--text));
  /* the shorthand above resets background-clip, so it has to be restated or
     the gradient fills the whole box instead of the glyphs */
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
html .career-info h5,
html .education-info h5 {
  color: var(--accentColor);
}
html .career-timeline,
html .education-timeline {
  background-image: linear-gradient(to top,
    var(--accentColor) 20%, var(--grade-accent-2) 50%, transparent 95%);
}

/* The original @keyframes timeline / timeline2 hard-code #67e8f9, #5eead4 and
   #a5f3fc.  @keyframes are global, and the big 110px halo has to follow the
   grade's tertiary violet, so identical keyframes are declared here under a
   new name — identical percentages, only the colour swapped — then
   animation-name is repointed, leaving duration (.8s), timing (linear),
   iteration (infinite) and fill (forwards) alone. */
@keyframes career-dot-glow {
  10%, 20%, 50%, 70%, 90% { box-shadow: 0 0 5px 2px var(--grade-accent-2); }
  10%, 30%, 0%, to, 64%, 80% {
    box-shadow: 0 0 5px 2px var(--grade-accent-2),
                0 0 15px 5px var(--accentColor),
                0 0 110px 20px var(--grade-accent-3);
  }
}

html .career-dot, html .education-dot { animation-name: career-dot-glow; }

html .career-dot,
html .education-dot {
  background-color: var(--accentColor);
  box-shadow: 0 0 5px 2px  var(--grade-accent-2),
              0 0 15px 8px var(--accentColor),
              0 0 110px 20px var(--grade-accent-3);
}

/* --- work ------------------------------------------------------------------ */
html .work-section h2 > span,
html .contact-box h2 > span {
  color: var(--accentColor);
}
html .carousel-track-container {
  border-top-color: var(--grade-line);
  border-bottom-color: var(--grade-line);
}
html .carousel-category,
html .carousel-tools p {
  color: var(--text-muted);
}
html .carousel-arrow {
  background: var(--grade-glass);
  border-color: var(--grade-border);
  color: var(--text);
}
html .carousel-arrow:hover {
  background: var(--grade-glass-hi);
  border-color: var(--accentColor);
  color: var(--accentColor);
  box-shadow: 0 0 20px color-mix(in srgb, var(--accentColor) 22%, transparent);
}
html .carousel-dot {
  border-color: var(--grade-border);
}
html .carousel-dot:hover {
  border-color: var(--accentColor);
  background: var(--grade-glass-hi);
}
html .carousel-dot-active {
  background: var(--accentColor);
  border-color: var(--accentColor);
  box-shadow: 0 0 8px color-mix(in srgb, var(--accentColor) 40%, transparent);
}
html .work-link {
  background-color: var(--backgroundColor);
  box-shadow: 0 0 10px #ffffff80, inset 0 0 10px var(--grade-line);
}
html .work-image-in:hover,
html .work-image-in:focus-within {
  box-shadow: 0 12px 34px color-mix(in srgb, var(--accentColor) 18%, transparent);
}

/* --- contact --------------------------------------------------------------- */
html a.contact-social {
  border-bottom-color: var(--grade-line);
}
html .resume-button {
  color: var(--text-muted);
}
html .resume-button:hover,
html div.resume-button span {
  color: var(--text);
}

/* availability pill */
html .availability-pill {
  border-color: color-mix(in srgb, var(--accentColor) 35%, transparent);
  background: color-mix(in srgb, var(--accentColor) 8%, transparent);
  color: var(--accentColor);
}
html .availability-dot {
  background: var(--accentColor);
}

/* contact action row — ALL THREE keep the original geometry (padding 11px 22px,
   1px border, 999px radius come from the site's own rule untouched) and get a
   plain graded glass treatment. */
html .contact-action {
  border-color: color-mix(in srgb, var(--accentColor) 45%, transparent);
  background: color-mix(in srgb, var(--accentColor) 7%, transparent);
  color: var(--accentColor);
}
html .contact-action:hover {
  background: var(--grade-hover-tint);
  color: var(--text);
  box-shadow: 0 0 24px var(--grade-hover-glow);
}

/* keyboard focus ring (item 10) */
html a:focus-visible,
html button:focus-visible,
html [role="button"]:focus-visible,
html [tabindex]:focus-visible {
  outline-color: var(--accentColor);
}


/* -----------------------------------------------------------------------------
   6.  SURFACES — a glass read on the accordion, arrows, tags and pills.
       Translucent fill + a 1px gradient border (padding-box / border-box) +
       layered shadow.  backdrop-filter is deliberately used on only three
       element types so it stays cheap.
   ----------------------------------------------------------------------------- */

html .what-accordion {
  border: 1px solid var(--grade-border);
  background: var(--grade-glass);
  border-radius: 18px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04),
              0 24px 60px rgba(0, 0, 0, .35);
}

html .what-tags {
  border-color: var(--grade-border);
  background: var(--grade-glass);
  border-radius: 999px;
}

html .carousel-arrow {
  border-radius: 999px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05),
              0 8px 22px rgba(0, 0, 0, .30);
}

html .availability-pill {
  border-radius: 999px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

html .contact-box {
  border-radius: 16px;
}


/* -----------------------------------------------------------------------------
   7.  TYPOGRAPHY POLISH.
       Deliberately NO font-size changes: the site's section headings are a
       fixed 70px / 60px / 42px at every width with no breakpoint overrides,
       so any clamp() would move the mobile layout.  Letter-spacing is only
       tightened where the original had none, and text-wrap / numerals are
       pure additions that cannot push content out of its box.
   ----------------------------------------------------------------------------- */

html .career-section h2,
html .education-section h2,
html .work-section h2,
html .contact-section h3,
html .what-box h2 {
  text-wrap: balance;
}

html .career-info-box p,
html .education-info-box p,
html .about-me p,
html .what-content p,
html .carousel-tools p {
  text-wrap: pretty;
}

/* dates read as data */
html .career-info h3,
html .education-info h3,
html .carousel-number h3 {
  font-variant-numeric: tabular-nums;
}

html .what-content p,
html .about-me p {
  line-height: 1.7;
}


/* -----------------------------------------------------------------------------
   8.  INTERACTION POLISH — selection, scrollbar, and the animated gradient
       border on the PRIMARY contact action only (@property drives the sweep).
       WhatsApp and Download Resume keep the plain glass border.
   ----------------------------------------------------------------------------- */

@property --grade-spin {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@keyframes grade-spin {
  to { --grade-spin: 360deg; }
}

html .contact-actions .contact-action:first-child {
  border-color: transparent;
  background:
    linear-gradient(var(--grade-cta-fill), var(--grade-cta-fill)) padding-box,
    conic-gradient(from var(--grade-spin),
      var(--accentColor), var(--grade-accent-2), var(--grade-accent-3), var(--accentColor)
    ) border-box;
  animation: grade-spin 7s linear infinite;
}
html .contact-actions .contact-action:first-child:hover {
  background:
    linear-gradient(var(--grade-cta-fill), var(--grade-cta-fill)) padding-box,
    conic-gradient(from var(--grade-spin),
      var(--accentColor), var(--grade-accent-2), var(--grade-accent-3), var(--accentColor)
    ) border-box;
  color: var(--text);
  box-shadow: 0 0 28px var(--grade-hover-glow);
}

/* selection */
:root ::selection {
  background: color-mix(in srgb, var(--accentColor) 40%, transparent);
  color: var(--text);
}

/* thin graded scrollbar */
html {
  scrollbar-color: var(--grade-accent-2) var(--backgroundColor);
  scrollbar-width: thin;
}
html ::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
html ::-webkit-scrollbar-track {
  background: var(--backgroundColor);
}
html ::-webkit-scrollbar-thumb {
  background: linear-gradient(var(--accentColor), var(--grade-accent-3));
  border-radius: 999px;
  border: 3px solid var(--backgroundColor);
}


/* -----------------------------------------------------------------------------
   9.  LOADER — colours only.
       The loader is a light panel that expands and hands off to the dark site.
       Only its background, its accent glow and the game box are tinted; the
       black pill (.loading-wrap) and the black reveal layer are left alone
       because they are the hand-off mechanism itself — the screen goes fully
       black before the site appears.  No timing, transform or JS is touched,
       so the hand-off is structurally identical, and grade A's background is
       now the original's own #0a0e17, so the reveal lands on exactly the
       colour the loader hands over to — the seam is #000 → #0a0e17, 1.09:1.
   ----------------------------------------------------------------------------- */

html .loading-screen {
  background-color: color-mix(in srgb, var(--backgroundColor) 12%, #f2fbfa);
}
html .loading-hover,
html .loaderGame-ball {
  background-color: var(--accentColor);
}
html .loading-box {
  background-color: #ffffff;
}
/* .loading-header and .loading-marquee already take var(--backgroundColor) as
   their text colour, so they follow the grade automatically and stay dark on
   the light panel. */


/* -----------------------------------------------------------------------------
   10. REDUCED MOTION — every animation this file adds is switched off, so the
       existing reduced-motion behaviour is preserved and not extended.
   ----------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html .contact-actions .contact-action:first-child {
    animation: none;
  }
}
