/* ==========================================================================
   SIGNAL — Core: layers, reset, design tokens, themes, typography, utilities
   Aditya Desikan Sripriya — portfolio
   ========================================================================== */

@layer reset, tokens, base, layout, components, sections, utilities;

/* --------------------------------------------------------------------------
   LIVE SCROLL VALUES

   Registered so they do NOT inherit. The scroll engine rewrites these every
   frame; left inheriting, each write invalidated the style of every
   descendant of the element it landed on — the marquee alone carries ~44
   children and cost 0.67ms per frame on its own. Only the element the value
   is written to reads it, so inheritance buys nothing.

   Browsers without @property fall back to inheriting custom properties: same
   picture, just the old cost.
   -------------------------------------------------------------------------- */
@property --scroll-progress {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}

@property --scroll-velocity {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}

/* --------------------------------------------------------------------------
   RESET
   -------------------------------------------------------------------------- */
@layer reset {
  *,
  *::before,
  *::after { box-sizing: border-box; }

  * { margin: 0; padding: 0; }

  html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    scroll-behavior: smooth;
    scroll-padding-top: 6rem;
  }

  /* When the JS smooth-scroll engine takes over, native smooth would fight it. */
  html.has-smooth-scroll { scroll-behavior: auto; }

  /* Touch devices scroll natively, so the browser provides the section
     settle instead of the engine. `proximity` only pulls when you already
     stopped near an edge, so it can never hold a visitor hostage. The
     existing scroll-padding-top keeps the landing clear of the nav. */
  html.has-native-snap { scroll-snap-type: y proximity; }
  html.has-native-snap [data-snap] { scroll-snap-align: start; }

  body {
    min-height: 100svh;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
  }

  img, svg, video, canvas { display: block; max-width: 100%; }
  img, video { height: auto; }

  input, button, textarea, select { font: inherit; color: inherit; }
  button { background: none; border: 0; cursor: pointer; }

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

  ul, ol { list-style: none; }

  h1, h2, h3, h4, h5, h6 { text-wrap: balance; font-weight: 500; }
  p { text-wrap: pretty; }

  :focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
    border-radius: 4px;
  }
  :focus:not(:focus-visible) { outline: none; }

  ::selection {
    background: var(--brand);
    color: var(--on-brand);
  }
}

/* --------------------------------------------------------------------------
   TOKENS
   -------------------------------------------------------------------------- */
@layer tokens {
  /* Registered custom properties so gradients/glows can be animated smoothly */
  @property --spin {
    syntax: "<angle>";
    inherits: false;
    initial-value: 0deg;
  }
  @property --sheen {
    syntax: "<percentage>";
    inherits: false;
    initial-value: 0%;
  }
  @property --glow {
    syntax: "<number>";
    inherits: false;
    initial-value: 0;
  }

  :root {
    color-scheme: dark;

    /* ---- Type families ---- */
    --font-display: "Bricolage Grotesque", "Arial Black", system-ui, sans-serif;
    --font-body: "Inter Tight", ui-sans-serif, system-ui, "Segoe UI", sans-serif;
    --font-mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
    --font-serif: "Instrument Serif", Georgia, "Times New Roman", serif;

    /* ---- Fluid type scale ---- */
    --step--2: clamp(0.69rem, 0.67rem + 0.10vw, 0.75rem);
    --step--1: clamp(0.80rem, 0.77rem + 0.16vw, 0.89rem);
    --step-0:  clamp(1.00rem, 0.96rem + 0.22vw, 1.13rem);
    --step-1:  clamp(1.20rem, 1.12rem + 0.42vw, 1.50rem);
    --step-2:  clamp(1.44rem, 1.29rem + 0.75vw, 2.00rem);
    --step-3:  clamp(1.73rem, 1.45rem + 1.40vw, 2.66rem);
    --step-4:  clamp(2.07rem, 1.57rem + 2.50vw, 3.55rem);
    --step-5:  clamp(2.49rem, 1.60rem + 4.45vw, 4.74rem);
    --step-6:  clamp(2.99rem, 1.35rem + 8.20vw, 6.31rem);
    --step-7:  clamp(3.58rem, 0.60rem + 14.9vw, 8.42rem);

    /* ---- Rhythm ---- */
    --gutter: clamp(1.25rem, 0.9rem + 1.7vw, 2.5rem);
    --measure: 62ch;
    --shell: 1440px;
    --section-y: clamp(5rem, 3rem + 9vw, 10rem);

    /* ---- Radii ---- */
    --r-xs: 6px;
    --r-sm: 10px;
    --r-md: 16px;
    --r-lg: 24px;
    --r-xl: 34px;
    --r-pill: 999px;

    /* ---- Motion ---- */
    --ease-out-expo: cubic-bezier(0.16, 1, 0.30, 1);
    --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
    --ease-spring: cubic-bezier(0.34, 1.46, 0.64, 1);
    --ease-in-out: cubic-bezier(0.65, 0.05, 0.36, 1);
    --t-fast: 180ms;
    --t-mid: 380ms;
    --t-slow: 720ms;

    /* ---- Layers ---- */
    --z-canvas: 0;
    --z-content: 1;
    --z-nav: 60;
    --z-overlay: 80;
    --z-palette: 90;
    --z-cursor: 100;

    /* ---- Constant brand block (readable in BOTH themes) ---- */
    --brand: #ccff00;
    --on-brand: #08080b;

    /* ---- Live values written by JS ---- */
    --scroll-progress: 0;
    --scroll-velocity: 0;
    --pointer-x: 50%;
    --pointer-y: 50%;
  }

  /* Laptop-height screens: trim the section rhythm so a section comes closer
     to fitting one screen, which is what the scroll settle aims for. Taller
     displays have the room already and keep the original spacing. */
  @media (max-height: 1000px) {
    :root { --section-y: clamp(2.5rem, 1.5rem + 4vw, 5rem); }
  }

  /* ============================ DARK (default) ============================ */
  :root,
  :root[data-theme="dark"] {
    color-scheme: dark;

    --bg: #08080b;
    --bg-2: #0d0d12;
    --bg-3: #131319;

    --surface: rgb(255 255 255 / 0.035);
    --surface-2: rgb(255 255 255 / 0.06);
    --surface-solid: #121218;

    --line: rgb(255 255 255 / 0.11);
    --line-strong: rgb(255 255 255 / 0.22);

    --ink: #f6f3ed;
    --ink-2: rgb(246 243 237 / 0.66);
    --ink-3: rgb(246 243 237 / 0.40);

    --acid: #ccff00;
    --iris: #8b6cff;
    --flare: #ff5c3a;
    --aqua: #00e5d0;

    --accent: var(--acid);
    --accent-2: var(--iris);
    --on-accent: #08080b;
    --accent-soft: rgb(204 255 0 / 0.13);

    --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);
    --shadow-md: 0 12px 34px -12px rgb(0 0 0 / 0.75);
    --shadow-lg: 0 40px 90px -30px rgb(0 0 0 / 0.85);

    --grain-opacity: 0.05;
    --mesh-opacity: 0.85;
  }

  /* ============================== LIGHT ================================== */
  :root[data-theme="light"] {
    color-scheme: light;

    --bg: #f2f0e9;
    --bg-2: #eceadf;
    --bg-3: #ffffff;

    --surface: rgb(255 255 255 / 0.68);
    --surface-2: rgb(255 255 255 / 0.92);
    --surface-solid: #ffffff;

    --line: rgb(14 14 18 / 0.13);
    --line-strong: rgb(14 14 18 / 0.30);

    --ink: #0c0c10;
    --ink-2: rgb(12 12 16 / 0.72);
    --ink-3: rgb(12 12 16 / 0.54);

    --acid: #a9d600;
    --iris: #5b3be8;
    --flare: #e03c15;
    --aqua: #00a08c;

    --accent: var(--iris);
    --accent-2: var(--flare);
    --on-accent: #ffffff;
    --accent-soft: rgb(91 59 232 / 0.10);

    --shadow-sm: 0 1px 2px rgb(24 20 10 / 0.07);
    --shadow-md: 0 14px 34px -14px rgb(24 20 10 / 0.22);
    --shadow-lg: 0 44px 90px -34px rgb(24 20 10 / 0.30);

    --grain-opacity: 0.032;
    --mesh-opacity: 0.7;
  }

  /* System preference wins before the user picks (no data-theme attribute) */
  @media (prefers-color-scheme: light) {
    :root:not([data-theme]) {
      color-scheme: light;
      --bg: #f2f0e9;
      --bg-2: #eceadf;
      --bg-3: #ffffff;
      --surface: rgb(255 255 255 / 0.68);
      --surface-2: rgb(255 255 255 / 0.92);
      --surface-solid: #ffffff;
      --line: rgb(14 14 18 / 0.13);
      --line-strong: rgb(14 14 18 / 0.30);
      --ink: #0c0c10;
      --ink-2: rgb(12 12 16 / 0.72);
      --ink-3: rgb(12 12 16 / 0.54);
      --acid: #a9d600;
      --iris: #5b3be8;
      --flare: #e03c15;
      --aqua: #00a08c;
      --accent: var(--iris);
      --accent-2: var(--flare);
      --on-accent: #ffffff;
      --accent-soft: rgb(91 59 232 / 0.10);
      --shadow-sm: 0 1px 2px rgb(24 20 10 / 0.07);
      --shadow-md: 0 14px 34px -14px rgb(24 20 10 / 0.22);
      --shadow-lg: 0 44px 90px -34px rgb(24 20 10 / 0.30);
      --grain-opacity: 0.032;
      --mesh-opacity: 0.7;
    }
  }
}

/* --------------------------------------------------------------------------
   BASE
   -------------------------------------------------------------------------- */
@layer base {
  body {
    font-family: var(--font-body);
    font-size: var(--step-0);
    font-weight: 400;
    color: var(--ink);
    background: var(--bg);
    overflow-x: clip;
    transition: background var(--t-mid) var(--ease-out-quint),
                color var(--t-mid) var(--ease-out-quint);
  }

  /* Scroll lock: fixed body preserves the offset written by scroller.lock() */
  body.is-locked {
    position: fixed;
    inline-size: 100%;
    overflow: hidden;
  }

  h1, h2, h3, h4 {
    font-family: var(--font-display);
    font-weight: 600;
    line-height: 0.94;
    letter-spacing: -0.035em;
    font-variation-settings: "wdth" 100, "opsz" 48;
  }

  h1 { font-size: var(--step-6); }
  h2 { font-size: var(--step-5); }
  h3 { font-size: var(--step-2); letter-spacing: -0.02em; line-height: 1.08; }
  h4 { font-size: var(--step-1); letter-spacing: -0.015em; line-height: 1.15; }

  p { color: var(--ink-2); }

  strong { color: var(--ink); font-weight: 600; }

  em, .serif {
    font-family: var(--font-serif);
    font-style: italic;
    font-weight: 400;
    letter-spacing: -0.01em;
  }

  code, kbd, samp { font-family: var(--font-mono); font-size: 0.9em; }

  kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.7em;
    padding: 0.15em 0.45em;
    font-size: 0.78em;
    color: var(--ink-2);
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-bottom-width: 2px;
    border-radius: var(--r-xs);
  }

  ::-webkit-scrollbar { width: 10px; height: 10px; }
  ::-webkit-scrollbar-track { background: var(--bg); }
  ::-webkit-scrollbar-thumb {
    background: var(--line-strong);
    border: 3px solid var(--bg);
    border-radius: 999px;
  }
  ::-webkit-scrollbar-thumb:hover { background: var(--accent); }
}

/* --------------------------------------------------------------------------
   LAYOUT
   -------------------------------------------------------------------------- */
@layer layout {
  .shell {
    width: min(100% - (var(--gutter) * 2), var(--shell));
    margin-inline: auto;
  }

  .shell--narrow { --shell: 1080px; }

  .section {
    position: relative;
    padding-block: var(--section-y);
    z-index: var(--z-content);
  }

  .section--tight { padding-block: clamp(3rem, 2rem + 5vw, 6rem); }

  /* Section chrome: eyebrow + oversized title + optional aside */
  .sec-head {
    display: grid;
    gap: clamp(1rem, 2vw, 1.75rem);
    margin-bottom: clamp(2.5rem, 5vw, 5rem);
  }

  /* Same reasoning as --section-y: on a laptop the gap between a section's
     heading and its content was costing a fifth of the screen. */
  @media (max-height: 1000px) {
    .sec-head {
      gap: clamp(0.75rem, 1.4vw, 1.25rem);
      margin-bottom: clamp(1.5rem, 3vw, 2.75rem);
    }
  }

  .sec-head__top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1.5rem;
    flex-wrap: wrap;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--line);
  }

  .sec-head__title {
    font-size: var(--step-5);
    max-width: 18ch;
  }

  .sec-head__note {
    max-width: 40ch;
    font-size: var(--step-0);
    color: var(--ink-2);
  }

  .eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-family: var(--font-mono);
    font-size: var(--step--2);
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--ink-3);
    white-space: nowrap;
  }

  .eyebrow::before {
    content: "";
    inline-size: 0.5rem;
    block-size: 0.5rem;
    border-radius: 2px;
    background: var(--accent);
    box-shadow: 0 0 12px var(--accent);
    animation: pulse-dot 2.4s var(--ease-in-out) infinite;
  }

  .eyebrow--plain::before { display: none; }

  /* ---- Section hand-off -------------------------------------------------
     As the page settles from one section to the next, the incoming header
     lifts into place and its rule draws itself across in accent. Opacity and
     transform only, and never on the section box itself — a transform there
     would become the containing block for the experience rail's sticky pin
     and break it. */
  .sec-head {
    transition:
      opacity 560ms var(--ease-out-quint),
      translate 720ms var(--ease-out-expo);
  }

  html.has-section-focus [data-snap]:not(.is-current) .sec-head {
    /* Enough to read as a hand-off, not so little that an approaching heading
       is unreadable on the way in. */
    opacity: 0.5;
    translate: 0 12px;
  }

  html.has-section-focus [data-snap].is-current .sec-head {
    opacity: 1;
    translate: 0 0;
  }

  .sec-head__top { position: relative; }

  .sec-head__top::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    inset-block-end: -1px;
    block-size: 1px;
    background: linear-gradient(90deg, var(--accent), transparent);
    transform: scaleX(0);
    transform-origin: 0 50%;
    transition: transform 1s var(--ease-out-expo);
  }

  html.has-section-focus [data-snap].is-current .sec-head__top::after {
    transform: scaleX(1);
  }

  @keyframes pulse-dot {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.35; transform: scale(0.7); }
  }
}

/* --------------------------------------------------------------------------
   UTILITIES
   -------------------------------------------------------------------------- */
@layer utilities {
  /* Skip link — visible only once focused */
  .skip {
    position: fixed;
    inset-block-start: 0.75rem;
    inset-inline-start: 0.75rem;
    z-index: 200;
    padding: 0.7rem 1.1rem;
    border-radius: var(--r-pill);
    background: var(--brand);
    color: var(--on-brand);
    font-size: var(--step--1);
    font-weight: 600;
    translate: 0 -180%;
    transition: translate 260ms var(--ease-out-expo);
  }

  .skip:focus-visible { translate: 0 0; }

  .visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }

  .mono {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.02em;
  }

  .muted { color: var(--ink-3); }

  /* Lime marker highlight — the signature brand move, works in both themes */
  .mark {
    position: relative;
    padding: 0.02em 0.28em;
    color: var(--on-brand);
    background: var(--brand);
    border-radius: 4px;
    box-decoration-break: clone;
    -webkit-box-decoration-break: clone;
  }

  .grad {
    background: linear-gradient(100deg, var(--ink) 0%, var(--accent) 55%, var(--accent-2) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }

  .stroke-text {
    color: transparent;
    -webkit-text-stroke: 1.2px var(--line-strong);
  }

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

  /* Fixed decorative layers */
  .fx-layer {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: var(--z-canvas);
  }

  .grain {
    position: fixed;
    inset: -200%;
    z-index: 3;
    pointer-events: none;
    opacity: var(--grain-opacity);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    animation: grain-shift 0.7s steps(3) infinite;
    mix-blend-mode: overlay;
  }

  @keyframes grain-shift {
    0%   { transform: translate(0, 0); }
    33%  { transform: translate(-2%, 1.5%); }
    66%  { transform: translate(1.5%, -1%); }
    100% { transform: translate(0, 0); }
  }

  /* Reveal primitives driven by IntersectionObserver.

     Deliberately opacity + transform only. The blur this used to animate made
     every revealing card repaint its whole layer on every frame of the
     transition, and a staggered bento grid means a dozen of those at once —
     which is exactly when the visitor is scrolling. Opacity and transform
     stay on the compositor and cost nothing per frame. */
  [data-reveal] {
    opacity: 0;
    transform: translate3d(0, 26px, 0);
    transition:
      opacity 0.72s var(--ease-out-quint) var(--reveal-delay, 0s),
      transform 0.92s var(--ease-out-expo) var(--reveal-delay, 0s);
  }

  [data-reveal="left"]  { transform: translate3d(-38px, 0, 0); }
  [data-reveal="right"] { transform: translate3d(38px, 0, 0); }
  [data-reveal="scale"] { transform: scale(0.94); }
  [data-reveal="clip"] {
    opacity: 1;
    filter: none;
    transform: none;
    clip-path: inset(0 0 100% 0);
    transition: clip-path 1.1s var(--ease-out-expo) var(--reveal-delay, 0s);
  }

  .is-revealed[data-reveal] {
    opacity: 1;
    transform: none;
    clip-path: inset(0 0 0 0);
  }

  /* Divider with a travelling shimmer */
  .rule {
    position: relative;
    height: 1px;
    background: var(--line);
    overflow: hidden;
  }
  .rule::after {
    content: "";
    position: absolute;
    inset-block: 0;
    inline-size: 28%;
    background: linear-gradient(90deg, transparent, var(--accent), transparent);
    animation: rule-sweep 5.5s var(--ease-in-out) infinite;
  }
  @keyframes rule-sweep {
    0%   { transform: translateX(-120%); }
    100% { transform: translateX(460%); }
  }
}

/* --------------------------------------------------------------------------
   VIEW TRANSITIONS (theme swap) — must sit outside @layer to beat UA defaults
   -------------------------------------------------------------------------- */
::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}

/* The outgoing theme stays put while the new one is revealed by a growing circle. */
::view-transition-old(root) { z-index: 1; }
::view-transition-new(root) { z-index: 2147483646; }

html.is-theme-swapping,
html.is-theme-swapping * { pointer-events: none; }

/* --------------------------------------------------------------------------
   REDUCED MOTION
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; scroll-snap-type: none; }

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

  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    clip-path: none !important;
  }

  /* No dimming or drawing-in when motion is unwelcome. */
  html.has-section-focus [data-snap] .sec-head {
    opacity: 1 !important;
    translate: none !important;
  }
  .sec-head__top::after { display: none; }

  .grain { animation: none; }
}
