:root {
  --color-bg: #f8f2e7;
  --color-surface: #fbf7ee;
  --color-text: #1a1a18;
  --color-text-muted: #5f5c56;
  --color-border: #ddd4c2;
  --color-accent: #2f5233;
  --color-header-bg: #123a5e;
  --color-header-text: #f8f2e7;
  --color-header-text-muted: rgba(243, 236, 221, 0.72);
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, sans-serif;
  --font-mono: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  /* Layout: the nav, every section and the footer share one container, so
     all content starts on the same left edge. Long-form text additionally
     caps at --reading-width but stays anchored to that edge. */
  --container: 72rem;
  --gutter: 1.5rem;
  --reading-width: 42rem;
  /* One size for every page and section title (the hero name is the only
     larger heading). */
  --font-size-title: clamp(1.75rem, 3vw, 2.125rem);
  --space-section: clamp(4.5rem, 10vw, 8rem);
  --footer-height: 0px;
}

@media (max-width: 40rem) {
  :root {
    --gutter: 1.25rem;
  }
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  /* Always reserve the scrollbar's space so short pages (no scrollbar) don't
     shift the centered container sideways relative to long ones. */
  scrollbar-gutter: stable;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--color-accent);
  color: #fff;
  padding: 0.5rem 1rem;
  z-index: 100;
}
.skip-link:focus {
  left: 0;
}

a {
  color: inherit;
}

h1, h2, h3 {
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-accent);
}

/* Header */
.site-header {
  border-bottom: 1px solid var(--color-header-bg);
  position: sticky;
  top: 0;
  background: var(--color-header-bg);
  color: var(--color-header-text);
  z-index: 10;
}

.site-nav {
  max-width: calc(var(--container) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 1rem var(--gutter);
  display: flex;
  align-items: center;
  gap: 1.5rem;
  flex-wrap: wrap;
}

.brand {
  text-decoration: none;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--color-header-text);
}

.nav-links {
  list-style: none;
  display: flex;
  gap: 1.5rem;
  margin: 0 0 0 auto;
  padding: 0;
  font-size: 0.9rem;
}

.nav-links a {
  text-decoration: none;
  color: var(--color-header-text);
}

.nav-links a:hover {
  color: var(--color-header-text);
}

.nav-social {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 1rem;
  margin: 0;
  padding: 0;
}

.nav-social a {
  display: inline-flex;
  color: var(--color-header-text);
}

.nav-social a:hover {
  color: var(--color-header-text);
}

/* Sections */
section {
  padding: var(--space-section) var(--gutter);
  border-bottom: 1px solid var(--color-border);
  scroll-margin-top: 4.5rem;
}

section:last-of-type {
  border-bottom: none;
}

/* Multi-section views (home, about): each section is one full screen tall so
   it reads as a distinct "slide", with its content vertically centered and
   any scroll cue pinned to the bottom edge. Full 100svh (not minus the
   header) so the centered content lines up with the fixed, full-viewport
   background wave. Single-section views like Contact keep normal
   content-height sections. */
.full-sections section {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* Scroll-to-next-section cue — pinned near the bottom of the *viewport*.
   Sections are a full 100svh tall but start below the sticky header, so the
   section's own bottom edge sits header-height below the fold; add that
   clearance (matching the header offset used by scroll-margin-top below)
   or the cue would land off-screen and need a scroll to reach. */
.scroll-cue {
  display: flex;
  justify-content: center;
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(4.5rem + clamp(1rem, 2vh, 1.5rem));
}

.scroll-cue a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background: var(--color-surface);
  color: var(--color-text-muted);
  transition: transform 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.scroll-cue a:hover {
  border-color: var(--color-accent);
  color: var(--color-accent);
  transform: translateY(3px);
}

.scroll-cue a:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

.scroll-cue svg {
  width: 1.15rem;
  height: 1.15rem;
  animation: scroll-cue-bounce 2.4s ease-in-out infinite;
}

@keyframes scroll-cue-bounce {
  0%, 100% { transform: translateY(-2px); }
  50% { transform: translateY(2px); }
}

@media (prefers-reduced-motion: reduce) {
  .scroll-cue svg {
    animation: none;
  }
  .scroll-cue a:hover {
    transform: none;
  }
}

.section-inner {
  /* width:100% so the box always fills the container and its left edge
     lines up across sections. Without it, a flex-column section centers this
     via the auto margins at its shrink-to-fit content width, so a section
     with short content ends up narrower and visibly indented. */
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
}

/* Shared section header: title plus optional one-line intro, left-aligned
   on the container edge, with the same gap to the content below on every
   section. */
.section-header {
  margin-bottom: 2.5rem;
}

.section-header h1,
.section-header h2 {
  font-size: var(--font-size-title);
  margin: 0;
}

.section-header .lede {
  margin: 0.75rem 0 0;
  max-width: var(--reading-width);
  color: var(--color-text-muted);
}

/* Hero */
.hero {
  padding-top: clamp(4rem, 12vw, 7rem);
}

.hero h1 {
  font-size: clamp(2.25rem, 5vw, 3.5rem);
  margin: 0.5rem 0 1rem;
}

.hero p.lede {
  font-size: 1.15rem;
  color: var(--color-text-muted);
  max-width: var(--reading-width);
}

.hero-links {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 2rem;
}

.btn {
  display: inline-block;
  padding: 0.6rem 1.1rem;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  text-decoration: none;
  font-size: 0.9rem;
  color: var(--color-text);
}

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

.btn:hover {
  border-color: var(--color-accent);
}

/* About */
#about p {
  color: var(--color-text-muted);
}

/* Two-column About: prose on the left, a stack of info cards on the right.
   Collapses to a single column on narrow screens (cards below the prose). */
.about-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 20rem;
  gap: 2.5rem;
  align-items: start;
}

.about-prose p:first-child {
  margin-top: 0;
}

.about-aside {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.about-card {
  border: 1px solid var(--color-border);
  border-radius: 6px;
  padding: 1.5rem;
  background: var(--color-surface);
}

.about-card h3 {
  margin: 0.35rem 0 0.5rem;
  font-size: 1.05rem;
}

.about-card p {
  margin: 0;
  font-size: 0.92rem;
  color: var(--color-text-muted);
}

.about-card .eyebrow {
  display: block;
}

.about-card__links {
  display: flex;
  gap: 1rem;
  margin-top: 1rem;
  font-size: 0.85rem;
}

.about-card__links a {
  text-decoration: none;
  color: var(--color-text);
  border-bottom: 1px solid var(--color-border);
}

.about-card__links a:hover {
  border-color: var(--color-accent);
}

.about-card--cta {
  border-color: var(--color-accent);
  background: color-mix(in srgb, var(--color-accent) 7%, var(--color-surface));
}

.about-card--cta .btn {
  margin-top: 1.1rem;
}

@media (max-width: 52rem) {
  .about-layout {
    grid-template-columns: 1fr;
    gap: 2rem;
  }

  .about-aside {
    max-width: 28rem;
  }
}

/* Skills */
.skill-groups {
  display: grid;
  /* One row of category columns; each category is a 2-wide icon grid that
     grows downward as it gains skills. Sized so all 5 categories fit the
     shared container on one row (5 x 13rem + 4 x 1.5rem = 71rem). */
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 2.5rem 1.5rem;
}

.skill-group h3 {
  font-size: 1rem;
  margin: 0 0 1.25rem;
}

.skill-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  /* Two fixed-width columns of tiles, packed at the group's left edge under
     the heading. */
  display: grid;
  grid-template-columns: repeat(2, 6rem);
  justify-content: start;
  gap: 1.75rem 1rem;
}

.skill-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
  text-align: center;
  transition: transform 0.18s ease;
}

.skill-tile:hover {
  transform: translateY(-4px);
}

.skill-tile__icon {
  width: 4.5rem;
  height: 4.5rem;
  padding: 0.7rem;
  flex-shrink: 0;
  border: 1px solid var(--color-border);
  border-radius: 12px;
  background: var(--color-surface);
  object-fit: contain;
}

.skill-tile__icon--generic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-muted);
}

.skill-tile__icon--generic svg {
  width: auto;
  height: 100%;
  aspect-ratio: 1;
}

.skill-tile__label {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  line-height: 1.3;
  /* Slightly wider than the 6rem tile column (overflowing evenly into the
     column gaps) so the longest name, "Entity Framework Core", still wraps
     to 2 lines rather than 3. */
  width: 7rem;
  /* Reserve room for a 2-line label so every tile in a row is the
     same total height and rows stay aligned across categories regardless
     of how many lines a given label wraps to. */
  min-height: calc(0.78rem * 1.3 * 2);
  color: var(--color-text-muted);
}

@media (prefers-reduced-motion: reduce) {
  .skill-tile {
    transition: none;
  }
  .skill-tile:hover {
    transform: none;
  }
}

/* Projects */
/* Two columns filling the container; cards in a row share a height, and
   each card's links sit on its bottom edge. */
.project-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.75rem;
}

@media (max-width: 52rem) {
  .project-list {
    grid-template-columns: 1fr;
  }
}

.project-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  padding: 1.75rem;
  background: var(--color-surface);
}

.project-card h3 {
  margin: 0 0 0.5rem;
  font-size: 1.15rem;
}

.project-card p.summary {
  color: var(--color-text-muted);
  margin: 0 0 1rem;
  flex-grow: 1;
}

.tech-list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0 0 1rem;
  padding: 0;
}

.tech-list li {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--color-accent);
}

.tech-list li:not(:last-child)::after {
  content: "·";
  margin-left: 0.4rem;
  color: var(--color-border);
}

.project-links {
  display: flex;
  gap: 1rem;
  font-size: 0.85rem;
}

.project-links a {
  text-decoration: none;
  color: var(--color-text);
  border-bottom: 1px solid var(--color-border);
}

.project-links a:hover {
  border-color: var(--color-accent);
}

/* Education */
/* Same two-column grid and card style as Featured Projects. */
.education-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.75rem;
}

@media (max-width: 52rem) {
  .education-list {
    grid-template-columns: 1fr;
  }
}

.education-entry {
  border: 1px solid var(--color-border);
  border-radius: 6px;
  padding: 1.75rem;
  background: var(--color-surface);
}

.education-entry .eyebrow {
  margin: 0 0 0.5rem;
}

.education-entry h3 {
  margin: 0 0 0.35rem;
  font-size: 1.15rem;
}

.education-entry .meta {
  margin: 0;
  color: var(--color-text-muted);
}

/* Contact */
.contact-methods {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 1.25rem;
}

.contact-card {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  height: 100%;
  padding: 1.5rem;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  background: var(--color-surface);
  text-decoration: none;
  transition: border-color 0.18s ease;
}

.contact-card:hover {
  border-color: var(--color-accent);
}

.contact-card .eyebrow {
  margin: 0;
}

.contact-card__value {
  font-size: 1rem;
  overflow-wrap: anywhere;
}

/* Single-section pages (Contact): the footer sits at the bottom of the
   window, and the section fills the space above it with its content
   vertically centered, like the full-height sections on Home and About. */
body.fill-viewport {
  display: flex;
  flex-direction: column;
  min-height: 100svh;
}

body.fill-viewport #main {
  flex: 1;
  display: flex;
  flex-direction: column;
}

body.fill-viewport #main > section {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Content is centered in the available space, so the tall default
     section padding would only push the footer below the fold. */
  padding-block: clamp(3rem, 6vw, 4.5rem);
}

/* As a flex item the footer would otherwise shrink to its content width. */
body.fill-viewport .site-footer {
  width: 100%;
}

/* Blog */
.blog-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: 1.75rem;
}

.blog-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  padding: 1.75rem;
  background: var(--color-surface);
}

.blog-card h2 {
  margin: 0 0 0.6rem;
  font-size: 1.15rem;
}

.blog-card h2 a {
  text-decoration: none;
}

.blog-card h2 a:hover {
  color: var(--color-accent);
}

.blog-card p.summary {
  color: var(--color-text-muted);
  margin: 0 0 1rem;
  flex-grow: 1;
}

.tag-list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0 0 1.25rem;
  padding: 0;
}

.tag-list li {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--color-accent);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 0.2rem 0.65rem;
}

.blog-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 0.85rem;
  color: var(--color-text-muted);
  padding-top: 1rem;
  border-top: 1px solid var(--color-border);
}

.blog-card__readmore {
  text-decoration: none;
  color: var(--color-accent);
  font-weight: 600;
}

.blog-card__readmore:hover {
  text-decoration: underline;
}

/* Blog post detail */
.back-link {
  display: inline-block;
  text-decoration: none;
  color: var(--color-text-muted);
  font-size: 0.9rem;
  margin-bottom: 1.5rem;
}

.back-link:hover {
  color: var(--color-accent);
}

#blog-post h1 {
  font-size: var(--font-size-title);
  max-width: var(--reading-width);
  margin: 0 0 1rem;
}

.blog-post__meta {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  flex-wrap: wrap;
  color: var(--color-text-muted);
  font-size: 0.9rem;
  margin-bottom: 2rem;
}

.blog-post__meta .tag-list {
  margin: 0;
}

.blog-post__body {
  color: var(--color-text);
  max-width: var(--reading-width);
}

.blog-post__body p {
  margin: 0 0 1.25rem;
}

.blog-post__body p:last-child {
  margin-bottom: 0;
}

.blog-post__body h2 {
  font-size: 1.25rem;
  margin: 2.25rem 0 0.75rem;
}

.blog-post__body ul {
  margin: 0 0 1.25rem;
  padding-left: 1.25rem;
}

.blog-post__body li {
  margin-bottom: 0.4rem;
}

.blog-post__body figure {
  margin: 1.75rem 0;
}

.blog-post__body img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: #fff;
}

.blog-post__body .figure-row {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 0.75rem;
}

.blog-post__body figcaption {
  margin-top: 0.6rem;
  color: var(--color-text-muted);
  font-size: 0.85rem;
}

@media (max-width: 40rem) {
  .blog-post__body .figure-row {
    grid-auto-flow: row;
  }
}

#blog-post .about-card {
  margin-top: 2.5rem;
  max-width: var(--reading-width);
}

/* Footer */
.site-footer {
  max-width: calc(var(--container) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 3rem var(--gutter) 1.75rem;
  border-top: 1px solid var(--color-border);
  color: var(--color-text-muted);
  font-size: 0.85rem;
}

.site-footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: 2.5rem;
}

.site-footer__logo {
  margin: 0 0 0.6rem;
  font-weight: 600;
  color: var(--color-text);
}

.site-footer__blurb {
  margin: 0;
  max-width: 24rem;
  line-height: 1.6;
}

.site-footer__heading {
  margin: 0 0 1rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.site-footer__col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.65rem;
}

.site-footer__col a {
  text-decoration: none;
  color: var(--color-text-muted);
}

.site-footer__col a:hover {
  color: var(--color-accent);
}

.site-footer__contact {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}

.site-footer__contact a {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.site-footer__social {
  display: flex;
  gap: 0.6rem;
  margin-top: 0.15rem;
}

.site-footer__social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  background: var(--color-surface);
  color: var(--color-text-muted);
  transition: border-color 0.18s ease, color 0.18s ease;
}

.site-footer__social a:hover {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  justify-content: space-between;
  margin-top: 2.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--color-border);
  font-size: 0.78rem;
}

.site-footer__bottom p {
  margin: 0;
}

.site-footer__built {
  font-family: var(--font-mono);
}

@media (max-width: 40rem) {
  .site-footer__grid {
    grid-template-columns: 1fr;
    gap: 2rem;
  }
}

@media (max-width: 40rem) {
  section {
    padding: 2.5rem var(--gutter);
  }

  /* Don't force a full screen on small viewports — tall stacked content
     (e.g. the skills list) would overflow and get clipped by centering. */
  .full-sections section {
    min-height: auto;
    justify-content: flex-start;
    padding-bottom: 5rem;
  }

  /* No sticky-header clearance needed here — sections aren't forced to
     100svh on small screens, so the cue sits right in the reserved
     padding-bottom above, not off-screen past the fold. */
  .scroll-cue {
    bottom: clamp(1.5rem, 4vh, 2.75rem);
  }
}

/* The last full-bleed section (e.g. Education on the About page) sits flush
   against the footer instead of another 100svh section. Scrolled all the way
   down, the footer eats into the bottom of its box, so content centered on
   the full 100svh would sit visibly above true center. Reserve the footer's
   real height (set on --footer-height by site.js) so it centers within the
   space actually visible above the footer instead. Scoped to the same
   breakpoint as the full-height behavior above — on narrow screens sections
   already collapse to auto height and this doesn't apply. */
@media (min-width: 40.0625rem) {
  .full-sections section:last-of-type {
    min-height: calc(100svh - var(--footer-height));
  }
}

/* Animated background wave
   The wave is a static inline SVG (stroke = currentColor). Per-section CSS
   custom properties, set via body[data-section] by site.js, drive a subtle
   tint shift plus a slow vertical drift/scale as the visitor moves down. */
.site-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  /* Tunable per section (defaults match the hero state).
     Effective line opacity = --wave-opacity * each stroke's own opacity
     (see the <use> ramp in _Layout.cshtml), so keep this the master dimmer. */
  --wave-color: #6ea8dc;
  --wave-opacity: 0.45;
  --wave-shift: 0px;
  --wave-rotate: 0deg;
  --wave-scale: 1;
  color: var(--wave-color);
  opacity: var(--wave-opacity);
}

.site-bg__wave {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 140%;
  height: 140%;
  transform: translate3d(-50%, calc(-50% + var(--wave-shift)), 0)
    rotate(var(--wave-rotate)) scale(var(--wave-scale));
  transform-origin: 50% 50%;
  will-change: transform;
}

body.bg-ready .site-bg {
  transition: color 900ms ease, opacity 900ms ease;
}

body.bg-ready .site-bg__wave {
  transition: transform 1200ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* Keep page content above the wave. */
#main,
.site-footer {
  position: relative;
  z-index: 1;
}

/* Per-section states — subtle, kept within the blue family. */
body[data-section="hero"] .site-bg {
  --wave-color: #6ea8dc;
  --wave-opacity: 0.45;
  --wave-shift: 0px;
  --wave-rotate: 0deg;
  --wave-scale: 1;
}

body[data-section="skills"] .site-bg {
  --wave-color: #5aa6c6;
  --wave-opacity: 0.38;
  --wave-shift: -46px;
  --wave-rotate: -1.6deg;
  --wave-scale: 1.05;
}

body[data-section="projects"] .site-bg {
  --wave-color: #7183d2;
  --wave-opacity: 0.34;
  --wave-shift: -96px;
  --wave-rotate: 2deg;
  --wave-scale: 1.09;
}

@media (max-width: 40rem) {
  .site-bg {
    --wave-opacity: 0.3 !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  body.bg-ready .site-bg__wave {
    transition: none;
  }
  .site-bg__wave {
    transform: translate3d(-50%, -50%, 0);
  }
}
