/* ===================================================================
   Design: violet-accented mono/grotesk system, dark + light themes.
   See DESIGN.md for the full system and rules. Redesigned from the
   previous "Celestial Navigation Chart" system — see
   openspec/changes/redesign-visual-identity/ for the rationale.
   =================================================================== */

/* Self-hosted (site CSP is style-src/font-src 'self' — no external font CDN). */
/* See assets/fonts/LICENSES.md for provenance and license terms. */
@font-face {
  font-family: "Cabinet Grotesk";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("assets/fonts/cabinet-grotesk-variable.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("assets/fonts/jetbrains-mono-variable.woff2") format("woff2");
}
@font-face {
  font-family: "Martian Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("assets/fonts/martian-mono-variable.woff2") format("woff2");
}

:root {
  /* Ground */
  --bg: #100e1a;
  --bg-panel: #16121f;
  --bg-header: rgba(16, 14, 26, 0.86);

  /* Ink (text) — opacity-based hierarchy on white */
  --ink: rgba(255, 255, 255, 0.97);
  --ink-2: rgba(255, 255, 255, 0.72);

  /* Graticule (structure lines) — low-opacity accent tint */
  --graticule: rgba(155, 143, 255, 0.16);
  --graticule-strong: rgba(155, 143, 255, 0.32);

  /* Accent — the single fixed-point color */
  --accent: #9b8fff;
  --accent-bright: #b7afff;
  --accent-ink: #100e1a;
  --accent-glow: rgba(155, 143, 255, 0.28);
  --selection-bg: rgba(155, 143, 255, 0.35);
  --link-underline: rgba(155, 143, 255, 0.4);
  --chart-hover-bg: rgba(155, 143, 255, 0.04);

  --max-width: 1240px;
  --radius-pill: 999px;

  --font-display: "Cabinet Grotesk", -apple-system, sans-serif;
  --font-body: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --font-label: "Martian Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
}

/*
  Light theme. Values are NOT a blind port of the reference site's own
  light-mode colors — the reference's accent (#9B8FFF) is only 2.2:1
  against a cream ground, well under WCAG AA's 4.5:1 for text. These are
  recalculated: --accent hits 4.89:1 as link/label text on --bg, and
  --accent-bright 6.62:1 for hover emphasis (see design.md - Risks).
*/
:root[data-theme="light"] {
  --bg: #efe7d4;
  --bg-panel: #e4dac2;
  --bg-header: rgba(239, 231, 212, 0.86);

  --ink: rgba(10, 10, 10, 0.92);
  --ink-2: rgba(10, 10, 10, 0.68);

  --graticule: rgba(10, 10, 10, 0.12);
  --graticule-strong: rgba(10, 10, 10, 0.24);

  --accent: #5b4fd1;
  --accent-bright: #4b3fa8;
  --accent-ink: #ffffff;
  --accent-glow: rgba(91, 79, 209, 0.14);
  --selection-bg: rgba(91, 79, 209, 0.22);
  --link-underline: rgba(91, 79, 209, 0.4);
  --chart-hover-bg: rgba(91, 79, 209, 0.05);
}

* {
  box-sizing: border-box;
}

/* Theme switch: animate themed color properties, skip it under reduced motion. */
@media (prefers-reduced-motion: no-preference) {
  * {
    transition: background-color 0.2s var(--ease-standard), border-color 0.2s var(--ease-standard), color 0.2s var(--ease-standard);
  }
}

html {
  background: var(--bg);
}

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 1.05rem;
  background: var(--bg);
  color: var(--ink);
  line-height: 1.65;
  position: relative;
  min-height: 100vh;
}

/* ---------- Starfield ground ---------- */

body::before,
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
}

body::before {
  background-image: url("assets/stars-fine.svg");
  background-repeat: repeat;
  background-size: 300px 300px;
  opacity: 0.9;
}

body::after {
  background-image: url("assets/stars-bright.svg"), radial-gradient(ellipse at 50% -10%, var(--accent-glow), transparent 55%);
  background-repeat: repeat, no-repeat;
  background-size: 600px 600px, 100% 100%;
  animation: twinkle 9s ease-in-out infinite;
}

@keyframes twinkle {
  0%, 100% { opacity: 0.75; }
  50% { opacity: 0.95; }
}

@media (prefers-reduced-motion: reduce) {
  body::after {
    animation: none;
    opacity: 0.85;
  }
}

/* Starfield is a night-sky atmosphere — dark-mode only. */
:root[data-theme="light"] body::before,
:root[data-theme="light"] body::after {
  display: none;
}

:root[data-theme="light"] .constellation {
  opacity: 0.12;
}

.container {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 1.5rem;
  position: relative;
  z-index: 1;
}

a {
  color: var(--accent);
  text-decoration-color: var(--link-underline);
  text-underline-offset: 3px;
}

a:hover {
  color: var(--accent-bright);
}

::selection {
  background: var(--selection-bg);
  color: var(--ink);
}

/* ---------- Header / Nav (chart legend) ---------- */

.site-header {
  position: sticky;
  top: 0;
  background: var(--bg-header);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--graticule);
  z-index: 10;
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.1rem 1.5rem;
  /* Reserve room for the fixed-position theme toggle floating over the
     top-right corner (see .theme-toggle) so the last nav link doesn't
     render underneath it. Reset to the plain 1.5rem on mobile, where
     the toggle moves to a fixed bottom-right position instead. */
  padding-right: 4.5rem;
}

.logo {
  font-family: var(--font-label);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-decoration: none;
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
}

.logo::before {
  content: "✦";
  color: var(--accent);
  font-size: 0.85em;
}

.nav-right {
  display: flex;
  align-items: center;
  gap: 1.5rem;
}

.nav-links {
  list-style: none;
  display: flex;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
}

/*
  Always position: fixed, deliberately detached from the nav's flex row
  (not a flex child of .nav-right) — floats independently of the other
  nav controls rather than sitting in the same cluster, and its position
  is set with real viewport coordinates. It cannot live inside
  .site-header: that element's `backdrop-filter` establishes a
  containing block for fixed/absolute descendants (same effect as
  `transform`), which would trap "bottom: 1.5rem" inside the header's
  own ~64px box instead of the viewport — exactly the bug that showed
  up when this lived inside the header.
*/
.theme-toggle {
  position: fixed;
  top: 1.1rem;
  right: max(1.5rem, calc((100vw - var(--max-width)) / 2 + 1.5rem));
  z-index: 20;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.4rem;
  height: 2.4rem;
  padding: 0;
  background: var(--bg-header);
  color: var(--ink-2);
  border: 1px solid var(--graticule-strong);
  border-radius: var(--radius-pill);
  cursor: pointer;
  backdrop-filter: blur(8px);
  transition: color 0.2s var(--ease-standard), border-color 0.2s var(--ease-standard), background-color 0.2s var(--ease-standard);
}

.theme-toggle:hover {
  color: var(--accent-bright);
  border-color: var(--accent);
}

.theme-toggle-icon {
  width: 1.05rem;
  height: 1.05rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.3;
  stroke-linecap: round;
}

.theme-toggle-icon-moon {
  display: none;
}

:root[data-theme="light"] .theme-toggle-icon-sun {
  display: none;
}

:root[data-theme="light"] .theme-toggle-icon-moon {
  display: block;
}

.nav-links a {
  display: inline-block;
  text-decoration: none;
  color: var(--ink-2);
  font-family: var(--font-label);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.4rem 0.75rem;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  transition: color 0.2s var(--ease-standard), border-color 0.2s var(--ease-standard), background-color 0.2s var(--ease-standard);
}

.nav-links a:hover {
  color: var(--accent-bright);
  background: var(--chart-hover-bg);
  border-color: var(--graticule-strong);
}

.nav-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.5rem;
}

.nav-toggle span {
  width: 20px;
  height: 1px;
  background: var(--accent);
}

/* ---------- Hero (full-viewport chart sheet) ---------- */

.hero {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  border-bottom: 1px solid var(--graticule);
  overflow: hidden;
  scroll-margin-top: 4.5rem;
}

.hero::before,
.hero::after {
  content: "";
  position: absolute;
  width: 22px;
  height: 22px;
  border: 1px solid var(--accent);
  z-index: 2;
}

.hero::before {
  top: 1.5rem;
  left: 1.5rem;
  border-right: none;
  border-bottom: none;
}

.hero::after {
  bottom: 1.5rem;
  right: 1.5rem;
  border-left: none;
  border-top: none;
}

.constellation {
  position: absolute;
  top: 50%;
  right: -4%;
  width: min(50vw, 620px);
  height: auto;
  transform: translateY(-50%);
  fill: none;
  stroke: var(--accent);
  stroke-width: 1;
  opacity: 0.4;
  z-index: 0;
}

.constellation circle {
  fill: var(--accent);
  stroke: none;
  opacity: 0.8;
}

.constellation .star-bright {
  fill: var(--accent-bright);
  opacity: 1;
}

.hero-inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: end;
  gap: 4rem;
  width: 100%;
  padding-top: 6rem;
  padding-bottom: 6rem;
}

.hero-main {
  max-width: 42rem;
}

.hero h1 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2.75rem, 9vw, 6rem);
  margin: 0 0 1.25rem;
  letter-spacing: 0.01em;
  line-height: 1.02;
}

.hero-subtitle {
  color: var(--ink-2);
  font-size: clamp(1.05rem, 1.6vw, 1.3rem);
  margin: 0 0 2.25rem;
  max-width: 44ch;
  line-height: 1.5;
}

.hero-legend {
  border: 1px solid var(--graticule-strong);
  padding: 1.5rem 1.75rem;
  min-width: 15rem;
  max-width: 20rem;
}

.legend-title {
  display: block;
  font-family: var(--font-label);
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.9rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--graticule);
}

.legend-list {
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: var(--font-label);
  font-size: 0.8rem;
  color: var(--ink-2);
  display: grid;
  gap: 0.6rem;
}

.legend-list li {
  padding-left: 1.1rem;
  position: relative;
}

.legend-list li::before {
  content: "✦";
  position: absolute;
  left: 0;
  color: var(--accent);
  font-size: 0.75em;
}

/*
  Items with a real official icon (competencias.ts' `icon` field) skip
  the ✦ bullet in favor of the brand mark itself — small and colored
  via currentColor (inherits the list's --ink-2), never each brand's
  own color, so ~25 different logos don't reintroduce a rainbow of
  accents into a system built around exactly one. Kept deliberately
  tiny given how many items are in this grid at once.
*/
.legend-list li.has-icon {
  display: flex;
  align-items: center;
  gap: 0.5em;
  padding-left: 0;
}

.legend-list li.has-icon::before {
  content: none;
}

.tech-icon {
  width: 1.3em;
  height: 1.3em;
  flex-shrink: 0;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-label);
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 0.8rem 1.6rem;
  border-radius: var(--radius-pill);
  border: 1px solid var(--accent);
  transition: background 0.2s var(--ease-standard), transform 0.2s var(--ease-standard);
}

.btn::before {
  content: "✦";
  font-size: 0.85em;
}

.btn:hover {
  background: var(--accent-bright);
  border-color: var(--accent-bright);
  color: var(--accent-ink);
  transform: translateY(-1px);
}

.btn-mail {
  text-transform: none;
}

/* Secondary button: bordered pill, same shape/typography as .btn but
   transparent — reuses the theme toggle's outline treatment rather
   than inventing a new one, for a link that's a real second CTA
   (LinkedIn) but shouldn't compete with the filled primary button. */
.btn-outline {
  background: transparent;
  color: var(--ink-2);
  border-color: var(--graticule-strong);
}

.btn-outline:hover {
  background: transparent;
  border-color: var(--accent);
  color: var(--accent-bright);
}

/* For buttons that carry a real brand icon instead of the ✦ glyph. */
.btn-icon {
  text-transform: none;
}

.btn-icon::before {
  content: none;
}

.btn-icon .tech-icon {
  width: 1.1em;
  height: 1.1em;
  flex-shrink: 0;
}

/* ---------- Sections ---------- */

.section {
  padding: 6.5rem 1.5rem;
  border-top: 1px solid var(--graticule);
  scroll-margin-top: 4.5rem;
}

.section-close {
  padding-bottom: 8rem;
}

.section-heading {
  display: flex;
  align-items: baseline;
  gap: 0.85rem;
  margin-bottom: 2.5rem;
}

.section-heading::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--graticule);
}

.section h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.9rem, 4vw, 2.75rem);
  margin: 0;
  letter-spacing: 0.01em;
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.section h2::before {
  content: "✦";
  color: var(--accent);
  font-size: 0.7em;
}

.section > .container > p,
.section-close p {
  max-width: 66ch;
  color: var(--ink-2);
  font-size: 1.05rem;
}

.contact-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  max-width: none;
}

/* ---------- Sobre mí (asymmetric two-column) ---------- */

.about-grid {
  display: grid;
  grid-template-columns: minmax(200px, 320px) 1fr minmax(200px, 20rem);
  gap: 3rem;
  align-items: start;
}

.about-grid .section-heading {
  margin-bottom: 0;
}

.ficha-group {
  margin-top: 1.1rem;
}

.ficha-group:first-of-type {
  margin-top: 0;
}

.ficha-label {
  display: block;
  font-family: var(--font-label);
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  color: var(--ink-2);
  margin-bottom: 0.5rem;
}

/* ---------- Competencias (legend grid) ---------- */

.competencias-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 2.5rem 3rem;
}

.competencia-group {
  border-top: 1px solid var(--graticule);
  padding-top: 1.25rem;
}

/* ---------- Projects (chart-plate sequence) ---------- */

.chart-list {
  border-top: 1px solid var(--graticule);
}

.chart-entry {
  display: grid;
  grid-template-columns: minmax(180px, 280px) 1fr;
  gap: 2.5rem;
  padding: 2.75rem 0;
  border-bottom: 1px solid var(--graticule);
  transition: background 0.2s var(--ease-standard);
}

.chart-entry:hover {
  background: var(--chart-hover-bg);
}

.chart-entry-tag {
  display: block;
  font-family: var(--font-label);
  font-size: 0.8rem;
  letter-spacing: 0.02em;
  color: var(--accent);
  padding-top: 0.4rem;
}

.chart-entry-main h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.35rem, 2.2vw, 1.75rem);
  margin: 0 0 0.85rem;
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
}

.chart-entry-main h3::before {
  content: "✦";
  color: var(--accent);
  font-size: 0.65em;
  transition: color 0.2s var(--ease-standard);
}

.chart-entry:hover .chart-entry-main h3::before {
  color: var(--accent-bright);
}

.chart-entry-main p {
  color: var(--ink-2);
  font-size: 1.05rem;
  max-width: 62ch;
  margin: 0 0 1rem;
}

.project-link {
  text-decoration: none;
  font-family: var(--font-label);
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  font-weight: 700;
}

/* ---------- Footer (chart imprint) ---------- */

.site-footer {
  text-align: center;
  padding: 2.5rem 1.5rem;
  color: var(--ink-2);
  font-family: var(--font-label);
  font-size: 0.63rem;
  letter-spacing: 0.02em;
  border-top: 1px solid var(--graticule);
  position: relative;
  z-index: 1;
}

/* ---------- Responsive: structural collapse ---------- */

@media (max-width: 900px) {
  .hero {
    min-height: auto;
  }

  .hero-inner {
    grid-template-columns: 1fr;
    align-items: start;
    padding-top: 7rem;
    padding-bottom: 4rem;
    gap: 2.5rem;
  }

  .hero-legend {
    min-width: 0;
  }

  .constellation {
    width: min(70vw, 380px);
    opacity: 0.25;
  }

  .about-grid {
    grid-template-columns: 1fr;
    gap: 1.5rem;
  }

  .about-grid .section-heading {
    margin-bottom: 0.5rem;
  }

  .chart-entry {
    grid-template-columns: 1fr;
    gap: 1rem;
    padding: 2rem 0;
  }

  .chart-entry-tag {
    padding-top: 0;
  }

  .section {
    padding: 4.5rem 1.5rem;
  }

  .section-close {
    padding-bottom: 5.5rem;
  }
}

/* ---------- Mobile nav ---------- */

/*
  1024px, not 640px: with 5 nav links (one as long as "Proyectos
  personales") plus the space reserved for the floating theme toggle,
  the full inline nav has nowhere near enough room between roughly
  640-1024px. It doesn't overflow outright any more (the toggle isn't
  in the flex row to get pushed off-screen), but flexbox still tries to
  fit everything on one line first: the longer links wrap their own
  text to two lines while the short ones (e.g. "Contacto") don't, which
  leaves oddly large gaps in the row and reads as "Contacto floating
  off on its own" even though nothing is actually misaligned. Collapsing
  to the hamburger pattern earlier, at 1024px, avoids that regime
  entirely — verified content actually fits above this width.
*/
@media (max-width: 1024px) {
  .nav-toggle {
    display: flex;
  }

  .nav-links {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 1rem;
    background: var(--bg-panel);
    border-bottom: 1px solid var(--graticule);
    padding: 1.25rem 1.5rem;
    display: none;
  }

  .nav-links.open {
    display: flex;
  }
}

@media (max-width: 640px) {
  .nav {
    padding-right: 1.5rem;
  }

  .theme-toggle {
    top: auto;
    left: auto;
    bottom: 1.5rem;
    right: 1.5rem;
    background: var(--bg-panel);
  }

  .hero::before,
  .hero::after {
    width: 16px;
    height: 16px;
  }

  .contact-actions .btn {
    width: 100%;
    justify-content: center;
  }

  .btn-label-full {
    display: none;
  }
}
