/* ==========================================================
   Portfolio landing page – CSS (Styles)
   Sections:
   1. Design tokens   2. Base   3. Layout helpers
   4. Header          5. Hero   6. Stack
   7. Work            7b. Contact  8. About  9. Footer
   9b. Motion (typing cursor, card reveal)
   9c. Lava lamp background (side margins on wide screens, full page below 1440px)
   10. Responsive / accessibility
   ========================================================== */

/* ---------- 1. Design tokens ---------- */
:root {
  /* Dark grays */
  --bg:          #1b1e1d;  /* page background */
  --bg-deep:     #161918;  /* header/footer strip */
  --surface:     #242826;  /* cards, code window */
  --surface-alt: #2e3331;  /* image placeholders */
  --border:      #3a403d;  /* outlines and dividers */

  /* Text */
  --text:        #e4e8e5;  /* main text */
  --text-muted:  #a9b2ad;  /* secondary text */
  --text-faint:  #818b87;  /* labels, social links */

  /* Accents */
  --green:       #7fb896;  /* main accent: buttons, logo, highlights */
  --green-ink:   #13201a;  /* dark text used on green buttons */
  --terracotta:  #c98577;  /* complementary accent, used sparingly */

  /* Lava lamp colours as R, G, B triplets (read by indexscript.js): coral is hot wax, green is warm, mint is cool */
  --lava-green:  95, 205, 150;
  --lava-mint:   160, 235, 195;
  --lava-coral:  232, 128, 108;

  /* Fade for the side-margin lava (wide screens). Stops follow a smooth S-curve across the whole
     margin, from solid at the screen edge to clear at the content column, so there is no visible
     band where the fade starts. Edit these stops to make it longer or shorter. */
  --lava-fade: #000 0%, rgba(0,0,0,.96) 10%, rgba(0,0,0,.88) 22%, rgba(0,0,0,.74) 34%,
               rgba(0,0,0,.56) 46%, rgba(0,0,0,.38) 58%, rgba(0,0,0,.22) 70%,
               rgba(0,0,0,.1) 82%, rgba(0,0,0,.03) 92%, transparent 100%;

  /* Type */
  --font-body: "Bricolage Grotesque", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;

  /* Shape and width */
  --radius-sm: 8px;
  --radius-md: 12px;
  --container: 1200px;

  color-scheme: dark;
}

/* ---------- 2. Base ---------- */
/* Smooth anchor scrolling; scroll-margin keeps targets clear of the sticky header */
html { scroll-behavior: smooth; }
[id] { scroll-margin-top: 90px; }

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  line-height: 1.5;
}

a { color: var(--text); text-decoration: none; }
a:hover { color: var(--green); }

ul { margin: 0; padding: 0; list-style: none; }

/* Clear keyboard focus ring for accessibility */
:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 3px;
}

/* ---------- 3. Layout helpers ---------- */
/* Centred content column used by every section */
.container {
  max-width: var(--container);
  margin: 0 auto;
  padding-left: 32px;
  padding-right: 32px;
}

/* Small monospace section labels, e.g. "// stack" */
.label {
  margin: 0 0 16px;
  font-family: var(--font-mono);
  font-size: 20px;
  font-weight: 500;
  color: var(--text-faint);
}

/* Hidden until focused: skip-to-content link */
.skip-link {
  position: absolute;
  left: 16px;
  top: -60px;
  background: var(--green);
  color: var(--green-ink);
  padding: 10px 16px;
  border-radius: var(--radius-sm);
  z-index: 30;
}
.skip-link:focus { top: 16px; color: var(--green-ink); }

/* ---------- 4. Header ---------- */
/* Sticky bar: transparent at the top, frosted dark glass once the page scrolls.
   The .is-scrolled class is toggled by script.js */
.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  border-bottom: 1px solid transparent;
  transition: background-color 0.3s ease, border-color 0.3s ease;
}
.site-header.is-scrolled {
  background: rgba(27, 30, 29, 0.85);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom-color: var(--border);
}
/* NOTE: the bar's height is deliberately constant. Shrinking it on scroll moved the page
   content up, which pushed the scroll position back across the threshold and made the whole
   page jitter near the top. */

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  padding-top: 28px;
  padding-bottom: 28px;
}

.logo {
  font-family: var(--font-mono);
  font-size: 22px;
  font-weight: 700;
  color: var(--green);
}
.site-footer .logo { font-size: 18px; }   /* slightly smaller beside the footer text */

.nav { display: flex; flex-wrap: wrap; gap: 32px; font-size: 16px; }

/* Nav links: green underline slides in on hover/focus and stays on the current section */
.nav a { position: relative; padding: 4px 0; }
.nav a::after {
  content: "";
  position: absolute;
  left: 0; bottom: -2px;
  width: 100%; height: 2px;
  background: var(--green);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.25s ease;
}
.nav a:hover::after,
.nav a:focus-visible::after,
.nav a[aria-current="true"]::after { transform: scaleX(1); }
.nav a[aria-current="true"] { color: var(--green); }

/* ---------- 5. Hero ---------- */
.hero {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 56px;
  align-items: center;
  padding-top: 72px;
  padding-bottom: 64px;
}

.hero__tagline {
  margin: 0 0 20px;
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--terracotta);
}

.hero h1 {
  margin: 0 0 24px;
  font-size: clamp(40px, 5vw, 64px);
  line-height: 1.05;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.hero__summary {
  margin: 0 0 36px;
  max-width: 520px;
  font-size: 19px;
  line-height: 1.6;
  color: var(--text-muted);
}

.hero__actions { display: flex; flex-wrap: wrap; gap: 16px; }

/* Buttons */
.btn {
  padding: 14px 28px;
  border-radius: var(--radius-sm);
  font-size: 16px;
}
.btn--primary { background: var(--green); color: var(--green-ink); font-weight: 700; }
.btn--primary:hover { background: var(--text); color: var(--green-ink); }
.btn--secondary { border: 1px solid var(--border); }
.btn--secondary:hover { border-color: var(--green); }

/* Social links (shared by hero, contact section and footer) */
.social {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 14px;
  font-family: var(--font-mono);
  font-size: 16px;
}
/* Off-site and email links are green "chips" by default (tinted fill, green outline, an arrow
   or envelope icon) so they stand out from normal text. On hover, keyboard focus or touch press
   a solid green fill sweeps in from the left, the text turns dark, the chip lifts and the icon
   moves. :active covers touch screens, which have no hover. */
.social a {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 6px 14px;
  border: 1px solid rgba(127, 184, 150, 0.55);
  border-radius: 999px;
  color: var(--green);
  font-weight: 500;
  background-color: rgba(127, 184, 150, 0.12);
  background-image: linear-gradient(var(--green), var(--green));
  background-repeat: no-repeat;
  background-position: left center;
  background-size: 0% 100%;                          /* the solid fill, hidden until hover */
  transition: color 0.25s ease, background-size 0.3s ease, border-color 0.25s ease,
              transform 0.2s ease, box-shadow 0.25s ease;
}
.social a:hover,
.social a:focus-visible,
.social a:active {
  color: var(--green-ink);
  border-color: var(--green);
  background-size: 100% 100%;
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(127, 184, 150, 0.28);
}
.social a:active { transform: translateY(0) scale(0.97); }   /* pressed feel on touch */
.social a[target="_blank"]::after {                /* arrow marks links that leave the site */
  content: "\2197";
  content: "\2197" / "";                          /* empty alt text so screen readers skip the arrow */
  display: inline-block;
  transition: transform 0.2s ease;
}
.social a[target="_blank"]:hover::after,
.social a[target="_blank"]:focus-visible::after,
.social a[target="_blank"]:active::after { transform: translate(3px, -3px); }
.social a[href^="mailto:"]::before {               /* envelope icon marks email links */
  content: "";
  flex: none;
  width: 1.15em;
  height: 1.15em;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linejoin='round' stroke-linecap='round'%3E%3Crect x='3' y='5' width='18' height='14' rx='2'/%3E%3Cpath d='m3 7 9 6 9-6'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linejoin='round' stroke-linecap='round'%3E%3Crect x='3' y='5' width='18' height='14' rx='2'/%3E%3Cpath d='m3 7 9 6 9-6'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: transform 0.2s ease;
}
.social a[href^="mailto:"]:hover::before,
.social a[href^="mailto:"]:focus-visible::before,
.social a[href^="mailto:"]:active::before { transform: rotate(-10deg) scale(1.15); }
.hero .social { margin-top: 28px; }

/* Code window card */
.code-card {
  margin: 0;
  padding: 24px;
  background: var(--surface);
  border: 1px solid #333936;
  border-radius: var(--radius-md);
  font-family: var(--font-mono);
  font-size: 14px;
  line-height: 1.8;
  color: var(--text-muted);
  overflow-x: auto;           /* long lines scroll instead of breaking the layout */
}
.code-card pre { margin: 0; }

/* Code stack: the hero's code windows sit in one column. Only the first window shows on screens
   under 1440px; at 1440px and over (the same point the lava lamp moves into the page margins) two more
   windows join it. Each is stepped a little further in and overlaps the bottom edge of the one before
   (the overlap only covers that window's empty bottom padding, so no code is hidden), so the three
   look stacked. Later windows sit on top, with a shadow to show the layering. */
.code-stack { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.code-card--extra { display: none; }
@media (min-width: 1440px) {
  .code-stack { gap: 0; }                            /* the overlap replaces the gap */
  .code-card--extra {
    display: block;
    position: relative;
    margin-top: -20px;                               /* tucks under the window above by 20px */
    box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.35);
  }
  .code-card--2 { margin-left: 28px; z-index: 1; }
  .code-card--3 { margin-left: 56px; z-index: 2; }
}
/* The extra windows slide in when their typing starts (indexscript.js adds .is-shown). Only with
   JavaScript running, so they are never left hidden without it. */
.js .code-card--extra { opacity: 0; transform: translateY(14px); transition: opacity 0.5s ease, transform 0.5s ease; }
.js .code-card--extra.is-shown { opacity: 1; transform: none; }
.code--compact { display: none; }   /* the short snippet only appears on mobile (section 10) */
.code-card__dots { display: flex; gap: 8px; margin-bottom: 16px; }
.code-card__dots span {
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--border);
}
/* Syntax colouring */
.kw { color: var(--terracotta); }   /* keywords */
.fn { color: var(--green); }        /* method names */

/* ---------- 6. Stack ---------- */
.stack { padding-top: 24px; padding-bottom: 56px; }

.pills { display: flex; flex-wrap: wrap; gap: 12px; }
/* Each pill is a toggle button; several can be selected at once (aria-pressed="true") */
.pill {
  padding: 10px 20px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text);
  font: inherit;
  font-size: 15px;
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease;
}
.pill:hover { border-color: rgba(127, 184, 150, 0.6); }
.pill[aria-pressed="true"] {          /* selected state */
  border-color: var(--green);
  background: rgba(127, 184, 150, 0.16);
  color: var(--green);
}

/* ---------- 7. Work ---------- */
.work { padding-bottom: 72px; }

/* Fixed 3-column grid so a card keeps its width when others are filtered out
   (auto-fit would stretch a lone card across the full row) */
.cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px;
}
@media (max-width: 900px) { .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) { .cards { grid-template-columns: 1fr; } }

/* Filter status line, e.g. "Showing 2 of 3 projects" (hidden while empty) */
.work__status {
  margin: 0 0 16px;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text-muted);
}
.work__status:empty { display: none; }


/* Cards removed by the stack filter */
.card[hidden] { display: none; }

.card {
  position: relative;                  /* anchors the whole-card link below */
  padding: 28px;
  background: var(--surface);
  border: 1px solid transparent;       /* reserved so the hover border doesn't shift layout */
  border-radius: var(--radius-md);
  transition: transform 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
}
/* Hover: card lifts and picks up a soft green edge */
.card:hover {
  transform: translateY(-6px);
  border-color: rgba(127, 184, 150, 0.5);
  box-shadow: 0 14px 32px rgba(0, 0, 0, 0.35);
}
.card:hover .card__image { background: #353b38; }
.card__image {                /* swap for a real <img> when you have screenshots */
  height: 120px;
  margin-bottom: 20px;
  background: var(--surface-alt);
  border-radius: var(--radius-sm);
  transition: background-color 0.3s ease;
}
.card h3 { margin: 0 0 8px; font-size: 22px; }

/* The whole card is one link to its project page: the title link stretches over the card
   (a single link per card keeps keyboard and screen reader use simple) */
.card__link { color: inherit; transition: color 0.2s ease; }
.card__link::after { content: ""; position: absolute; inset: 0; border-radius: var(--radius-md); }
.card__link:focus-visible { outline: none; }
.card__link:focus-visible::after { outline: 2px solid var(--green); outline-offset: 3px; }
.card:hover .card__link,
.card:focus-within .card__link { color: var(--green); }

/* "View project" cue at the bottom of each card (decorative; the title link does the work) */
.card .card__cta {                 /* .card prefix so it beats the general .card p rule */
  margin: 18px 0 0;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--green);
}
.card__cta span { display: inline-block; transition: transform 0.2s ease; }
.card:hover .card__cta span,
.card:focus-within .card__cta span { transform: translateX(5px); }
.card p  { margin: 0; color: var(--text-muted); }

/* Project tags (up to 3 per card); a tag matching a selected stack pill turns green */
.card__tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.card__tags li {
  padding: 4px 10px;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-faint);
  transition: border-color 0.2s ease, color 0.2s ease;
}
.card__tags li.is-match { border-color: var(--green); color: var(--green); }

/* ---------- 7b. Contact ---------- */
/* Extra space below so the About section sits clearly apart from the form */
.contact { padding-bottom: clamp(96px, 12vw, 160px); }

/* Two columns: intro on the left, form on the right (stacks on narrow screens) */
.contact__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 48px;
  align-items: start;
}
@media (max-width: 900px) { .contact__grid { grid-template-columns: 1fr; gap: 32px; } }

/* Top-aligned with the form: the "// Contact" heading, pitch and links hang from the form's top edge
   (no effect once the columns stack) */
.contact__intro { align-self: start; }
.contact__intro .label { line-height: 1.1; }   /* trims the gap above the heading text so it sits level with the box */

.contact__lead {
  margin: 0 0 28px;
  max-width: 480px;
  font-size: 19px;
  line-height: 1.6;
  color: var(--text-muted);
}

/* Form panel, matching the project cards */
.contact-form {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 28px;
  background: var(--surface);
  border-radius: var(--radius-md);
}
.field label {
  display: block;
  margin-bottom: 6px;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text-faint);
}
.field input,
.field textarea {
  width: 100%;
  padding: 12px 14px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font: inherit;
  font-size: 16px;
  transition: border-color 0.2s ease;
}
.field textarea { resize: vertical; min-height: 120px; }
.field input:focus,
.field textarea:focus { border-color: var(--green); }

/* Submit is a <button>, so reset the browser defaults the .btn link style doesn't expect */
button.btn { align-self: flex-start; border: 0; font: inherit; font-size: 16px; font-weight: 700; cursor: pointer; }
.form__status { margin: 0; font-family: var(--font-mono); font-size: 13px; color: var(--text-muted); }
.form__status:empty { display: none; }
/* Disabled submit button while a message is being sent */
button.btn:disabled { opacity: 0.6; cursor: not-allowed; }

/* Honeypot field: kept in the page for bots but taken out of sight and out of the layout flow
   (so it adds no gap in the form). Not display:none, as some bots skip fields hidden that way. */
.field--hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---------- 8. About ---------- */
.about { padding-bottom: 72px; }
.about p {
  margin: 0;
  max-width: 900px;           /* keeps line length comfortable to read */
  font-size: 19px;
  line-height: 1.6;
  color: var(--text-muted);
}

/* ---------- 9. Footer ---------- */
.site-footer {
  background: var(--bg-deep);
  border-top: 1px solid #2e3331;
}
.site-footer__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  padding-top: 32px;
  padding-bottom: 32px;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text-faint);
}
.site-footer p { margin: 0; }
.site-footer .social { font-size: 13px; }

/* ---------- 9b. Motion ---------- */
/* Blinking cursor shown at the end of the typed code (added by script.js) */
.cursor {
  display: inline-block;
  width: 8px;
  height: 1.1em;
  margin-left: 2px;
  background: var(--green);
  vertical-align: text-bottom;
  animation: blink 0.5s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* Cards start hidden (only when JS is running), then rise in one after another.
   --i is each card's index, set by script.js, to stagger the delay.
   "backwards" fill keeps the hover transform working after the animation ends. */
.js .card { opacity: 0; }
.js .card.is-visible {
  opacity: 1;
  animation: rise 0.6s ease backwards;
  animation-delay: calc(var(--i, 0) * 120ms);
}
@keyframes rise {
  from { opacity: 0; transform: translateY(24px); }
}

/* ---------- 9c. Lava lamp background ----------
   A fixed layer behind everything. The animation itself is drawn onto two canvases by
   indexscript.js (section 7).
   - Wide screens (over 1440px): each canvas fills one page margin outside the content column
     (the page width minus --container, split in two), so nothing animates behind the content.
     The edge facing the content fades out gradually (--lava-fade) so the lava blends into the page.
   - Screens 1440px and narrower (phones, tablets, small laptops): the margins are too small to
     show anything, so the left canvas covers the whole page behind all the content instead
     (see the block at the end of section 10).
   The colours come from the --lava-* variables in the design tokens. */
.lava {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}
.lava__canvas {
  position: absolute;
  top: 0;
  height: 100%;
  width: max(0px, calc((100% - var(--container)) / 2));
}
.lava__canvas--left {
  left: 0;
  -webkit-mask-image: linear-gradient(to right, var(--lava-fade));
  mask-image: linear-gradient(to right, var(--lava-fade));
}
.lava__canvas--right {
  right: 0;
  -webkit-mask-image: linear-gradient(to left, var(--lava-fade));
  mask-image: linear-gradient(to left, var(--lava-fade));
}

/* ---------- 10. Responsive / accessibility ---------- */
/* ---------- Full-page lava lamp (1440px and narrower) ----------
   Below this width the page margins are under ~120px, too small to show the lava, so the lamp
   moves behind the whole site instead (phones, tablets and small laptops). One canvas covers the
   page and the right canvas is switched off. It is dimmed well down (24% opacity) so text stays
   readable, the content panels and footer are only slightly see-through so the lava still glows
   behind them, the skill pills share the project cards' fill, and the secondary text colours are brightened to
   compensate. indexscript.js detects the full-width canvas by itself and switches the lamp to its
   full-screen mode. */
@media (max-width: 1439px) {
  .lava__canvas--right { display: none; }
  .lava__canvas--left {
    width: 100%;
    opacity: 0.24;                              /* dimmed so text and panels keep strong contrast */
    filter: brightness(0.85);                   /* and a little darker */
    -webkit-mask-image: none;
    mask-image: none;
  }
  :root {
    --surface: rgba(36, 40, 38, 0.92);
    --text-muted: #c4ccc7;
    --text-faint: #a3ada8;
  }
  .site-footer { background: rgba(22, 25, 24, 0.88); }

  /* Skill pills: the same fill as the project cards (--surface) so they contrast with the lava.
     The selected pill keeps its green tint, layered over that same fill. */
  .pill { background-color: var(--surface); }
  .pill[aria-pressed="true"] {
    background-image: linear-gradient(rgba(127, 184, 150, 0.16), rgba(127, 184, 150, 0.16));
    background-color: var(--surface);
  }
}

/* ---------- Mobile (600px and narrower) ---------- */
@media (max-width: 600px) {
  .container { padding-left: 20px; padding-right: 20px; }
  [id] { scroll-margin-top: 120px; }            /* the stacked header is taller, so anchors need more room */

  /* Header: logo above the nav, both centred, tighter vertically */
  .site-header__inner {
    flex-direction: column;
    justify-content: center;
    gap: 10px;
    padding-top: 16px;
    padding-bottom: 16px;
  }
  .nav { justify-content: center; gap: 20px; }

  /* Hero: one column with all content centred */
  .hero {
    grid-template-columns: minmax(0, 1fr);      /* the 340px minimum would overflow small phones */
    gap: 28px;
    padding-top: 24px;
    text-align: center;
  }
  .hero__tagline { margin-bottom: 12px; }
  .hero h1 { margin-bottom: 16px; }
  .hero__summary { margin: 0 auto 24px; }
  .hero__actions,
  .hero .social { justify-content: center; }
  .hero .social { margin-top: 20px; }

  /* Code card: much shorter. Swap in the 3-line snippet, tighten spacing, keep text left-aligned */
  .code-card { padding: 16px; font-size: 12px; line-height: 1.6; text-align: left; }
  .code-card__dots { margin-bottom: 10px; }
  .code--full { display: none; }
  .code--compact { display: block; }

  /* Contact form: a smaller box */
  .contact-form { padding: 18px; gap: 12px; }
  .field label { margin-bottom: 4px; font-size: 12px; }
  .field input,
  .field textarea { padding: 9px 12px; }
  .field textarea { height: 88px; min-height: 88px; }
  button.btn { padding: 11px 22px; }

  /* Footer: stacked and centred instead of wrapping unevenly */
  .site-footer__inner {
    flex-direction: column;
    justify-content: center;
    gap: 12px;
    padding-top: 24px;
    padding-bottom: 24px;
    text-align: center;
  }
  .site-footer .logo { display: block; margin-bottom: 4px; }
  .site-footer .social { justify-content: center; gap: 8px 20px; }
  .site-footer .social a { overflow-wrap: anywhere; }   /* a long email address can't push the page wider */

  /* Smaller gaps between sections (the desktop spacing is too generous on a phone) */
  .hero    { padding-bottom: 16px; }
  .stack   { padding-top: 0; padding-bottom: 20px; }
  .work    { padding-bottom: 28px; }
  .contact { padding-bottom: 32px; }
  .about   { padding-bottom: 28px; }
  .label   { margin-bottom: 10px; font-size: 18px; }
  .pills   { gap: 8px; }
  .contact__grid { gap: 20px; }
  .contact__lead { margin-bottom: 16px; }
}

/* Respect users who prefer no motion (this design has none, so this is a safeguard) */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
}
