/* ==========================================================================
   base.css — structure, layout and components.

   This file owns every structural rule exactly once. It never hard-codes a
   colour, font or texture: everything visual comes from a custom property
   defined by css/theme-default.css or css/theme-mario.css.

   Adding a theme means supplying token values, not re-writing layout.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Token contract
   Every token below MUST be given a value by each theme file. The values here
   are only fallbacks so the page is still readable if a theme fails to load.
   -------------------------------------------------------------------------- */
:root {
  /* page canvas */
  --bg-page: #16131a;
  --bg-page-image: none;
  --bg-overlay: none;
  --bg-attachment: fixed;
  /* Which edge of the background survives the `cover` crop. */
  --bg-position: center;

  /* surfaces */
  --surface: rgba(255, 255, 255, 0.04);
  --surface-2: rgba(255, 255, 255, 0.07);
  --border: rgba(255, 255, 255, 0.12);
  --border-width: 1px;
  /* Backing for diagrams shown whole — they carry their own light background. */
  --media-figure-bg: #eef1f7;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.25);
  --shadow-lift: 0 2px 4px rgba(0, 0, 0, 0.3), 0 16px 40px rgba(0, 0, 0, 0.35);

  /* type */
  --text: #ece8f0;
  --text-muted: #a49daf;
  --heading: #ffffff;
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-display: var(--font-body);
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --heading-transform: none;
  --heading-shadow: none;
  --heading-spacing: -0.02em;

  /* accent */
  --accent: #7c1e2e;
  --accent-soft: rgba(124, 30, 46, 0.18);
  --on-accent: #ffffff;
  --link: #e08a97;

  /* header */
  --nav-bg: #21181d;
  --nav-bg-image: none;
  --nav-bg-size: auto;
  --nav-text: #ece8f0;
  --nav-border: rgba(255, 255, 255, 0.1);
  --nav-item-bg: transparent;
  --nav-item-bg-active: var(--accent);
  --nav-item-text-active: var(--on-accent);

  /* geometry */
  --radius: 10px;
  --radius-lg: 16px;
  --radius-pill: 999px;
  --edges: auto; /* image-rendering; Mario flips this to pixelated */

  /* rhythm */
  --step: 1rem;
  --container: 68rem;
}

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

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

body,
h1,
h2,
h3,
h4,
p,
ul,
ol,
li,
figure {
  margin: 0;
  padding: 0;
}

ul,
ol {
  list-style: none;
}

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

button {
  font: inherit;
  color: inherit;
}

a {
  color: var(--link);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

a:hover {
  text-decoration-thickness: 2px;
}

/* --------------------------------------------------------------------------
   Page shell
   -------------------------------------------------------------------------- */
html,
body {
  min-height: 100%;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  margin: 0;
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--text);
  background-color: var(--bg-page);
  background-image: var(--bg-overlay), var(--bg-page-image);
  background-size: cover;
  background-position: var(--bg-position);
  background-repeat: no-repeat;
  background-attachment: var(--bg-attachment);
  overflow-x: hidden;
}

h1,
h2,
h3 {
  font-family: var(--font-display);
  color: var(--heading);
  line-height: 1.15;
  letter-spacing: var(--heading-spacing);
  text-transform: var(--heading-transform);
  text-shadow: var(--heading-shadow);
  text-wrap: balance;
}

h1 {
  font-size: clamp(2rem, 6vw, 3.25rem);
}

h2 {
  font-size: clamp(1.35rem, 3.5vw, 1.85rem);
}

h3 {
  font-size: 1.1rem;
}

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: clamp(1rem, 4vw, 2rem);
}

main {
  flex: 1 0 auto;
  padding-block: clamp(2rem, 6vw, 4rem) clamp(3rem, 8vw, 5rem);
}

.section + .section {
  margin-top: clamp(2.5rem, 7vw, 4rem);
}

.section-title {
  margin-bottom: calc(var(--step) * 1.25);
}

.lede {
  color: var(--text-muted);
  font-size: 1.05rem;
  max-width: 60ch;
}

/* Visible only to screen readers. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Keyboard focus. Applied globally so no interactive element can lose it. */
:focus-visible {
  outline: 3px solid var(--link);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: 1rem;
  top: -4rem;
  z-index: 100;
  padding: 0.6rem 1rem;
  background: var(--accent);
  color: var(--on-accent);
  border-radius: var(--radius);
  text-decoration: none;
  transition: top 0.15s ease;
}

.skip-link:focus {
  top: 1rem;
}

/* --------------------------------------------------------------------------
   Header / navigation
   Hard-coded into each page so it works without JavaScript.
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background-color: var(--nav-bg);
  background-image: var(--nav-bg-image);
  background-size: var(--nav-bg-size);
  border-bottom: var(--border-width) solid var(--nav-border);
  color: var(--nav-text);
}

.site-header__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  padding-block: 0.75rem;
}

.brand {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--nav-text);
  text-decoration: none;
  white-space: nowrap;
}

.brand:hover {
  color: var(--nav-text);
}

.nav-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.35rem;
  /* The header centres its children on narrow screens, which would otherwise
     let this row size to its content and overflow instead of wrapping. */
  max-width: 100%;
}

.nav-links a {
  display: block;
  padding: 0.5rem 0.9rem;
  border-radius: var(--radius);
  background: var(--nav-item-bg);
  color: var(--nav-text);
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.nav-links a:hover {
  background: var(--surface-2);
}

.nav-links a[aria-current="page"] {
  background: var(--nav-item-bg-active);
  color: var(--nav-item-text-active);
}

.social {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.social a {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--radius-pill);
  background: var(--surface);
  transition: background-color 0.15s ease, transform 0.15s ease;
}

.social a:hover {
  background: var(--surface-2);
  transform: translateY(-2px);
}

.social img {
  width: 1.25rem;
  height: 1.25rem;
  object-fit: contain;
}

@media (min-width: 46em) {
  .site-header__inner {
    flex-direction: row;
    justify-content: space-between;
    gap: 1.5rem;
    padding-block: 0.9rem;
  }

  .nav-links {
    justify-content: flex-end;
    margin-left: auto;
  }
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.7rem 1.3rem;
  border: var(--border-width) solid transparent;
  border-radius: var(--radius);
  background: var(--surface-2);
  color: var(--text);
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
}

.btn:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow);
  text-decoration: none;
}

.btn:active {
  transform: translateY(0);
}

.btn--primary {
  background: var(--accent);
  color: var(--on-accent);
  border-color: var(--accent);
}

.btn--ghost {
  background: transparent;
  border-color: var(--border);
  color: var(--text);
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: calc(var(--step) * 1.5);
}

/* --------------------------------------------------------------------------
   Theme toggle — fixed bottom-left, present on every page.

   It is a block you hit: a ? block in the default theme, a brick in the Mario
   theme. Each theme supplies the face; the geometry is identical so the block
   stays put across the switch.
   -------------------------------------------------------------------------- */
.theme-toggle {
  position: fixed;
  bottom: 1.25rem;
  left: 1.25rem;
  z-index: 60;
  width: 4rem;
  height: 4rem;
  padding: 0;
  border: 0;
  background-color: transparent;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  image-rendering: var(--edges);
  cursor: pointer;
  filter: drop-shadow(3px 3px 0 rgba(0, 0, 0, 0.45));
  transition: transform 0.15s ease;
}

.theme-toggle:hover {
  transform: translateY(-5px);
}

.theme-toggle:active {
  transform: translateY(-1px);
}

/* The button has no visible text, so its accessible name comes from whichever
   label the active theme un-hides. Both carry .visually-hidden in the markup;
   this only controls which one is exposed. */
.theme-toggle__to-mario,
.theme-toggle__to-default {
  display: none;
}

/* JS is what makes the toggle work — hide it entirely when JS is off. */
.no-js .theme-toggle {
  display: none;
}

/* --------------------------------------------------------------------------
   Panels & generic content
   -------------------------------------------------------------------------- */
.panel {
  padding: clamp(1.25rem, 4vw, 2rem);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow);
}

.panel > * + * {
  margin-top: var(--step);
}

.prose p + p,
.prose ul,
.prose h3 {
  margin-top: var(--step);
}

.prose li {
  position: relative;
  padding-left: 1.4rem;
  margin-top: 0.5rem;
}

.prose li::before {
  content: "";
  position: absolute;
  left: 0.15rem;
  top: 0.7em;
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 2px;
  background: var(--accent);
}

.prose li strong {
  color: var(--heading);
}

/* --------------------------------------------------------------------------
   Home hero
   -------------------------------------------------------------------------- */
.hero {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: min(70vh, 34rem);
  padding-block: clamp(1rem, 5vw, 3rem);
}

.hero__grid {
  display: grid;
  gap: clamp(1.5rem, 5vw, 3.5rem);
  align-items: center;
}

@media (min-width: 52em) {
  .hero__grid {
    grid-template-columns: 1.25fr 1fr;
  }
}

.hero__portrait {
  width: min(100%, 20rem);
  margin-inline: auto;
  border-radius: var(--radius-lg);
  border: var(--border-width) solid var(--border);
  box-shadow: var(--shadow-lift);
  image-rendering: var(--edges);
}

.hero__eyebrow {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--link);
  margin-bottom: 0.75rem;
}

.hero__subtitle {
  margin-top: 0.75rem;
  font-size: clamp(1.05rem, 2.5vw, 1.3rem);
  color: var(--text-muted);
}

.hero__bio {
  margin-top: calc(var(--step) * 1.25);
  max-width: 56ch;
}

.hero__panel {
  display: inline-block;
  padding: clamp(1.5rem, 5vw, 2.5rem);
  border-radius: var(--radius-lg);
  background: var(--surface);
  border: var(--border-width) solid var(--border);
  backdrop-filter: blur(6px);
}

/* Mystery-box easter egg. Home only, Mario only — themes opt it back in. */
.mystery-box {
  display: none;
  position: fixed;
  bottom: 5.5rem;
  left: 1.25rem;
  z-index: 60;
  width: 4rem;
  height: 4rem;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}

.no-js .mystery-box {
  display: none !important;
}

/* --------------------------------------------------------------------------
   Card grid — projects
   -------------------------------------------------------------------------- */
/* Project groups — LLM / Traditional ML / Software. */
.project-group + .project-group {
  margin-top: clamp(2.5rem, 7vw, 3.5rem);
}

.project-group__title {
  margin-bottom: calc(var(--step) * 1.1);
  padding-bottom: 0.5rem;
  border-bottom: var(--border-width) solid var(--border);
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
  gap: clamp(1rem, 3vw, 1.5rem);
  /* Two-column cards otherwise leave a hole beside them; let single-column
     cards backfill it. */
  grid-auto-flow: dense;
}

.card {
  display: flex;
  flex-direction: column;
  /* Grid items default to min-width:auto, which would let a figure's intrinsic
     width (these are ~860px) push the whole grid wider than the viewport. */
  min-width: 0;
  overflow: hidden;
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lift);
  border-color: var(--accent);
}

.card__media {
  aspect-ratio: 16 / 10;
  min-width: 0;
  overflow: hidden;
  background-color: var(--surface-2);
  border-bottom: var(--border-width) solid var(--border);
}

.card__media img {
  width: 100%;
  max-width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  image-rendering: var(--edges);
}

/* Diagrams and figures, as opposed to UI screenshots: show the whole image at
   its own aspect ratio rather than cropping it to a fixed well. */
.card__media--contain {
  aspect-ratio: auto;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.6rem;
  background: var(--media-figure-bg);
}

.card__media--contain img {
  height: auto;
  object-fit: contain;
}

/* Two related figures stacked so they can be read against each other. */
.card__media--stack {
  justify-content: center;
}

/* Wide figures need more than one column to stay legible. Spanning the whole
   row rather than two columns also avoids stranding an empty column in groups
   that have nothing left to backfill with. */
@media (min-width: 52em) {
  .card--wide {
    grid-column: 1 / -1;
  }
}

/* Not every project has a screenshot. Text-only cards get a marker instead
   of a broken or empty image well. */
.card--no-media .card__media {
  aspect-ratio: auto;
  display: grid;
  place-items: center;
  min-height: 4.5rem;
  font-family: var(--font-mono);
  font-size: 1.5rem;
  color: var(--link);
  background-image: none;
}

.card__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 0.7rem;
  padding: 1.15rem 1.25rem 1.35rem;
}

.card__title {
  font-size: 1.1rem;
}

.card__blurb {
  flex: 1;
  font-size: 0.95rem;
  color: var(--text-muted);
}

.card__status {
  align-self: flex-start;
  padding: 0.15rem 0.55rem;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--link);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.card__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.25rem;
}

.card__link {
  align-self: flex-start;
  font-weight: 600;
  font-size: 0.9rem;
}

.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.tag {
  padding: 0.2rem 0.6rem;
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--text-muted);
}

/* Progressive enhancement: the plain-HTML project list is visible by default,
   so the page works with JavaScript off. js/projects.js hides it once it has
   successfully rendered the cards. */
.card-grid-fallback.is-hidden {
  display: none;
}

/* --------------------------------------------------------------------------
   Skills (resume page)
   -------------------------------------------------------------------------- */
.skills-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  gap: clamp(1rem, 3vw, 1.5rem);
  align-items: start;
}

.chip-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: var(--step);
}

/* --------------------------------------------------------------------------
   Resume embed
   -------------------------------------------------------------------------- */
.resume-embed {
  width: 100%;
  height: min(95vh, 46rem);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
}

/* Mobile browsers do not render <object> PDFs — the download button above is
   the real affordance there, so drop the dead frame entirely. */
@media (max-width: 46em), (hover: none) {
  .resume-embed {
    display: none;
  }
}

.resume-embed__fallback {
  padding: clamp(1.25rem, 4vw, 2rem);
  text-align: center;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Contact
   -------------------------------------------------------------------------- */
.contact-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: clamp(1rem, 3vw, 1.5rem);
}

.contact-link {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 1.25rem;
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--text);
  text-decoration: none;
  box-shadow: var(--shadow);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}

.contact-link:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lift);
  border-color: var(--accent);
  text-decoration: none;
}

.contact-link__icon {
  width: 1.75rem;
  height: 1.75rem;
  object-fit: contain;
  margin-bottom: 0.35rem;
}

.contact-link__label {
  font-weight: 700;
  color: var(--heading);
}

.contact-link__value {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}

/* --------------------------------------------------------------------------
   Bottom clearance
   No page has a footer, so <main> carries the space that keeps the fixed theme
   toggle from covering the last of the content on narrow screens.
   -------------------------------------------------------------------------- */
@media (max-width: 46em) {
  main {
    padding-bottom: 6rem;
  }
}

/* --------------------------------------------------------------------------
   Motion
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .btn:hover,
  .card:hover,
  .contact-link:hover,
  .social a:hover,
  .theme-toggle:hover {
    transform: none;
  }
}
