/* ============================================================================
   Mahmoud Abia — portfolio stylesheet
   No framework, no build step. Organised as:
     1. Tokens & themes      5. Sections
     2. Reset & base         6. Components
     3. Layout               7. Responsive
     4. Header & nav         8. Motion preferences
   ========================================================================== */

/* ── 1. TOKENS & THEMES ─────────────────────────────────────────────────────
   Every colour is defined on bare :root first, so no token is ever undefined.
   The two dark blocks only *redefine* those tokens:
     - @media (prefers-color-scheme: dark) → OS preference, when no explicit choice
     - :root[data-theme="dark"]            → the toggle, which wins either way
   The :not([data-theme="light"]) guard lets the toggle force light on a dark OS.
   ------------------------------------------------------------------------- */
:root {
  --bg:            #fbfbfe;
  --bg-alt:        #f5f3fd;
  --surface:       #ffffff;
  --surface-hover: #f3f1fb;
  --border:        #e7e4f3;
  --border-strong: #cfcae1;

  --text:          #14131f;
  --text-muted:    #565169;
  --text-faint:    #837e99;

  --accent:        #4f46e5;
  --accent-hover:  #4338ca;
  --accent-soft:   #eef2ff;
  --accent-text:   #4f46e5;
  --on-accent:     #ffffff;

  --shadow-sm: 0 1px 2px rgba(16, 24, 40, .06), 0 1px 3px rgba(16, 24, 40, .08);
  --shadow-md: 0 4px 8px -2px rgba(16, 24, 40, .08), 0 2px 4px -2px rgba(16, 24, 40, .05);
  --shadow-lg: 0 12px 24px -6px rgba(16, 24, 40, .12), 0 4px 8px -4px rgba(16, 24, 40, .06);

  /* Skills-section canvas + the four coloured glows floating on it.
     Light theme keeps them barely-there; the dark blocks turn them up. */
  --skills-bg: #efecfb;
  --glow-a: rgba(255, 138, 46, .16);
  --glow-b: rgba(16, 185, 129, .14);
  --glow-c: rgba(124, 92, 255, .16);
  --glow-d: rgba(234, 179, 8, .14);

  /* Page-wide ambient field painted behind everything by body::before. */
  --amb-1: rgba(124, 92, 255, .14);
  --amb-2: rgba(56, 189, 248, .11);
  --amb-3: rgba(244, 114, 182, .10);
  --amb-4: rgba(251, 191, 36, .09);

  --header-h: 68px;
  --radius:    14px;
  --radius-sm: 9px;
  --maxw:      1120px;

  --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --ease: cubic-bezier(.22, .61, .36, 1);
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:            #08070f;
    --bg-alt:        #0d0c1a;
    --surface:       #141326;
    --surface-hover: #1c1a33;
    --border:        #272444;
    --border-strong: #383455;

    --text:          #eae8f6;
    --text-muted:    #a29dbd;
    --text-faint:    #746f90;

    --accent:        #7c78f0;
    --accent-hover:  #918dff;
    --accent-soft:   #1b1f3a;
    --accent-text:   #a5a1ff;
    --on-accent:     #08070f;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-md: 0 4px 10px -2px rgba(0, 0, 0, .5);
    --shadow-lg: 0 16px 32px -8px rgba(0, 0, 0, .6);

    --skills-bg: #06050d;
    --glow-a: rgba(255, 122, 26, .30);
    --glow-b: rgba(16, 185, 129, .26);
    --glow-c: rgba(124, 92, 255, .30);
    --glow-d: rgba(234, 179, 8, .22);

    --amb-1: rgba(124, 92, 255, .30);
    --amb-2: rgba(34, 211, 238, .20);
    --amb-3: rgba(244, 114, 182, .18);
    --amb-4: rgba(251, 191, 36, .13);

    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --bg:            #08070f;
  --bg-alt:        #0d0c1a;
  --surface:       #141326;
  --surface-hover: #1c1a33;
  --border:        #272444;
  --border-strong: #383455;

  --text:          #eae8f6;
  --text-muted:    #a29dbd;
  --text-faint:    #746f90;

  --accent:        #7c78f0;
  --accent-hover:  #918dff;
  --accent-soft:   #1b1f3a;
  --accent-text:   #a5a1ff;
  --on-accent:     #08070f;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-md: 0 4px 10px -2px rgba(0, 0, 0, .5);
  --shadow-lg: 0 16px 32px -8px rgba(0, 0, 0, .6);

  --skills-bg: #06050d;
  --glow-a: rgba(255, 122, 26, .30);
  --glow-b: rgba(16, 185, 129, .26);
  --glow-c: rgba(124, 92, 255, .30);
  --glow-d: rgba(234, 179, 8, .22);

  --amb-1: rgba(124, 92, 255, .30);
  --amb-2: rgba(34, 211, 238, .20);
  --amb-3: rgba(244, 114, 182, .18);
  --amb-4: rgba(251, 191, 36, .13);

  color-scheme: dark;
}

/* ── 2. RESET & BASE ─────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

/* The base colour lives on <html>, not <body>. A body background propagates to
   the canvas, which would leave body::before fighting it for paint order; this
   way the stack is unambiguous: html colour, then the ambient field, then content. */
html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  background: var(--bg);
  transition: background-color .25s var(--ease);
}

body {
  position: relative;
  margin: 0;
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.65;
  color: var(--text);
  background: transparent;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  transition: color .25s var(--ease);
}

/* Ambient colour field behind the whole page — four soft light sources rather
   than a flat sheet of white or black. It's `fixed`, so it stays put while the
   content scrolls over it, and the page reads as one lit surface instead of a
   stack of grey bands. Sections below are translucent so it shows through. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(46rem 34rem at 10% -8%, var(--amb-1), transparent 62%),
    radial-gradient(40rem 30rem at 94% 4%,  var(--amb-2), transparent 62%),
    radial-gradient(44rem 34rem at 82% 58%, var(--amb-3), transparent 62%),
    radial-gradient(40rem 32rem at 2% 92%,  var(--amb-4), transparent 62%);
}

h1, h2, h3, h4 { line-height: 1.18; margin: 0; font-weight: 700; letter-spacing: -.02em; }
p  { margin: 0 0 1rem; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img { max-width: 100%; height: auto; display: block; }

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

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

::selection { background: var(--accent); color: var(--on-accent); }

/* Shared inline-SVG icon rules: stroked by default, `.icon-fill` for solid glyphs. */
.icon {
  width: 1.15em; height: 1.15em;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.icon-fill { fill: currentColor; stroke: none; }

.skip-link {
  position: absolute;
  left: 50%; top: 0;
  transform: translate(-50%, -120%);
  z-index: 200;
  padding: .7rem 1.2rem;
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  transition: transform .2s var(--ease);
}
.skip-link:focus { transform: translate(-50%, 0); text-decoration: none; }

/* ── 3. LAYOUT ───────────────────────────────────────────────────────────── */
.container {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: 1.25rem;
}

.section {
  padding-block: clamp(3.5rem, 9vw, 6.5rem);
  scroll-margin-top: var(--header-h);
}
/* Translucent, not solid — an opaque band would blank out the ambient field
   underneath and put the flat grey stripes straight back. */
.section-alt { background: color-mix(in srgb, var(--bg-alt) 62%, transparent); }

.section-head { max-width: 46rem; margin-bottom: clamp(2rem, 5vw, 3rem); }

.section-kicker {
  font-family: var(--font-mono);
  font-size: .8rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--accent-text);
  margin-bottom: .6rem;
}

.section-title {
  font-size: clamp(1.8rem, 4.4vw, 2.6rem);
  margin-bottom: .75rem;
}

.section-lead { color: var(--text-muted); font-size: 1.05rem; margin: 0; }

/* ── 4. HEADER & NAV ─────────────────────────────────────────────────────── */
/* Sitting at the top of the page there is nothing underneath, so the bar can be
   mostly transparent and let the ambient field through. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background-color: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid transparent;
  transition: background-color .25s var(--ease), border-color .25s var(--ease),
              box-shadow .25s var(--ease);
}

/* Once content is scrolling underneath, the bar has to actually cover it.
   At the old 82% the hero copy stayed legible straight through the wordmark,
   which read as a rendering fault rather than a design. */
.site-header.is-stuck {
  background-color: color-mix(in srgb, var(--bg) 95%, transparent);
  border-bottom-color: var(--border);
  box-shadow: var(--shadow-sm);
}

.header-inner {
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  color: var(--text);
  font-weight: 700;
  letter-spacing: -.02em;
}
.brand:hover { text-decoration: none; }

/* The header avatar. Served at 400px for retina, drawn at 34. object-fit keeps
   a slightly-off crop filling the box rather than squashing.
   (This replaced an "MA" monogram; that rule is in git history if ever wanted.) */
.brand-photo {
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 10px;
  object-fit: cover;
  background: var(--surface-hover);
}

.nav-list { display: flex; align-items: center; gap: .35rem; }

.nav-list a {
  display: block;
  padding: .5rem .85rem;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: .93rem;
  font-weight: 500;
  transition: color .18s var(--ease), background-color .18s var(--ease);
}
.nav-list a:hover { color: var(--text); background: var(--surface-hover); text-decoration: none; }
.nav-list a.is-active { color: var(--accent-text); background: var(--accent-soft); }

.header-actions { display: flex; align-items: center; gap: .4rem; }

.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 40px; height: 40px;
  padding: 0;
  font-size: 1.05rem;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: color .18s var(--ease), background-color .18s var(--ease), border-color .18s var(--ease);
}
.icon-btn:hover {
  color: var(--text);
  background: var(--surface-hover);
  border-color: var(--border);
  text-decoration: none;
}

/* Only one of the two theme glyphs is ever shown. */
.icon-moon { display: none; }
:root[data-theme="dark"] .icon-sun  { display: none; }
:root[data-theme="dark"] .icon-moon { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .icon-sun  { display: none; }
  :root:not([data-theme="light"]) .icon-moon { display: block; }
}

.menu-toggle { display: none; }

.burger { display: block; width: 19px; }
.burger i {
  display: block;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
  transition: transform .25s var(--ease), opacity .2s var(--ease);
}
.burger i + i { margin-top: 4.5px; }

.menu-toggle[aria-expanded="true"] .burger i:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.menu-toggle[aria-expanded="true"] .burger i:nth-child(2) { opacity: 0; }
.menu-toggle[aria-expanded="true"] .burger i:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* ── 5. SECTIONS ─────────────────────────────────────────────────────────── */

/* Hero ------------------------------------------------------------------- */
.hero {
  position: relative;
  padding-block: clamp(3.5rem, 12vw, 7.5rem) clamp(3rem, 8vw, 5.5rem);
  overflow: hidden;
}
/* Soft radial glow behind the hero — decorative only. */
.hero::before {
  content: "";
  position: absolute;
  top: -35%; left: 50%;
  width: min(900px, 130vw);
  aspect-ratio: 1;
  transform: translateX(-50%);
  /* Softened from 16%: the page-wide ambient field now lights this area too,
     and at the old strength the two stacked into a hot spot behind the H1. */
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 10%, transparent) 0%, transparent 62%);
  pointer-events: none;
  z-index: 0;
}
.hero-inner { position: relative; z-index: 1; }

/* Single column by design: the hero leads with the claim, and the work section
   right below carries the devices. A phone up here would narrow the positioning
   to iOS before the reader gets to the rest. */
.hero-grid {
  display: grid;
  gap: clamp(2.5rem, 6vw, 4rem);
  align-items: center;
}
.hero-copy { max-width: 42rem; }

/* Quiet one-liner naming the stack — breadth, stated up front. */
.hero-stack {
  margin: -.5rem 0 1.75rem;
  font-size: .92rem;
  color: var(--text-faint);
}
.hero-stack-label {
  display: block;
  margin-bottom: .25rem;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.hero-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  padding: .35rem .85rem .35rem .6rem;
  margin-bottom: 1.4rem;
  font-size: .85rem;
  font-weight: 500;
  color: var(--text-muted);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  box-shadow: var(--shadow-sm);
}

.status-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: #22c55e;
  box-shadow: 0 0 0 3px color-mix(in srgb, #22c55e 22%, transparent);
}

/* The floor used to be 2.6rem, which overflowed a 320px screen because the
   line "and websites." can't shrink below it. A lower floor with a steeper
   vw slope reaches the same size on desktop without breaking small phones. */
.hero-title {
  font-size: clamp(2.15rem, 8.5vw, 4.4rem);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -.04em;
  margin-bottom: 1.25rem;
}
.accent-text { color: var(--accent-text); }

.hero-lead {
  font-size: clamp(1.02rem, 2.2vw, 1.18rem);
  color: var(--text-muted);
  max-width: 38rem;
  margin-bottom: 2rem;
}

.hero-cta { display: flex; flex-wrap: wrap; gap: .75rem; margin-bottom: 2rem; }

.social-list { display: flex; gap: .3rem; margin-left: -.5rem; }

/* About ------------------------------------------------------------------ */
.about-grid {
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: start;
}

.about-text p { color: var(--text-muted); font-size: 1.03rem; }

.fact-list {
  margin: 1.75rem 0 0;
  display: grid;
  gap: .1rem;
}
.fact {
  display: grid;
  grid-template-columns: 6.5rem 1fr;
  gap: 1rem;
  padding: .6rem 0;
  border-top: 1px solid var(--border);
  font-size: .93rem;
}
.fact dt { color: var(--text-faint); font-weight: 500; }
.fact dd { margin: 0; color: var(--text); font-weight: 500; }

/* The quick-facts panel that sits where a portrait would otherwise go. */
.about-panel {
  padding: 1.5rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.about-panel-title {
  font-size: .78rem;
  font-family: var(--font-mono);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: .5rem;
}
.about-panel .fact-list { margin-top: 0; }
.about-panel .fact { grid-template-columns: 1fr; gap: .1rem; }
.about-panel .fact dd { font-weight: 500; }

/* Services ---------------------------------------------------------------- */
.services-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
}

.service-card {
  padding: 1.6rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: border-color .2s var(--ease), transform .2s var(--ease), box-shadow .2s var(--ease);
}
.service-card:hover {
  border-color: var(--border-strong);
  transform: translateY(-3px);
  box-shadow: var(--shadow-md);
}

.service-icon {
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  margin-bottom: 1.1rem;
  border-radius: 12px;
  color: var(--accent-text);
  background: var(--accent-soft);
}
.service-icon svg {
  width: 22px; height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.service-title { font-size: 1.1rem; margin-bottom: .55rem; }
.service-desc  { margin: 0; font-size: .93rem; color: var(--text-muted); }

.services-note {
  margin: 1.75rem 0 0;
  font-size: .93rem;
  color: var(--text-muted);
}

/* Skills ------------------------------------------------------------------
   A logo grid on its own tinted canvas, lit by four soft colour glows.       */
/* The one section that intensifies the field rather than sitting on it: its
   own four glows layer on top of the page ambient, so it reads as the brightest
   moment on the page. Still translucent so the two blend. */
.section-skills {
  position: relative;
  overflow: hidden;
  background: color-mix(in srgb, var(--skills-bg) 72%, transparent);
  border-block: 1px solid var(--border);
}

/* All four glows in one decorative layer, sitting behind the content. */
.section-skills::before {
  content: "";
  position: absolute;
  inset: -10%;
  pointer-events: none;
  background:
    radial-gradient(30rem 24rem at 20% 14%, var(--glow-a), transparent 62%),
    radial-gradient(28rem 22rem at 86% 6%,  var(--glow-b), transparent 62%),
    radial-gradient(32rem 26rem at 6%  66%, var(--glow-c), transparent 62%),
    radial-gradient(28rem 24rem at 74% 84%, var(--glow-d), transparent 62%);
}

.section-skills .container { position: relative; z-index: 1; }

/* Flex-wrap rather than a fixed grid: the tile count changes every time a skill
   is added, and this centres a partial last row instead of leaving one item
   stranded on the left. Each flex-basis is (100% - gaps) / columns, so full
   rows still line up edge to edge. Column gap is 1.25rem throughout. */
.skills-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(2.5rem, 6vw, 4rem) 1.25rem;
}

.skill-item {
  flex: 0 0 calc(50% - .625rem);      /* 2 across */
  display: grid;
  justify-items: center;
  align-content: start;
  gap: .7rem;
  text-align: center;
  transition: transform .22s var(--ease);
}
.skill-item:hover { transform: translateY(-4px); }

.skill-icon {
  width: 56px;
  height: 56px;
  object-fit: contain;
  filter: drop-shadow(0 6px 14px rgba(0, 0, 0, .22));
  transition: transform .22s var(--ease);
}
.skill-item:hover .skill-icon { transform: scale(1.08); }

/* Inlined single-colour logos. The brand colour is set per-icon in the HTML
   and the path picks it up through currentColor. Overrides the shared .icon
   sizing/stroke rules, which are meant for the small UI glyphs. */
.skill-icon-glyph {
  fill: currentColor;
  stroke: none;
  flex: none;
}

.skill-name {
  font-size: 1.02rem;
  font-weight: 700;
  letter-spacing: -.01em;
  line-height: 1.25;
  color: var(--text);
}

.skill-kind {
  font-size: .84rem;
  color: var(--text-muted);
  margin-top: -.35rem;
}

.chips { display: flex; flex-wrap: wrap; gap: .45rem; }
.chips li {
  padding: .32rem .7rem;
  font-size: .85rem;
  font-weight: 500;
  color: var(--text);
  background: var(--bg-alt);
  border: 1px solid var(--border);
  border-radius: 7px;
}
.section-alt .chips li { background: var(--bg); }
.chips-sm li { font-size: .76rem; padding: .22rem .55rem; }

/* Experience & education timeline ---------------------------------------- */
.timeline-columns {
  display: grid;
  gap: clamp(2.5rem, 6vw, 4rem);
}

.timeline-heading {
  font-size: .78rem;
  font-family: var(--font-mono);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 1.5rem;
}

/* The rail is a pseudo-element on the list; each item draws its own dot. */
.timeline {
  position: relative;
  padding-left: 1.75rem;
}
.timeline::before {
  content: "";
  position: absolute;
  left: 5px; top: .55rem; bottom: .55rem;
  width: 2px;
  background: linear-gradient(var(--border), color-mix(in srgb, var(--border) 25%, transparent));
  border-radius: 2px;
}

.timeline-item { position: relative; padding-bottom: 2rem; }
.timeline-item:last-child { padding-bottom: 0; }
.timeline-item::before {
  content: "";
  position: absolute;
  left: -1.75rem; top: .5rem;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--bg-alt);
  border: 2px solid var(--accent);
}

.timeline-date {
  font-family: var(--font-mono);
  font-size: .78rem;
  color: var(--accent-text);
  margin-bottom: .35rem;
}
.timeline-role { font-size: 1.06rem; margin-bottom: .15rem; }
.timeline-org  { font-size: .92rem; color: var(--text-muted); margin-bottom: .6rem; }

.timeline-points { display: grid; gap: .3rem; }
.timeline-points li {
  position: relative;
  padding-left: 1.1rem;
  font-size: .92rem;
  color: var(--text-muted);
}
.timeline-points li::before {
  content: "";
  position: absolute;
  left: 0; top: .62em;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--border-strong);
}

.timeline-note { font-weight: 400; font-size: .88em; color: var(--text-faint); }

/* Certifications ---------------------------------------------------------- */
.cert-heading { margin-top: clamp(2.5rem, 6vw, 3.5rem); }

.cert-grid {
  display: grid;
  gap: .6rem;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

.cert-item {
  display: flex;
  align-items: flex-start;
  gap: .7rem;
  padding: .85rem 1rem;
  font-size: .92rem;
  color: var(--text-muted);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.cert-item .icon {
  margin-top: .12em;
  color: var(--accent-text);
  fill: color-mix(in srgb, var(--accent) 18%, transparent);
}

/* Contact ---------------------------------------------------------------- */
.contact-grid {
  display: grid;
  gap: clamp(1.5rem, 4vw, 2.5rem);
  align-items: start;
}

.contact-direct { display: grid; gap: .6rem; align-content: start; }

.contact-line {
  display: flex;
  align-items: center;
  gap: .9rem;
  padding: 1rem 1.15rem;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: border-color .2s var(--ease), transform .2s var(--ease), box-shadow .2s var(--ease);
}
.contact-line:hover {
  border-color: var(--accent);
  transform: translateX(3px);
  box-shadow: var(--shadow-md);
  text-decoration: none;
}
.contact-line .icon { width: 1.3rem; height: 1.3rem; color: var(--accent-text); }
.contact-line span { display: grid; font-size: .93rem; color: var(--text-muted); line-height: 1.45; }
.contact-line strong { font-size: .8rem; font-weight: 600; color: var(--text-faint); }

.contact-form {
  display: grid;
  gap: 1rem;
  padding: clamp(1.25rem, 3vw, 1.75rem);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.field { display: grid; gap: .4rem; }
.field label { font-size: .86rem; font-weight: 600; color: var(--text); }

.field input,
.field textarea {
  width: 100%;
  padding: .7rem .9rem;
  font: inherit;
  font-size: .95rem;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease);
}
.field textarea { resize: vertical; min-height: 7rem; }
.field input::placeholder, .field textarea::placeholder { color: var(--text-faint); }
.field input:focus, .field textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
/* Only flag invalid fields the user has actually touched (class added by JS). */
.field input.is-invalid, .field textarea.is-invalid {
  border-color: #e5484d;
  box-shadow: 0 0 0 3px color-mix(in srgb, #e5484d 16%, transparent);
}

.form-status { margin: 0; font-size: .88rem; min-height: 1.3em; }
.form-status.is-error   { color: #e5484d; }
.form-status.is-success { color: #17914d; }
:root[data-theme="dark"] .form-status.is-success { color: #4ade80; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .form-status.is-success { color: #4ade80; }
}

/* Footer ----------------------------------------------------------------- */
.site-footer {
  padding-block: 2rem;
  border-top: 1px solid var(--border);
  background: transparent;
}
.footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.footer-note { margin: 0; font-size: .88rem; color: var(--text-faint); }

.back-to-top {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: .88rem;
  font-weight: 500;
  color: var(--text-muted);
}
.back-to-top:hover { color: var(--accent-text); text-decoration: none; }

/* ── 5b. DEVICE MOCKUP ────────────────────────────────────────────────────
   A phone drawn entirely in CSS — no image, so it stays crisp at any size and
   costs nothing to load. The screen is a plain box: drop an <img> inside it
   and the screenshot inherits the rounded corners via overflow:hidden.
   ------------------------------------------------------------------------- */
/* Starts small: the frame is 9:19.5, so every 100px of width costs 217px of
   height. At the old 260px each phone stood 563px tall, and four of them made
   the phone page an endless scroll. Widths step up at the breakpoints below. */
.device {
  --device-w: 200px;
  width: var(--device-w);
  max-width: 100%;
  margin-inline: auto;
}

.device-frame {
  position: relative;
  aspect-ratio: 9 / 19.5;
  padding: 9px;
  border-radius: 13% / 6%;
  background: linear-gradient(160deg, #3a3f4a, #16181d 40%, #23262e);
  box-shadow:
    0 2px 4px rgba(0, 0, 0, .35),
    0 24px 48px -12px rgba(0, 0, 0, .45),
    inset 0 0 0 1px rgba(255, 255, 255, .10);
}

.device-screen {
  position: relative;
  height: 100%;
  overflow: hidden;
  border-radius: 11% / 5.2%;
  background: var(--surface);
  display: grid;
}
.device-screen img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}

/* Dynamic-island pill. Purely decorative, sits above the screen content. */
.device-frame::after {
  content: "";
  position: absolute;
  top: 2.4%;
  left: 50%;
  transform: translateX(-50%);
  width: 31%;
  height: 2.4%;
  min-height: 9px;
  border-radius: 999px;
  background: #0b0c0f;
  z-index: 2;
}

/* ── 5c. PROJECT SHOWCASE ─────────────────────────────────────────────────
   Full-width alternating feature blocks, one per project, in place of the old
   uniform card grid. Each is copy beside a device.
   ------------------------------------------------------------------------- */
.showcase {
  display: grid;
  gap: clamp(2rem, 6vw, 4rem);
  align-items: center;
  padding-block: clamp(2.5rem, 7vw, 5rem);
  border-top: 1px solid var(--border);
}
.showcase:first-of-type { border-top: 0; padding-top: clamp(1rem, 3vw, 2rem); }

.showcase-copy { max-width: 34rem; }

.showcase-eyebrow {
  display: inline-block;
  margin-bottom: .75rem;
  padding: .22rem .6rem;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--accent-text);
  background: var(--accent-soft);
  border-radius: 6px;
}

.showcase-title {
  font-size: clamp(1.9rem, 4.5vw, 2.9rem);
  letter-spacing: -.03em;
  margin-bottom: .85rem;
}

.showcase-desc {
  font-size: 1.05rem;
  color: var(--text-muted);
  margin-bottom: 1.25rem;
}

.showcase-links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.1rem;
  margin-top: 1.25rem;
}
.showcase-links a {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: .92rem;
  font-weight: 600;
}

/* The device column gets its own soft halo so it doesn't float unsupported. */
.showcase-media {
  position: relative;
  display: grid;
  place-items: center;
  padding-block: 1rem;
}
.showcase-media::before {
  content: "";
  position: absolute;
  inset: 8% 0;
  background: radial-gradient(closest-side, var(--glow-c), transparent 72%);
  filter: blur(6px);
  pointer-events: none;
}
.showcase-media > * { position: relative; }

/* ── 6. COMPONENTS ───────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .72rem 1.35rem;
  font: inherit;
  font-size: .95rem;
  font-weight: 600;
  line-height: 1.2;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: transform .16s var(--ease), background-color .18s var(--ease),
              border-color .18s var(--ease), box-shadow .18s var(--ease), color .18s var(--ease);
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn-block { width: 100%; }

.btn-primary {
  color: var(--on-accent);
  background: var(--accent);
  box-shadow: var(--shadow-sm);
}
.btn-primary:hover { background: var(--accent-hover); box-shadow: var(--shadow-md); }

.btn-ghost {
  color: var(--text);
  background: var(--surface);
  border-color: var(--border);
}
.btn-ghost:hover { border-color: var(--border-strong); background: var(--surface-hover); }

/* Scroll-reveal. The .reveal-ready class is added by JS only when an
   IntersectionObserver is actually going to run — so with JS disabled or with
   reduced motion on, content stays visible instead of being stuck at opacity 0. */
.reveal-ready .reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .55s var(--ease), transform .55s var(--ease);
}
.reveal-ready .reveal.is-visible { opacity: 1; transform: none; }

/* Card surfaces sit slightly translucent so the ambient field tints them
   instead of punching opaque holes in it. 88% is high enough that body-text
   contrast is unaffected — the field behind is soft and low-alpha. */
.service-card,
.about-panel,
.contact-form,
.contact-line,
.cert-item {
  background: color-mix(in srgb, var(--surface) 88%, transparent);
}

/* ── 7. RESPONSIVE ───────────────────────────────────────────────────────── */
@media (min-width: 560px) {
  .skill-item { flex-basis: calc(33.3333% - .8334rem); }   /* 3 across */
  .device { --device-w: 250px; }
}

@media (min-width: 720px) {
  .about-grid      { grid-template-columns: 1.4fr 1fr; }
  .timeline-columns { grid-template-columns: 1fr 1fr; }
  .contact-grid    { grid-template-columns: 1fr 1.15fr; }
}

@media (min-width: 860px) {
  .skill-item { flex-basis: calc(25% - .9375rem); }        /* 4 across */

  /* Showcases become two columns and alternate: odd ones put the device on the
     right, even ones on the left, using explicit grid columns so the DOM order
     (copy first) stays correct for screen readers. */
  .showcase { grid-template-columns: 1fr 1fr; }

  .showcase:nth-of-type(even) .showcase-copy  { grid-column: 2; grid-row: 1; }
  .showcase:nth-of-type(even) .showcase-media { grid-column: 1; grid-row: 1; }

  .device { --device-w: 280px; }
}

@media (min-width: 960px) {
  .container { padding-inline: 2rem; }
}

/* Mobile nav: the list becomes a dropdown panel toggled by the hamburger.
   Kicks in below 900px — six nav items plus the wordmark would otherwise
   overflow the header on tablets. Keep in sync with the matching query in
   js/main.js, which closes the panel when the layout goes wide. */
@media (max-width: 899px) {
  .menu-toggle { display: inline-grid; }

  .nav {
    position: absolute;
    top: var(--header-h);
    left: 0;
    width: 100%;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-lg);
    transform-origin: top;
    display: none;
  }
  .nav.is-open { display: block; animation: dropIn .2s var(--ease); }

  .nav-list {
    flex-direction: column;
    align-items: stretch;
    gap: .15rem;
    padding: .75rem 1.25rem 1.15rem;
  }
  .nav-list a { padding: .8rem 1rem; font-size: 1rem; }

  .fact { grid-template-columns: 5.5rem 1fr; }
  .footer-inner { justify-content: center; text-align: center; }
}

/* ── PHONE REFINEMENTS ────────────────────────────────────────────────────
   Below 520px the container is roughly 335px wide, so anything sized for a
   desktop column has to be re-tuned rather than just left to shrink.
   ------------------------------------------------------------------------- */
@media (max-width: 520px) {
  /* Side-by-side buttons wrapped into an awkward ragged pair. Stacking them
     full-width also gives a much bigger tap target. */
  .hero-cta { flex-direction: column; align-items: stretch; }
  .hero-cta .btn { width: 100%; }

  .hero-lead { font-size: 1rem; }
  .hero-stack { font-size: .86rem; }

  /* Two skill tiles per row at ~157px each: the 56px icon and full-size labels
     left names like "App Store Connect" wrapping into three ragged lines. */
  .skills-grid { gap: 2rem 1rem; }
  .skill-icon  { width: 44px; height: 44px; }
  .skill-name  { font-size: .92rem; }
  .skill-kind  { font-size: .76rem; margin-top: -.25rem; }

  /* Tighten the vertical rhythm so the page isn't all whitespace on a phone. */
  .section        { padding-block: 3rem; }
  .showcase       { padding-block: 2rem; gap: 1.75rem; }
  .showcase-desc  { font-size: 1rem; }
  .showcase-media { padding-block: 0; }

  .service-card { padding: 1.25rem; }
  .about-panel  { padding: 1.25rem; }
  .contact-form { padding: 1.15rem; }

  /* Long addresses were the one thing at real risk of pushing the layout wide. */
  .contact-line span { overflow-wrap: anywhere; }
}

/* On the narrowest phones the wordmark crowds the buttons — the monogram carries it. */
@media (max-width: 380px) {
  .brand-name { display: none; }
}

@keyframes dropIn {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}

/* ── 8. MOTION PREFERENCES ───────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .btn:hover, .contact-line:hover, .service-card:hover,
  .skill-item:hover, .skill-item:hover .skill-icon { transform: none; }
}

/* ── PRINT ───────────────────────────────────────────────────────────────── */
@media print {
  .site-header, .hero-cta, .contact-form, .back-to-top, .skip-link { display: none; }
  body::before { display: none; }              /* no ambient wash on paper */
  body { background: #fff; color: #000; }
  .section-alt, .section-skills { background: none; }
  .section { padding-block: 1.5rem; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .8em; color: #555; }
}
