/*
 * mattheworres.com
 * Hand-written, no frameworks. Layers keep the cascade predictable:
 * later layers win over earlier ones regardless of selector specificity.
 */
@layer reset, tokens, base, layout, components, motion;

@font-face {
  font-family: 'Source Sans 3';
  src: url('../fonts/source-sans-3-latin-wght-normal.woff2') format('woff2');
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Source Sans 3';
  src: url('../fonts/source-sans-3-latin-wght-italic.woff2') format('woff2');
  font-weight: 200 900;
  font-style: italic;
  font-display: swap;
}

/* ---------------------------------------------------------------- reset */
@layer reset {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }
  * {
    margin: 0;
  }
  img,
  svg {
    display: block;
    max-width: 100%;
  }
  img {
    height: auto;
  }
  ul {
    padding: 0;
    list-style: none;
  }
}

/* --------------------------------------------------------------- tokens */
@layer tokens {
  :root {
    color-scheme: dark;

    --bg: #0e0e10;
    --surface: #17171a;
    --surface-raised: #202025;
    --line: rgb(255 255 255 / 0.1);
    --text: #ececec;
    --muted: #a3a3ad;
    --gold: #ffb612;
    --gold-deep: #c98f00;

    --font: 'Source Sans 3', system-ui, -apple-system, 'Segoe UI', sans-serif;

    /* Height of the top bar, which fades in once you scroll. */
    --bar-h: 4rem;

    --container: 68rem;
    --gutter: 1.25rem;
    --radius: 0.75rem;
  }
}

/* ----------------------------------------------------------------- base */
@layer base {
  html {
    /* Anchored sections land below the pinned bar instead of under it. */
    scroll-padding-top: var(--bar-h);
    -webkit-text-size-adjust: 100%;
  }

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

  body {
    background: var(--bg);
    color: var(--text);
    font-family: var(--font);
    font-size: 1.125rem;
    line-height: 1.6;
  }

  h1,
  h2,
  h3 {
    line-height: 1.15;
    text-wrap: balance;
  }
  p {
    text-wrap: pretty;
  }

  a {
    color: var(--gold);
    text-underline-offset: 0.2em;
  }
  a:hover {
    color: #ffd25a;
  }

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

  ::selection {
    background: var(--gold);
    color: var(--bg);
  }
  /* The call to action is already gold, so invert the selection there. */
  .cta ::selection {
    background: var(--bg);
    color: var(--gold);
  }

  .skip-link {
    position: fixed;
    top: 0.5rem;
    left: 0.5rem;
    z-index: 100;
    padding: 0.5rem 1rem;
    background: var(--gold);
    color: var(--bg);
    font-weight: 700;
    border-radius: 0.375rem;
    transform: translateY(-200%);
  }
  .skip-link:focus {
    transform: none;
  }

  /* Read by screen readers, not shown. */
  .visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

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

  .section {
    padding-block: clamp(4rem, 10vw, 7rem);
  }
  .section--surface {
    background: var(--surface);
  }

  .section__title {
    margin-bottom: clamp(2rem, 5vw, 3.5rem);
    font-size: clamp(2rem, 4vw, 2.75rem);
    text-align: center;
  }
  /* Short gold rule under each section title. */
  .section__title::after {
    content: '';
    display: block;
    width: 3.5rem;
    height: 3px;
    margin: 1rem auto 0;
    background: var(--gold);
    border-radius: 2px;
  }

  .grid {
    display: grid;
    gap: 1.5rem;
  }
  .grid--projects {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
  }
}

/* ----------------------------------------------------------- components */
@layer components {
  /* Band + navigation ------------------------------------------------- */
  .band {
    position: fixed;
    inset: 0 0 auto 0;
    z-index: 10;
    height: var(--bar-h);
    overflow: hidden;
    background: var(--bg);
    border-bottom: 1px solid rgb(255 183 18 / 0.35);
  }

  .band__art {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
  }

  .band__nav {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    height: var(--bar-h);
    padding-inline: var(--gutter);
    isolation: isolate;
  }

  /* A scrim so the links stay readable over the gold shapes. */
  .band__nav::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(90deg, rgb(14 14 16 / 0.9), rgb(14 14 16 / 0.7));
  }

  .band__brand {
    color: var(--text);
    font-size: 1.25rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-decoration: none;
  }
  .band__brand-short {
    display: none;
  }

  .band__links {
    display: flex;
    gap: clamp(0.9rem, 3vw, 2rem);
    font-size: 1rem;
  }
  .band__links a {
    padding-block: 0.25rem;
    color: var(--text);
    text-decoration: none;
    border-bottom: 2px solid transparent;
  }
  .band__links a:hover {
    color: var(--gold);
  }
  .band__links a[aria-current] {
    color: var(--gold);
    border-bottom-color: var(--gold);
  }

  @media (max-width: 40rem) {
    .band__brand-full {
      display: none;
    }
    .band__brand-short {
      display: inline;
    }
    .band__links {
      font-size: 0.9rem;
      gap: 0.9rem;
    }
  }

  /* Title slide ------------------------------------------------------- */
  .title {
    position: relative;
    display: grid;
    place-items: center;
    min-height: 100svh;
    padding: 2rem var(--gutter);
    overflow: hidden;
    text-align: center;
  }

  .title__art {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
  }
  /* Vignette: pulls the shapes down to near-black behind the text so contrast stays high. */
  .title::before {
    content: '';
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse 55% 40% at 50% 50%, rgb(14 14 16 / 0.85), transparent);
  }
  .title__inner {
    position: relative;
  }

  .title h1 {
    font-size: clamp(3rem, 11vw, 7rem);
    font-weight: 800;
    letter-spacing: -0.02em;
  }

  .title__sub {
    margin-block: 0.75rem 2.25rem;
    color: var(--muted);
    font-size: clamp(1.15rem, 2.5vw, 1.6rem);
    font-weight: 300;
    letter-spacing: 0.04em;
  }

  .button {
    display: inline-block;
    padding: 0.75rem 1.75rem;
    border: 2px solid var(--gold);
    border-radius: 999px;
    color: var(--gold);
    font-weight: 600;
    text-decoration: none;
    transition:
      background-color 0.2s,
      color 0.2s;
  }
  .button:hover {
    background: var(--gold);
    color: var(--bg);
  }

  /* About ------------------------------------------------------------- */
  .about__grid {
    display: grid;
    gap: 2.5rem;
    align-items: center;
    text-align: center;
  }

  .about__photo {
    width: min(100%, 13rem);
    aspect-ratio: 1;
    margin-inline: auto;
    border: 3px solid var(--gold);
    border-radius: 50%;
    box-shadow:
      0 0 0 8px var(--bg),
      0 0 0 10px rgb(255 183 18 / 0.3);
  }

  .about h2 {
    margin-bottom: 1.25rem;
    font-size: clamp(1.75rem, 3.5vw, 2.5rem);
  }

  .lead {
    font-size: 1.25rem;
  }
  .lead + .lead {
    margin-top: 1rem;
  }

  @media (min-width: 52rem) {
    .about__grid {
      grid-template-columns: 13rem 1fr;
      gap: 4rem;
      text-align: left;
    }
  }

  /* Cards, skills, projects ------------------------------------------- */
  .card {
    background: var(--surface-raised);
    border: 1px solid var(--line);
    border-radius: var(--radius);
  }

  .skill {
    padding: 2rem;
  }
  .skill h3 {
    margin-block: 1.25rem 0.75rem;
    font-size: 1.5rem;
  }
  .skill p {
    color: var(--muted);
    font-size: 1.0625rem;
  }

  /* Carousel (js/carousel.js) ------------------------------------------
   * Below 60rem: full-bleed cards, back/forward buttons flank the title.
   * 60rem and up: one centered card with the buttons on either side of it, plus the
   * pause button and progress bar (keep that breakpoint in sync with `desktop` in
   * js/carousel.js). */
  .carousel {
    --card-width: 30rem;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      'prev title next'
      'view view view'
      'status status status';
    grid-template-rows: auto var(--stage-height, auto) auto; /* stage height set by js/carousel.js */
    align-items: center;
    row-gap: 1.5rem;
    width: fit-content;
    min-width: 100%;
    margin-inline: auto;
  }

  .carousel__title {
    grid-area: title;
    /* The row gap supplies part of the usual space under a section title. */
    margin-bottom: calc(clamp(2rem, 5vw, 3.5rem) - 1.5rem);
  }

  .carousel__viewport {
    grid-area: view;
    align-self: start; /* cards hug the top; the controls below stay put */
    overflow: hidden;
    touch-action: pan-y; /* let the page scroll vertically; JS handles horizontal swipes */
  }
  .carousel__track {
    display: flex;
    align-items: flex-start;
  } /* each card keeps its own height */

  .carousel__slide {
    display: grid;
    flex: 0 0 100%;
    min-width: 0;
    padding-inline: var(--gutter);
  }
  .carousel .skill {
    width: min(100%, 34rem);
    justify-self: center;
  }

  /* Without JS: every card is shown, in a wrapping grid with a gap between them. */
  .carousel:not(.is-enhanced) {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      'title'
      'view';
    grid-template-rows: auto;
    width: auto;
    max-width: 72rem;
  }
  .carousel:not(.is-enhanced) .carousel__viewport {
    overflow: visible;
  }
  .carousel:not(.is-enhanced) .carousel__track {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
    gap: 1.5rem;
    padding-inline: var(--gutter);
  }
  .carousel:not(.is-enhanced) .carousel__slide {
    padding-inline: 0;
  }
  .carousel:not(.is-enhanced) .skill {
    width: 100%;
  }

  .carousel__prev {
    grid-area: prev;
    align-self: start; /* level with the title text */
    margin-left: var(--gutter);
  }
  .carousel__next {
    grid-area: next;
    align-self: start;
    margin-right: var(--gutter);
  }

  .carousel__status {
    grid-area: status;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
  }
  /* Fills over the auto-rotation interval (animated from js/carousel.js). Desktop only. */
  .carousel__progress {
    display: none;
    width: 5rem;
    height: 3px;
    overflow: hidden;
    border-radius: 2px;
    background: var(--line);
  }
  .carousel__progress span {
    display: block;
    height: 100%;
    background: var(--gold);
    transform: scaleX(0);
    transform-origin: left;
  }

  .carousel__count {
    color: var(--muted);
    font-variant-numeric: tabular-nums;
  }

  .carousel__button,
  .carousel__toggle {
    display: grid;
    place-items: center;
    width: 3rem;
    height: 3rem;
    padding: 0;
    border: 2px solid var(--line);
    border-radius: 50%;
    background: transparent;
    color: var(--text);
    cursor: pointer;
    transition:
      background-color 0.2s,
      border-color 0.2s,
      color 0.2s;
  }
  .carousel__toggle {
    display: none;
    width: 2.5rem;
    height: 2.5rem;
  }
  .carousel__button:hover,
  .carousel__toggle:hover {
    background: var(--gold);
    border-color: var(--gold);
    color: var(--bg);
  }
  .carousel__button[hidden],
  .carousel__status[hidden] {
    display: none;
  }

  @media (min-width: 60rem) {
    .carousel {
      grid-template-columns: auto var(--card-width) auto;
      grid-template-areas:
        '. title .'
        'prev view next'
        '. status .';
      column-gap: 1.5rem;
      min-width: 0;
    }
    .carousel__slide {
      padding-inline: 0;
    }
    .carousel .skill {
      width: 100%;
    }
    .carousel__prev,
    .carousel__next {
      align-self: center;
      margin-inline: 0;
    }
    .carousel__toggle {
      display: grid;
    }
    .carousel__progress {
      display: block;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .carousel__progress {
      display: none;
    }
  }

  .icon {
    width: 1.5rem;
    height: 1.5rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  /* Simple Icons glyphs are filled shapes, not strokes. */
  .icon--solid {
    fill: currentColor;
    stroke: none;
  }

  /* Tags: <ul class="tags"><li>…</li></ul>. Each pill is as wide as its text and they wrap. */
  .tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 1.25rem;
  }
  .tags li {
    padding: 0.25rem 0.75rem;
    border-radius: 999px;
    background: rgb(255 183 18 / 0.14);
    color: var(--gold);
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.4;
  }

  .skill__icon {
    box-sizing: content-box;
    color: var(--gold);
    /* The ring is painted as a gradient: border-radius on an <svg> also clips the glyph to a
       circle the size of its content box, which shaves the corners off square icons. */
    --ring: 2px;
    background: radial-gradient(
      circle closest-side,
      rgb(255 183 18 / 0.08) calc(100% - var(--ring) - 0.5px),
      var(--gold) calc(100% - var(--ring) + 0.5px) calc(100% - 0.5px),
      transparent 100%
    );
    padding: calc(0.875rem + var(--ring));
  }

  .project {
    overflow: hidden;
  }
  .project img {
    width: 100%;
    aspect-ratio: 3 / 2;
    object-fit: cover;
  }
  .project__body {
    padding: 1.5rem;
  }
  .project h3 {
    margin-bottom: 0.75rem;
    font-size: 1.5rem;
  }
  .project p {
    color: var(--muted);
    font-size: 1rem;
  }
  .project p + p {
    margin-top: 0.75rem;
  }

  /* Quote ------------------------------------------------------------- */
  .quote {
    padding: clamp(4rem, 12vw, 8rem) var(--gutter);
    background:
      radial-gradient(60rem 20rem at 50% 0%, rgb(255 183 18 / 0.14), transparent 70%), var(--bg);
    text-align: center;
  }
  .quote blockquote {
    max-width: 44rem;
    margin-inline: auto;
    font-size: clamp(1.75rem, 4.5vw, 3rem);
    font-style: italic;
    font-weight: 300;
    line-height: 1.25;
    text-wrap: balance;
  }
  .quote blockquote::before {
    content: '\201C';
    display: block;
    color: var(--gold);
    font-size: 1.5em;
    font-style: normal;
    font-weight: 800;
    line-height: 0.6;
  }
  .quote figcaption {
    margin-top: 1.5rem;
    color: var(--gold);
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
  }

  /* Call to action: the one place gold is used as a surface ----------- */
  .cta {
    padding-block: clamp(3rem, 8vw, 5rem);
    background: linear-gradient(135deg, var(--gold), var(--gold-deep));
    color: var(--bg);
    text-align: center;
  }
  .cta h2 {
    margin-bottom: 0.75rem;
    font-size: clamp(1.5rem, 3vw, 2.25rem);
  }
  .cta p {
    font-size: 1.25rem;
    font-weight: 500;
  }

  /* Footer ------------------------------------------------------------ */
  .footer {
    padding-block: 3.5rem 5.5rem;
    background: var(--surface);
    color: var(--muted);
    font-size: 1rem;
    text-align: center;
  }
  .footer p + p {
    margin-top: 0.5rem;
  }
  .footer__name {
    color: var(--text);
    font-size: 1.5rem;
    font-weight: 700;
  }

  .footer__links {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
    margin-block: 1.5rem 2rem;
  }
  .footer__links a {
    display: grid;
    place-items: center;
    width: 3.25rem;
    height: 3.25rem;
    border: 2px solid var(--line);
    border-radius: 50%;
    color: var(--text);
    transition:
      background-color 0.2s,
      border-color 0.2s,
      color 0.2s;
  }
  .footer__links a:hover {
    background: var(--gold);
    border-color: var(--gold);
    color: var(--bg);
  }
  .footer__links .icon {
    width: 1.4rem;
    height: 1.4rem;
  }

  .to-top {
    position: fixed;
    right: 1.25rem;
    bottom: 1.25rem;
    z-index: 10;
    display: grid;
    place-items: center;
    width: 3rem;
    height: 3rem;
    background: var(--gold);
    border-radius: 50%;
    color: var(--bg);
    box-shadow: 0 4px 16px rgb(0 0 0 / 0.5);
  }
  .to-top:hover {
    color: var(--bg);
    background: #ffd25a;
  }
  .to-top .icon {
    stroke-width: 2.5;
  }
}

/* ------------------------------------------------------------- motion
 *
 * Scroll-linked motion
 * --------------------
 * Everything that reacts to scrolling is one CSS animation whose progress is
 * the scroll position over the first 60% of a viewport height:
 *
 *   0 ........................ 100%
 *   no bar, big title  ->  nav bar faded in, title gone, back-to-top shown
 *
 * Browsers with scroll-driven animations (Chrome, Edge, Safari 26+) get that
 * natively and the work happens off the main thread.
 *
 * Elsewhere, js/main.js writes the same progress into --scroll-p (0..1) and the
 * animations are paused and "scrubbed" with a negative delay. Same keyframes,
 * same look, so there is only one definition of the visuals.
 */
@layer motion {
  /* Transparent and click-through until the first bit of scrolling. Not visibility:hidden, so
     keyboard users can still tab into the links (see .band:focus-within below). */
  @keyframes bar-in {
    0% {
      opacity: 0;
      pointer-events: none;
    }
    100% {
      opacity: 1;
      pointer-events: auto;
    }
  }

  @keyframes title-out {
    0% {
      opacity: 1;
      transform: none;
    }
    70%,
    100% {
      opacity: 0;
      transform: translateY(-3rem);
    }
  }

  @keyframes to-top-in {
    0%,
    70% {
      opacity: 0;
      visibility: hidden;
    }
    100% {
      opacity: 1;
      visibility: visible;
    }
  }

  .band {
    animation-name: bar-in;
  }
  .title__inner {
    animation-name: title-out;
  }
  .to-top {
    animation-name: to-top-in;
  }

  .band,
  .title__inner,
  .to-top {
    animation-timing-function: linear;
    animation-fill-mode: both;
  }

  /* A focused link must be seen, and the visible band clickable, even at the top of the page.
     (!important beats animations.) */
  .band:focus-within {
    opacity: 1 !important;
    pointer-events: auto !important;
  }

  @supports (animation-timeline: scroll()) {
    .band,
    .title__inner,
    .to-top {
      animation-timeline: scroll(root);
      animation-range: 0 60svh;
    }
  }

  @supports not (animation-timeline: scroll()) {
    .band,
    .title__inner,
    .to-top {
      animation-duration: 1s;
      animation-play-state: paused;
      animation-delay: calc(var(--scroll-p, 0) * -1s);
    }

    /* Nothing drives the animations until js/main.js sets --scroll-p (it adds .scroll-fallback).
       Without it: the bar is simply there (stuck to the top, above the title slide rather than
       over it) and the back-to-top button is not. */
    :root:not(.scroll-fallback) :is(.band, .title__inner) {
      animation: none;
    }
    :root:not(.scroll-fallback) .band {
      position: sticky;
    }
    :root:not(.scroll-fallback) .to-top {
      animation: none;
      visibility: hidden;
    }
  }

  /* Sections ease in as they enter the viewport. Without support for view
     timelines they are simply visible. */
  @supports (animation-timeline: view()) {
    @keyframes reveal {
      from {
        opacity: 0;
        transform: translateY(2rem);
      }
    }
    @media (prefers-reduced-motion: no-preference) {
      .section .container,
      .carousel,
      .quote blockquote,
      .cta .container,
      .footer .container {
        animation: reveal linear both;
        animation-timeline: view();
        animation-range: entry 0% entry 40%;
      }
    }
  }

  /* Reduced motion: the bar and button still fade in with scrolling (no movement), but the
     title scrolls away like any other content instead of lifting off as it fades. */
  @media (prefers-reduced-motion: reduce) {
    .title__inner {
      animation: none;
    }
  }
}
