/* ==========================================================================
   Datavectrix — site.css
   The only stylesheet. Edit colours, fonts and spacing in :root below.
   Sections in order:
     1. Tokens        2. Reset / base    3. Header + nav
     4. Hero          5. Pillars (home)  6. Projects
     7. Contact + footer                 8. Responsive
   ========================================================================== */

/* --- 1. TOKENS -------------------------------------------------------------
   Change a value here and it updates everywhere on both pages.
   Palette sampled from assets/img/hero-bg.webp.
   -------------------------------------------------------------------------- */
:root {
  --ink:        #080C15;   /* near-black field between the cubes */
  --ink-2:      #0F1524;
  --paper:      #F6F8FB;   /* light content background */
  --line:       #DBE2EC;   /* hairline borders */
  --body:       #39445A;   /* body text on light */
  --muted:      #69748A;

  --blue:       #2472E8;   /* vivid cube blue */
  --blue-ink:   #1655C4;   /* darker blue — legible as text on light */
  --blue-lt:    #7CC3FB;   /* blue glow highlight */
  --amber:      #F79420;   /* vivid cube orange */
  --amber-lt:   #F9C166;   /* orange glow highlight */

  --font-display: 'Space Grotesk', ui-sans-serif, system-ui, sans-serif;
  --font-body:    'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  --wrap: 1180px;          /* max content width */
  --pad:  28px;            /* gutter */

  /* Hero scrim — the dark veil over the cube photo. Heaviest on the left
     behind the headline, fading to fully transparent on the right so the
     image is revealed. Raise the alpha values to dim the photo further.
     Overridden for narrow screens in section 8. */
  --hero-scrim: linear-gradient(100deg,
      rgba(8,12,21,.94)  0%,
      rgba(8,12,21,.91) 28%,
      rgba(8,12,21,.70) 50%,
      rgba(8,12,21,.34) 74%,
      rgba(8,12,21,0)  100%);

  --capstrip-scrim: linear-gradient(100deg,
      rgba(8,12,21,.86) 0%,
      rgba(8,12,21,.52) 55%,
      rgba(8,12,21,.10) 100%);
}

/* Card hover glow (section 5). One pass: fades up to --glow-peak over half the
   duration, then back to nothing over the other half. Change the `1` in the
   animation shorthand to `infinite` if you want it to keep pulsing while the
   pointer rests on the card. */
@keyframes glow-pulse {
  0%   { opacity: 0; }
  50%  { opacity: var(--glow-peak, .9); }
  100% { opacity: 0; }
}

/* --- 2. RESET / BASE ------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; min-width: 0; }

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

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.65;
  color: var(--body);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }

:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; border-radius: 2px; }

/* Shared centred container. Every section wraps its content in one of these. */
.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 var(--pad); }

/* Small uppercase mono label used above headings */
.eyebrow {
  margin: 0 0 12px;
  font-family: var(--font-mono);
  font-size: .76rem;
  font-weight: 500;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--blue-ink);
}

/* Short amber rule used as a divider under hero text */
.rule { width: 64px; height: 2px; margin: 0 0 30px; border: 0; background: var(--amber); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* --- 3. HEADER + NAV ------------------------------------------------------
   Duplicated verbatim in index.html and projects/index.html.
   Only difference between the two: which link carries class="is-current",
   and the href values (root-relative, so they work from any depth).
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(8, 12, 21, .93);
  backdrop-filter: saturate(160%) blur(8px);
  border-bottom: 1px solid rgba(124, 195, 251, .16);
}

.site-header__inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 14px var(--pad);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.brand {
  display: flex;
  align-items: center;
  gap: 11px;
  text-decoration: none;
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.16rem;
  letter-spacing: -.015em;
}

.brand__mark { width: auto; height: 26px; flex: 0 0 auto; }

.nav { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }

.nav a {
  display: block;
  padding: 8px 13px;
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: .79rem;
  font-weight: 500;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .74);
  text-decoration: none;
  transition: color .18s ease, background .18s ease;
}

.nav a:hover { color: #fff; background: rgba(36, 114, 232, .22); }
.nav a.is-current { color: #fff; box-shadow: inset 0 -2px 0 var(--amber); }

/* --- 4. HERO -------------------------------------------------------------- */
/* The cube-grid photo sits behind the headline. Black background-color fills
   any area the image does not cover, and the gradient scrim keeps text legible.
   Swap the image by replacing assets/img/hero-bg.webp (and the .jpg fallback). */
.hero {
  position: relative;
  overflow: hidden;
  padding: 104px 0 0;
  color: #fff;
  background-color: #000;

  /* First declaration: plain JPEG, for browsers without image-set().
     Second declaration overrides it where image-set() is supported, serving
     the 166 KB WebP and falling back to the 271 KB JPEG otherwise. */
  background-image: var(--hero-scrim), url('../img/hero-bg.jpg');
  background-image: var(--hero-scrim),
    image-set(url('../img/hero-bg.webp') type('image/webp'),
              url('../img/hero-bg.jpg')  type('image/jpeg'));

  /* The asset is pre-composed: the photo sits on the RIGHT of a wider black
     canvas, its left edge feathered into the black. That puts the bright core
     of the image at roughly 70% across, directly under the transparent end of
     --hero-scrim, so the reveal lands on the dramatic part of the picture. */
  background-position: center center;
  background-size: cover;
  background-repeat: no-repeat;
}

.hero h1 {
  margin: 0 0 22px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.6rem, 7.4vw, 5.1rem);
  line-height: 1.02;
  letter-spacing: -.035em;
  color: #fff;
}

.hero__lede {
  margin: 0 0 26px;
  max-width: 24ch;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.22rem, 2.5vw, 1.72rem);
  line-height: 1.34;
  letter-spacing: -.015em;
  color: #fff;
}

.hero p:not(.hero__lede) {
  margin: 0 0 12px;
  max-width: 56ch;
  font-size: 1.05rem;
  color: rgba(255, 255, 255, .84);
}

/* Capability strip pinned to the bottom of the hero */
/* Fades left-to-right in step with --hero-scrim so the strip doesn't cut a
   flat dark band across the revealed part of the photo. */
.capstrip { margin-top: 64px; border-top: 1px solid rgba(124, 195, 251, .22); background: var(--capstrip-scrim); }

.capstrip ul {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 20px var(--pad);
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 34px;
}

.capstrip li {
  font-family: var(--font-mono);
  font-size: .8rem;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .74);
}

.capstrip li::before { content: "\2192 "; color: var(--amber); }

/* --- 5. PILLARS (home only) ---------------------------------------------- */

/* Shared tint for the light content sections — a very soft wash of the palette
   blues so the background isn't flat white. Cards stay pure #fff and lift
   slightly off it. Applied to .projects as well (section 6). */
.pillars,
.projects {
  background:
    radial-gradient(ellipse 900px 520px at 12% 0%,  rgba(124,195,251,.20), transparent 68%),
    radial-gradient(ellipse 820px 620px at 92% 78%, rgba(36,114,232,.09),  transparent 70%),
    linear-gradient(180deg, #FFFFFF 0%, var(--paper) 42%, #EAF1FA 100%);
}

.pillars { padding: 88px 0 96px; }

/* --- Card hover glow -----------------------------------------------------
   Each card defines its own --accent, which drives the top/left border, the
   bullet marks AND the hover glow, so they can never drift apart.
   The glow is a blurred conic gradient on a ::before sitting behind the card;
   on hover it sweeps once around the card and stops.
   ------------------------------------------------------------------------- */
.card,
.project {
  --accent: var(--blue);
  --glow-peak: .9;          /* how bright the glow gets at the top of the pulse */
  position: relative;
  z-index: 0;
  transition: transform .3s cubic-bezier(.22, .61, .36, 1), box-shadow .3s ease;
}

/* The glow. A box-shadow rather than a blurred, masked ring — two reasons:
   a shadow falls off smoothly to fully transparent at its outer extent, and it
   is clipped inside the border box so it can never reach the card's content.
   (The masked-ring approach cannot fade out: CSS applies `mask` AFTER `filter`,
   so the blur spreads and is then cut off flat at the element's box edge.)
   `inset` here sits just outside the card's border; the shadow's blur radius
   controls how far the halo reaches. */
.card::before,
.project::before {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: -2;
  border-radius: 11px;
  box-shadow: 0 0 10px 1px var(--accent);
  opacity: 0;
  pointer-events: none;
}

/* No interior fill layer is needed any more. An outer box-shadow is clipped
   inside its own border box by definition, so unlike the previous blurred
   ring it cannot paint over the card's content. */

/* Only on real pointer devices — phones report hover:none, so touch users
   never get a stuck hover state. */
@media (hover: hover) {
  .card:hover,
  .project:hover { transform: scale(1.015); }

  /* 2.2s total: ~1.1s fading in, ~1.1s fading out — the same pace the fade-in
     had before, now applied to the fade-out as well. */
  .card:hover::before,
  .project:hover::before {
    animation: glow-pulse 2.2s ease-in-out 1 both;
  }

  /* The third card's accent (--blue-lt) is pale, so at the same settings its
     glow reads about half as strong as the other two against the light
     background. Opacity alone cannot make up the difference (it is already at
     the ceiling), so stack a second shadow. Done here rather than by changing
     --accent, which would also alter the card's border colour. */
  .card:nth-child(3) { --glow-peak: 1; }
  .card:nth-child(3):hover::before {
    box-shadow: 0 0 10px 1px var(--accent), 0 0 9px 0 var(--accent);
  }
}

.section-head { max-width: 60ch; margin: 0 0 52px; }

.section-head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.7rem, 3.4vw, 2.5rem);
  line-height: 1.14;
  letter-spacing: -.025em;
  color: var(--ink);
}

.card-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 26px; }

.card {
  display: flex;
  flex-direction: column;
  padding: 34px 30px 32px;
  background: #fff;
  border: 1px solid var(--line);
  border-top: 3px solid var(--accent);
  border-radius: 10px;
}

/* Accent rotates blue / amber / light-blue across the three cards.
   Setting --accent here also recolours that card's bullets and hover glow. */
.card:nth-child(1) { --accent: var(--blue); }
.card:nth-child(2) { --accent: var(--amber); }
.card:nth-child(3) { --accent: var(--blue-lt); }

.card__tag {
  margin: 0 0 14px;
  font-family: var(--font-mono);
  font-size: .72rem;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}

.card h3 {
  margin: 0 0 16px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.6rem;
  line-height: 1.15;
  letter-spacing: -.025em;
  color: var(--ink);
}

.card__q {
  margin: 0 0 16px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.05rem;
  line-height: 1.42;
  letter-spacing: -.01em;
  color: var(--ink);
}

.card p:not(.card__q):not(.card__tag) { margin: 0 0 22px; font-size: .97rem; }

.card ul {
  list-style: none;
  margin: auto 0 0;
  padding: 20px 0 0;
  border-top: 1px solid var(--line);
}

.card li {
  position: relative;
  margin-bottom: 11px;
  padding-left: 22px;
  font-size: .93rem;
  line-height: 1.5;
}

.card li:last-child { margin-bottom: 0; }

.card li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .6em;
  width: 9px;
  height: 2px;
  background: var(--accent);
}

/* --- 6. PROJECTS (projects page only) ----------------------------------- */
/* Compact hero variant — no capability strip, shorter padding */
.hero--page { padding: 92px 0 78px; }

.hero__kicker {
  margin: 0 0 24px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.1rem, 2.2vw, 1.5rem);
  line-height: 1.35;
  letter-spacing: -.015em;
  color: var(--amber-lt);
}

.projects { padding: 82px 0 92px; }
.projects .eyebrow { margin-bottom: 22px; }

.project-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; }

.project {
  display: flex;
  flex-direction: column;
  padding: 32px 30px 28px;
  background: #fff;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 10px;
}

/* Alternating blue / amber down the two columns */
.project:nth-child(odd)  { --accent: var(--blue); }
.project:nth-child(even) { --accent: var(--amber); }

.project:hover { box-shadow: 0 10px 30px rgba(8, 12, 21, .14); }

.project h3 {
  margin: 0 0 14px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.28rem;
  line-height: 1.22;
  letter-spacing: -.02em;
  color: var(--ink);
}

.project p { margin: 0 0 22px; font-size: .95rem; }

/* Tech tag pills */
.stack {
  list-style: none;
  margin: auto 0 0;
  padding: 18px 0 0;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.stack li {
  padding: 4px 10px;
  font-family: var(--font-mono);
  font-size: .73rem;
  font-weight: 500;
  letter-spacing: .04em;
  color: var(--muted);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 100px;
}

/* --- 7. CONTACT + FOOTER -------------------------------------------------
   Duplicated verbatim in both pages. The id="contact" is what the Contact
   nav link targets (#contact on home, /#contact from the projects page).
   -------------------------------------------------------------------------- */
.contact {
  padding: 82px 0 0;
  scroll-margin-top: 80px;      /* stops the sticky header covering the heading */
  color: #fff;
  background:
    radial-gradient(ellipse at 80% 0%,  rgba(247, 148, 32, .16), transparent 55%),
    radial-gradient(ellipse at 10% 40%, rgba(36, 114, 232, .20), transparent 55%),
    var(--ink);
}

.contact .eyebrow { color: var(--amber-lt); }

.contact h2 {
  margin: 0 0 16px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.75rem, 4vw, 2.8rem);
  line-height: 1.1;
  letter-spacing: -.03em;
  color: #fff;
}

.contact__ask { margin: 0 0 46px; max-width: 56ch; font-size: 1.05rem; color: rgba(255, 255, 255, .8); }

.contact__details {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 30px;
  padding: 38px 0;
  border-top: 1px solid rgba(124, 195, 251, .20);
}

.contact__details h3 {
  margin: 0 0 12px;
  font-family: var(--font-mono);
  font-size: .74rem;
  font-weight: 500;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--amber-lt);
}

.contact__details p { margin: 0; font-size: 1rem; line-height: 1.6; color: rgba(255, 255, 255, .88); }

.contact__details a {
  color: #fff;
  text-decoration: none;
  border-bottom: 1px solid rgba(255, 255, 255, .4);
  word-break: break-word;
}

.contact__details a:hover { color: var(--amber-lt); border-bottom-color: var(--amber); }

.copyright {
  padding: 24px 0 30px;
  border-top: 1px solid rgba(124, 195, 251, .20);
  font-family: var(--font-mono);
  font-size: .78rem;
  letter-spacing: .05em;
  color: rgba(255, 255, 255, .55);
}

/* --- 8. RESPONSIVE ------------------------------------------------------- */
/* Keep these last so they override the rules above. */

@media (max-width: 1040px) {
  .card-grid { gap: 20px; }
  .card { padding: 28px 24px 26px; }
}

/* Tablet / phone — every multi-column grid collapses to one column */
@media (max-width: 900px) {
  /* Text now spans the full width, so the left-to-right reveal would put
     headline text over open photo. Swap to a top-to-bottom scrim instead. */
  :root {
    --hero-scrim: linear-gradient(172deg,
        rgba(8,12,21,.93)  0%,
        rgba(8,12,21,.88) 45%,
        rgba(8,12,21,.66) 78%,
        rgba(8,12,21,.42) 100%);
    --capstrip-scrim: linear-gradient(100deg,
        rgba(8,12,21,.72) 0%,
        rgba(8,12,21,.58) 100%);
  }

  /* Narrow viewports crop the wide asset hard; bias the crop right so it lands
     on the bright cubes rather than the black pad. */
  .hero { background-position: 72% center; }

  .card-grid,
  .project-grid,
  .contact__details { grid-template-columns: 1fr; }
  .contact__details { gap: 26px; }
  .hero { padding-top: 70px; }
  .hero--page { padding: 64px 0 56px; }
  .capstrip { margin-top: 48px; }
  .pillars { padding: 62px 0 70px; }
  .projects { padding: 58px 0 68px; }
  .contact { padding-top: 62px; }
  .section-head { margin-bottom: 36px; }
  .hero__lede { max-width: none; }
}

@media (max-width: 640px) {
  :root { --pad: 20px; }
  .site-header__inner { justify-content: center; gap: 8px; padding: 12px var(--pad); }
  .nav { gap: 2px; }
  .nav a {
    display: flex;
    align-items: center;
    min-height: 44px;             /* accessible touch target */
    padding: 0 11px;
    font-size: .73rem;
    letter-spacing: .07em;
  }
  .hero { padding-top: 52px; }
  .hero--page { padding: 48px 0 46px; }
  .capstrip ul { gap: 8px 22px; }
  .card { padding: 26px 22px 24px; }
  .project { padding: 26px 22px 24px; }
  .contact__ask { margin-bottom: 34px; }
  .contact__details { padding: 30px 0; }
  .contact__details a { display: inline-block; padding: 6px 0; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; animation: none !important; }

  /* No scale jump. The glow is a plain opacity change, not movement, so it
     stays — it just appears immediately instead of fading. */
  .card:hover,
  .project:hover { transform: none; }
}
