@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter-latin.v20.woff2") format("woff2");
}

*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

:root {
  color-scheme: light dark;
  --accent: #ff8d28;
  --accent-hover: #f2831c;
  --accent-active: #e67d18;
  --accent-focus: rgba(255, 141, 40, 0.28);
  --accent-secondary-focus: rgba(255, 141, 40, 0.16);
  --text-primary: #000;
  --text-secondary: rgba(0, 0, 0, 0.8);
  --text-muted: rgba(0, 0, 0, 0.52);
  --text-footer: rgba(0, 0, 0, 0.42);
  --page-background: #fff;
  --card-background: rgba(0, 0, 0, 0.028);
  --card-border: rgba(0, 0, 0, 0.06);
  --badge-background: rgba(255, 141, 40, 0.14);
  --space-1: 0.5rem;
  --space-2: 0.75rem;
  --space-3: 1rem;
  --space-4: 1.25rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 2.5rem;
  --radius-card: 1.55rem;
  --radius-card-mobile: 1.35rem;
  --icon-size-footer: 0.95rem;
  --icon-size-footer-linkedin-box: 1.34rem;
  --icon-size-footer-linkedin-glyph: 4rem;
  --icon-divider-height: 0.8rem;
  --font-stack: -apple-system, BlinkMacSystemFont, "Inter", sans-serif;
}

body {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  width: 100%;
  background: var(--page-background);
  color: var(--text-primary);
  font-family: var(--font-stack);
}

.page-home main,
.page-404 main {
  flex: 1;
  display: flex;
}

.site-header {
  width: 100%;
  flex: 1;
  display: grid;
  place-items: center;
}

.page-home,
.page-404 {
  align-items: center;
  justify-content: flex-start;
}

.page-projects {
  align-items: center;
  justify-content: flex-start;
}

.hero {
  text-align: left;
}

.hero h1 {
  font-size: 3rem;
  font-weight: 700;
  line-height: 1;
  color: var(--text-primary);
  opacity: 0;
  filter: blur(10px);
  animation: appleReveal 1s cubic-bezier(0.16, 1, 0.3, 1) 0.12s forwards;
}

.hero h2 {
  margin-top: 0.5rem;
  font-size: 1.5rem;
  font-weight: 400;
  line-height: 1.25;
  color: var(--text-secondary);
  opacity: 0;
  filter: blur(8px);
  animation: appleReveal 1s cubic-bezier(0.16, 1, 0.3, 1) 0.22s forwards;
}

.page-home .hero {
  padding: 6rem 1.25rem 4rem;
}

/* 404 has a back button, so (like .page-doc/.page-projects) it needs a flex
   column instead of the single centered grid item .site-header uses
   elsewhere. .top-action is anchored to site-header's own padding box
   (top: 0), not to .hero — a fixed, always-visible position, completely
   excluded from .hero's centering math since it's out of flow. .hero's
   auto top/bottom margins center it when it fits and clamp to 0
   (top-aligned, never clipped) when it doesn't — unlike
   justify-content: center, which lets overflow push content above the
   visible area with no way to scroll back to it.

   .page-home main, .page-404 main {flex:1;display:flex;} has no width of
   its own — with body's align-items: center, that means main shrinks to
   fit its content (the "404"/"Page Not Found" text), so it was never
   actually as wide as the content column used elsewhere on the site. An
   explicit width here (matching .page-doc/.page-projects main) is what
   lets .top-action align with the same left edge as the footer divider,
   instead of the button and its box shrink-wrapping around the button
   itself. .hero still centers within this wider main exactly as before —
   align-items: center doesn't care how wide the container actually is. */
.page-404 main {
  width: min(100%, 58rem);
  margin: 0 auto;
}

.page-404 .site-header {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 3.5rem 1.25rem 4rem;
}

/* Width-matched to the same content column used everywhere else on the site
   (.page-doc/.page-projects .top-action, the footer divider). top must
   match site-header's own padding-top exactly (not 0) — see the equivalent
   comment on .page-doc .top-action for why 0 ignores the padding entirely
   and sits flush against the true outer/viewport edge. left/right stay 0
   (not site-header's side padding) deliberately — with width also set,
   left + right + width is over-constrained and browsers silently discard
   "right", so the side inset is instead baked into the width formula. */
.page-404 .top-action {
  position: absolute;
  top: 3.5rem;
  left: 0;
  right: 0;
  width: min(calc(100% - 2.5rem), 40rem);
  margin: 0 auto;
}

.page-404 .hero {
  /* Guarantees a minimum gap from the button above — see .page-doc .content
     for why margin-top: auto alone isn't enough. */
  padding-top: 4rem;
  margin-top: auto;
  margin-bottom: auto;
}

@media (min-width: 1024px) {
  .page-404 main {
    width: min(100%, 62rem);
  }

  .page-404 .top-action {
    width: min(calc(100% - 2.5rem), 46rem);
  }
}

@media (min-width: 1440px) {
  .page-404 main {
    width: min(100%, 68rem);
  }

  .page-404 .top-action {
    width: min(calc(100% - 2.5rem), 50rem);
  }
}

.page-projects main {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: min(100%, 58rem);
  margin: 0 auto;
  padding: 3.5rem 1.25rem 4rem;
}

/* Anchored to main's own padding box, not to .content — so it renders at a
   fixed, always-visible position regardless of where .content ends up, and
   is completely excluded from .content's centering math (it's out of flow,
   so .content is main's only flow child). This is what makes .content's
   centering ignore the button's height entirely without risking the button
   being pushed off-screen, which happened when it was anchored to
   .content's own (variable) position instead. .content's auto top/bottom
   margins center it when it fits and clamp to 0 (top-aligned, never
   clipped) when it doesn't — unlike justify-content: center, which lets
   overflow push content above the visible area with no way to scroll back
   to it.

   top must match main's own padding-top exactly (not 0) — the containing
   block for an absolutely positioned element is the nearest positioned
   ancestor's *padding box*, so top: 0 aligns with where main's padding
   starts being applied, not with its content edge. In other words 0
   ignores main's padding entirely and sits flush against main's true
   outer edge (the viewport edge, in practice) — which was the "touches
   the top" bug. left/right stay 0 (not main's side padding) deliberately:
   with width also set, left + right + width is over-constrained, and
   browsers resolve that by silently discarding the "right" value — so a
   non-zero left/right here would NOT inset the button as expected. The
   side inset is instead baked into the width formula below. */
.page-projects .top-action {
  position: absolute;
  top: 3.5rem;
  left: 0;
  right: 0;
  width: min(calc(100% - 2.5rem), 40rem);
  margin: 0 auto;
}

.page-projects .content {
  width: min(100%, 40rem);
  /* Guarantees a minimum gap from the button above even in the worst case
     (margin-top resolving toward 0 for content close to main's full
     height, e.g. longer pages on short mobile viewports) — margin-top:auto
     alone has no floor, so without this the heading could render right up
     against the button. */
  padding-top: 4rem;
  margin-top: auto;
  margin-bottom: auto;
}

.page-projects .hero {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
}

.page-projects .hero h2 {
  max-width: 34rem;
}

@media (min-width: 1024px) {
  .page-projects main {
    width: min(100%, 62rem);
  }

  .page-projects .top-action {
    width: min(calc(100% - 2.5rem), 46rem);
  }

  .page-projects .content {
    width: min(100%, 46rem);
  }
}

@media (min-width: 1440px) {
  .page-projects main {
    width: min(100%, 68rem);
  }

  .page-projects .top-action {
    width: min(calc(100% - 2.5rem), 50rem);
  }

  .page-projects .content {
    width: min(100%, 50rem);
  }
}

.actions {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: var(--space-5);
}

/* Normal document flow (not absolutely positioned) so it can never be pushed
   off-screen or clipped — a real bug on mobile when it was excluded from
   flow entirely. Pages that want it excluded from vertical-centering math
   achieve that structurally instead, by placing it outside the centered
   box (see .page-doc/.page-projects/.page-404 below). */
/* Renders above .hero on every page that has it (doc/projects/404), so it
   must animate in before the elements below it - delay is intentionally
   lower than .hero h1's, not higher, to keep the reveal moving top to
   bottom instead of having the back button pop in after the heading. */
.top-action {
  width: 100%;
  margin-bottom: var(--space-5);
  opacity: 0;
  transform: translateY(8px) scale(0.98);
  filter: blur(6px);
  animation: appleButtonReveal 0.95s cubic-bezier(0.16, 1, 0.3, 1) 0.08s forwards;
}

.page-projects .actions {
  width: 100%;
  opacity: 0;
  transform: translateY(8px) scale(0.98);
  filter: blur(6px);
  animation: appleButtonReveal 0.95s cubic-bezier(0.16, 1, 0.3, 1) 0.32s forwards;
}

.button {
  display: inline-flex;
  align-items: center;
  padding: 0.7rem 1.16rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font-size: 0.92rem;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.012em;
  text-decoration: none;
  transition: background-color 160ms ease, transform 160ms ease, box-shadow 160ms ease, color 160ms ease;
  box-shadow: 0 0 0 0 rgba(255, 141, 40, 0);
  -webkit-font-smoothing: antialiased;
}

/* .page-404's only button is the back button already inside .top-action,
   which has its own reveal animation on the parent - giving the button a
   second, independently-timed opacity/blur animation compounded the two
   (opacity and blur filters stack down the tree), producing a double-blur
   that finished at a different time than the parent's. Home's buttons
   aren't inside an already-animated ancestor, so they still need this. */
.page-home .button {
  opacity: 0;
  transform: translateY(8px) scale(0.98);
  filter: blur(6px);
  animation: appleButtonReveal 0.95s cubic-bezier(0.16, 1, 0.3, 1) 0.32s forwards;
}

.button:hover {
  background: var(--accent-hover);
  transform: scale(1.01);
}

.button:active {
  background: var(--accent-active);
  transform: scale(0.99);
}

.button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-focus);
}

.button.secondary,
.secondary-link {
  background: transparent;
  color: var(--accent);
  border-color: var(--accent);
  box-shadow: none;
}

.button.secondary:hover,
.secondary-link:hover {
  background: var(--accent);
  color: #fff;
}

.button.secondary:active,
.secondary-link:active {
  background: var(--accent-active);
  color: #fff;
}

.button.secondary:focus-visible,
.secondary-link:focus-visible {
  box-shadow: 0 0 0 3px var(--accent-secondary-focus);
}

.social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.4rem;
  height: 2.4rem;
  color: var(--accent);
  text-decoration: none;
  opacity: 0;
  transform: translateY(8px) scale(0.98);
  filter: blur(6px);
  animation: appleButtonReveal 0.95s cubic-bezier(0.16, 1, 0.3, 1) 0.32s forwards;
  transition: color 160ms ease, transform 160ms ease;
}

.social-link svg {
  width: 1.02rem;
  height: 1.02rem;
  fill: currentColor;
}

.footer-links {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: calc(var(--space-1) + 0.05rem);
  width: 100%;
}

/* The deploy's git commit hash, injected server-side (see
   functions/_middleware.js) — pushed to the far right edge of the content
   area via margin-left: auto (footer-links now spans the full width, so
   this reaches the same right edge as the divider above it), and
   deliberately fainter than everything else in the footer since it's a
   low-priority technical detail, not a link. */
.footer-commit {
  margin-left: auto;
  padding-left: var(--space-2);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.7rem;
  color: inherit;
  opacity: 0.5;
}

.footer-divider {
  width: 1px;
  height: var(--icon-divider-height);
  background: rgba(0, 0, 0, 0.16);
}

.footer-text-link {
  color: inherit;
  text-decoration: none;
  transition: color 160ms ease;
}

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

.footer-text-link:focus-visible {
  outline: none;
  color: var(--accent);
}

.footer-pipe {
  color: inherit;
}

.footer-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  color: inherit;
  text-decoration: none;
  transition: color 160ms ease, transform 160ms ease;
}

.footer-link svg {
  display: block;
  width: var(--icon-size-footer);
  height: var(--icon-size-footer);
  fill: currentColor;
}

.footer-linkedin svg {
  width: var(--icon-size-footer-linkedin-glyph);
  height: var(--icon-size-footer-linkedin-glyph);
}

.footer-linkedin {
  width: var(--icon-size-footer-linkedin-box);
  height: var(--icon-size-footer-linkedin-box);
}

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

.footer-link:active {
  color: var(--accent-active);
  transform: none;
}

.footer-link:focus-visible {
  outline: none;
  color: var(--accent);
  transform: none;
}

.social-link:hover {
  color: var(--accent-hover);
  transform: scale(1.03);
}

.social-link:active {
  color: var(--accent-active);
  transform: scale(0.98);
}

.social-link:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-secondary-focus);
  border-radius: 999px;
}

.project-list {
  margin-top: var(--space-7);
  opacity: 0;
  filter: blur(8px);
  animation: appleReveal 1s cubic-bezier(0.16, 1, 0.3, 1) 0.3s forwards;
}

.project {
  padding: 1.35rem 1.4rem;
  border-radius: var(--radius-card);
  background: var(--card-background);
  border: 1px solid var(--card-border);
}

.project + .project {
  margin-top: var(--space-3);
}

.project-label {
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--text-muted);
}

.project-title {
  margin-top: 0.42rem;
  font-size: 1.45rem;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

.project-header {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  flex-wrap: wrap;
  margin-top: 0.42rem;
}

.project-header .project-title {
  margin-top: 0;
}

.badge {
  display: inline-flex;
  align-items: center;
  padding: 0.34rem 0.58rem;
  border-radius: 999px;
  background: var(--badge-background);
  color: var(--accent);
  font-size: 0.74rem;
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: -0.01em;
  -webkit-font-smoothing: antialiased;
}

.project-copy {
  margin-top: 0.6rem;
  font-size: 1rem;
  line-height: 1.55;
  color: rgba(0, 0, 0, 0.72);
}

.project-link {
  display: inline-block;
  color: var(--accent);
  font-size: 0.94rem;
  font-weight: 400;
  letter-spacing: -0.01em;
  text-decoration: none;
}

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

.acknowledgements {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  margin-top: 0.65rem;
}

footer {
  width: 100%;
  margin-top: auto;
  padding: 0 var(--space-4) var(--space-6);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: left;
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: -0.01em;
  color: var(--text-footer);
  -webkit-font-smoothing: antialiased;
}

/* Aligns the footer's left edge with the page's content column instead of
   the viewport edge, matching .page-doc/.page-projects .content widths.
   The top border is the divider line spanning the content width. Copyright
   always sits on its own line above the link row, at every viewport size. */
.footer-inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  width: min(100%, 40rem);
  margin: 0 auto;
  padding-top: var(--space-5);
  border-top: 1px solid var(--card-border);
}

@media (min-width: 1024px) {
  .footer-inner {
    width: min(100%, 46rem);
  }
}

@media (min-width: 1440px) {
  .footer-inner {
    width: min(100%, 50rem);
  }
}

@media (min-width: 768px) {
  .hero h1 {
    font-size: 3.75rem;
  }

  .hero h2 {
    font-size: 1.875rem;
  }
}

@media (max-width: 640px) {
  .page-home .hero,
  .page-404 .site-header {
    padding: 3rem var(--space-4);
  }

  .page-404 .top-action {
    top: 3rem;
  }

  .hero h1 {
    font-size: clamp(2.5rem, 12vw, 3.1rem);
  }

  .hero h2 {
    font-size: clamp(1.15rem, 5.4vw, 1.4rem);
  }

  .page-home .actions,
  .page-projects .actions {
    justify-content: flex-start;
  }

  .page-projects main {
    padding-top: 3rem;
    padding-bottom: 3rem;
  }

  .page-projects .top-action {
    top: 3rem;
  }

  .page-projects .content {
    width: 100%;
  }

  .page-projects .hero h2,
  .page-404 .hero h2 {
    max-width: 18rem;
  }

  .project-list {
    margin-top: 2rem;
  }

  .project {
    padding: 1.15rem 1.1rem;
    border-radius: var(--radius-card-mobile);
  }

  .project-title {
    font-size: 1.28rem;
  }

  .project-copy {
    font-size: 0.96rem;
  }

  .acknowledgements {
    gap: 0.65rem 0.9rem;
  }

  footer {
    padding-bottom: 1.5rem;
    font-size: 0.72rem;
  }

}

@media (prefers-color-scheme: dark) {
  :root {
    --accent: #ff9230;
    --accent-hover: #ffa24d;
    --accent-active: #ff8d28;
    --text-primary: rgb(246, 248, 249);
    --text-secondary: rgba(246, 248, 249, 0.8);
    --text-muted: rgba(246, 248, 249, 0.52);
    --text-footer: rgba(246, 248, 249, 0.42);
    --page-background: #000;
    --card-background: rgba(255, 255, 255, 0.05);
    --card-border: rgba(255, 255, 255, 0.08);
    --badge-background: rgba(255, 146, 48, 0.18);
  }

  .project-copy {
    color: rgba(246, 248, 249, 0.8);
  }

  .footer-divider {
    background: rgba(246, 248, 249, 0.16);
  }
}

@keyframes appleReveal {
  from {
    opacity: 0;
    transform: translateY(18px) scale(0.985);
    filter: blur(10px);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
  }
}

@keyframes appleButtonReveal {
  from {
    opacity: 0;
    transform: translateY(8px) scale(0.98);
    filter: blur(6px);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero h1,
  .hero h2,
  .top-action,
  .actions,
  .button,
  .social-link,
  .project-list,
  footer {
    animation: none !important;
    opacity: 1;
    filter: none;
    transform: none;
    transition: none;
  }

  .page-home .button,
  .page-404 .button,
  .top-action,
  .page-projects .actions,
  .footer-link,
  .footer-links {
    animation: none !important;
    opacity: 1;
    filter: none;
    transform: none;
    transition: none;
  }
}
