/* ==========================================================================
   Leakey Mugendi — portfolio
   Design tokens lifted from the "Justice" direction: near-black serif
   headings, one bronze accent, light/dark section rhythm.
   ========================================================================== */

:root {
  --accent:      #a0876e;
  --accent-deep: #5c544d;
  --body:        #3f4245;
  --ink:         #020404;
  --muted:       #979591;
  --muted-dark:  #b3b0ab;  /* --muted lifted for 4.5:1 on --night */
  --line:        #eaeaec;
  --line-dark:   #2a2e33;
  --surface:     #f4f4f5;
  --paper:       #ffffff;
  --night:       #121519;

  --shell:       1290px;
  --gutter:      clamp(24px, 5vw, 48px);
  --rhythm:      clamp(96px, 12vw, 140px);
  --header-h:    72px;

  --sans:  "Public Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --serif: "Source Serif 4", Georgia, serif;
}

/* ── Base ─────────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--body);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
  margin: 0;
  font-family: var(--serif);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--ink);
}
h4, h5, h6 { font-weight: 700; }

h1 { font-size: clamp(34px, 6.4vw, 64px); }
h2 { font-size: clamp(26px, 4.4vw, 35px); }
h3 { font-size: clamp(19px, 2.2vw, 23px); }
h4 { font-size: clamp(20px, 2.6vw, 25px); }
h5 { font-size: clamp(17px, 1.9vw, 19px); }

p { margin: 0; text-wrap: pretty; }

a {
  color: var(--accent);
  text-decoration: none;
  transition: color 160ms ease;
}
a:hover { color: var(--accent-deep); }

img { display: block; max-width: 100%; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 12px 20px;
  background: var(--paper);
  color: var(--ink);
  font-weight: 600;
}
.skip-link:focus { left: 0; }

/* ── Layout primitives ────────────────────────────────────────────────── */

.shell {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.section {
  padding: var(--rhythm) 0;
  scroll-margin-top: var(--header-h);
}
.section--surface { background: var(--surface); }
/* Set the dark-section body colour on the section so paragraphs INHERIT it.
   A `.section--night p` rule would out-specify the .eyebrow--* modifiers and
   silently grey out every bronze eyebrow in here. */
.section--night   { background: var(--night); color: var(--muted-dark); }
.section--night h2, .section--night h4 { color: #ffffff; }
.section--footer   { padding-bottom: 56px; }

.stack {
  display: flex;
  flex-direction: column;
  gap: clamp(28px, 3vw, 40px);
}
.stack--mid     { gap: clamp(40px, 5vw, 56px); }
.stack--writing { gap: clamp(40px, 5vw, 64px); }
.stack--wide    { gap: clamp(48px, 6vw, 72px); }

.section-head {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.section-head__lede { max-width: 56ch; }

.eyebrow {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.eyebrow--sm     { font-size: 11px; }  /* project tags, article datelines */
.eyebrow--accent { color: var(--accent); }
.eyebrow--muted  { color: var(--muted); }
.section--night .eyebrow--muted { color: var(--muted-dark); }

/* The signature device: a bronze rule that draws itself on section entry. */
.rule {
  height: 1px;
  width: 64px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 700ms cubic-bezier(.2, .7, .3, 1);
}
.rule.is-shown { transform: scaleX(1); }

/* ── Buttons ──────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 52px;
  padding: 0 30px;
  border: 1px solid transparent;
  border-radius: 100px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: background 160ms ease, color 160ms ease, border-color 160ms ease;
}
.btn--sm { height: 44px; padding: 0 22px; font-size: 14px; }

.btn--primary { background: var(--accent); color: #ffffff; }
.btn--primary:hover { background: var(--accent-deep); color: #ffffff; }

.btn--ghost-light {
  border-color: rgba(255, 255, 255, 0.35);
  color: #ffffff;
}
.btn--ghost-light:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: #ffffff;
}

.btn--ghost {
  height: 48px;
  padding: 0 26px;
  background: transparent;
  border-color: var(--accent);
  color: var(--accent);
  font-size: 14px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.btn--ghost:hover { background: var(--accent); color: #ffffff; }

/* ── Header ───────────────────────────────────────────────────────────── */

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background 240ms ease, border-color 240ms ease;
}
.site-header__inner {
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.logo {
  font-family: var(--serif);
  font-size: 20px;
  font-weight: 600;
  color: #ffffff;
  transition: color 240ms ease;
}
.logo:hover { color: #ffffff; }

.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(16px, 2.4vw, 32px);
}
.site-nav__links { display: none; }
.site-nav__links a {
  font-size: 14px;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.82);
  transition: color 240ms ease;
}
.site-nav__links a:hover { color: #ffffff; }

/* Solid state, set by main.js once the page scrolls off the hero. */
.site-header.is-solid {
  background: var(--paper);
  border-bottom-color: var(--line);
}
.site-header.is-solid .logo { color: var(--ink); }
.site-header.is-solid .site-nav__links a { color: var(--body); }
.site-header.is-solid .site-nav__links a:hover { color: var(--accent); }

@media (min-width: 860px) {
  .site-nav__links {
    display: flex;
    align-items: center;
    gap: clamp(16px, 2.4vw, 32px);
  }
}

/* ── Hero ─────────────────────────────────────────────────────────────── */

.hero {
  padding: calc(var(--header-h) + clamp(72px, 10vw, 120px)) 0 var(--rhythm);
  background: radial-gradient(120% 100% at 18% 12%, #4b4640 0%, #3a3630 45%, #2b2823 100%);
  scroll-margin-top: var(--header-h);
}
.hero__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(36px, 5vw, 72px);
  align-items: start;
}
.hero__aside {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 24px;
}
.hero__main {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 28px;
}

.avatar {
  width: 180px;
  height: 180px;
  flex: none;
  border-radius: 50%;
  overflow: hidden;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.18);
}
.avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0%;
}

.hero__role {
  font-size: clamp(17px, 1.9vw, 20px);
  font-weight: 600;
  color: #e6e1d9;
}
.hero__availability { color: var(--muted-dark); max-width: 44ch; }
.hero h1 { color: #ffffff; max-width: 18ch; }
.hero__lede {
  font-size: clamp(17px, 2.2vw, 20px);
  max-width: 52ch;
  color: #cfc9c0;
}
.hero__cta { display: flex; flex-wrap: wrap; gap: 14px; }

/* The two pills need 312px side by side at the default 30px padding, which is
   a hair more than a 360px phone leaves once the 24px gutters come off — so
   they wrapped onto two rows despite visibly having room for one. Trimming the
   side padding keeps them on a single line down to 320px; nowrap means that if
   a row genuinely can't fit, the second pill wraps whole rather than breaking
   its label across two lines. */
.hero__cta .btn { white-space: nowrap; }
@media (max-width: 400px) {
  .hero__cta { gap: 12px; }
  .hero__cta .btn { padding: 0 16px; }
}

@media (min-width: 900px) {
  .hero__grid { grid-template-columns: minmax(220px, 300px) 1fr; }
  .hero__aside { align-items: flex-start; text-align: left; }
}

/* ── Project list ─────────────────────────────────────────────────────── */

.project-list { display: contents; }

.project {
  display: grid;
  grid-template-columns: 96px 1fr;
  column-gap: 14px;
  row-gap: 8px;
  align-items: start;
  padding: clamp(22px, 2.6vw, 30px) 0;
  border-top: 1px solid var(--line);
}
.project[hidden] { display: none; }

.project__thumb {
  grid-column: 1;
  grid-row: 1;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  background: var(--paper);
}
.project__head {
  grid-column: 2;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.project__body {
  grid-column: 1 / -1;
  grid-row: 2;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.project__title-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
}
.project__link {
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
}
.project__body p { font-size: 15px; line-height: 1.55; }

/* From 700px the copy moves up beside the thumbnail. */
@media (min-width: 700px) {
  .project {
    grid-template-columns: clamp(104px, 12vw, 152px) 1fr;
    column-gap: clamp(18px, 2.4vw, 30px);
  }
  .project__thumb { grid-row: 1 / 3; }
  .project__body  { grid-column: 2; }
}

.more-row {
  order: 99;
  display: flex;
  justify-content: flex-start;
  border-top: 1px solid var(--line);
  padding-top: clamp(22px, 2.6vw, 30px);
}
.more-row[hidden] { display: none; }

/* ── Roles ────────────────────────────────────────────────────────────── */

/* Two columns on desktop, so five roles read as 3+2 rather than an
   unbalanced 3-up row. Single column on mobile. */
.role-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(28px, 3.5vw, 56px);
}
@media (min-width: 760px) {
  .role-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.role {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.role p:last-child { max-width: 52ch; }

/* ── Writing ──────────────────────────────────────────────────────────── */

.article-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  max-width: 940px;
}
.article {
  display: grid;
  grid-template-columns: 96px 1fr;
  gap: 16px;
  align-items: center;
  padding: 16px 0;
  border-top: 1px solid var(--line);
  color: var(--body);
  transition: transform 200ms ease, border-color 200ms ease;
}
.article:hover { color: var(--body); }
.article__cover {
  aspect-ratio: 1 / 1;
  border-radius: 4px;
  overflow: hidden;
  background: var(--surface);
}
.article__text {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.article__desc {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 14px;
  line-height: 1.5;
}

/* Collapsed, the grid shows four cards on mobile and two full rows (six) on
   desktop; the rest are revealed by the "View more articles" button. The cut
   is done in CSS so it follows the breakpoint without a resize listener. */
.article-grid.is-collapsed .article:nth-child(n + 5) { display: none; }

@media (min-width: 1024px) {
  .article-grid.is-collapsed .article:nth-child(n + 5) { display: flex; }
  .article-grid.is-collapsed .article:nth-child(n + 7) { display: none; }

  .article-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
    max-width: none;
  }
  .article {
    display: flex;
    flex-direction: column;
    /* The mobile rule centres its two columns; a column card must stretch
       instead, or the cover collapses to the width of its placeholder. */
    align-items: stretch;
    gap: 0;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 8px;
    overflow: hidden;
    background: var(--paper);
  }
  .article:hover {
    transform: translateY(-3px);
    border-color: var(--accent);
  }
  .article__cover { aspect-ratio: 16 / 9; border-radius: 0; }
  .article__text  { padding: 16px 18px 18px; }
}

/* ── Image slots ──────────────────────────────────────────────────────── */

/* Empty slot: a quiet placeholder rather than a broken-image icon. */
.slot {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  padding: 8px;
  background: var(--surface);
  color: var(--muted);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: center;
}
.slot img { width: 100%; height: 100%; object-fit: cover; }

/* ── Education timeline ───────────────────────────────────────────────── */

.timeline {
  display: flex;
  flex-direction: column;
  gap: 44px;
  max-width: 760px;
  padding-left: clamp(20px, 3vw, 36px);
  border-left: 1px solid var(--accent);
}
.timeline__item {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* The design sets these degree headings in serif caps. Source text keeps its
   real casing ("BSc") so copy/paste and screen readers get it right. */
.timeline__item h4 { text-transform: uppercase; }
.timeline__org {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--accent);
}

/* ── Contact ──────────────────────────────────────────────────────────── */

/* Every tile shares one track size, the email included. The minimum is set by
   that tile: icon, full address and the Copy button on a single line. */
.contact-grid {
  display: grid;
  /* min() so the 368px floor can't push the track wider than the screen. */
  grid-template-columns: repeat(auto-fit, minmax(min(368px, 100%), 1fr));
  gap: 16px;
}
/* Equal rows once the grid has more than one column, so neither tile can end up
   shorter than its neighbour. Left off in the single-column layout, where it would
   only pad the short email tile out to the height of the taller social group.
   Two 368px tracks plus the gap need a 752px container, which — once the two
   clamp(24px, 5vw, 48px) gutters are taken off — lands near an 840px viewport;
   860px keeps the switch safely inside two-column territory. */
@media (min-width: 860px) {
  .contact-grid { grid-auto-rows: 1fr; }
}
.contact-tile {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 44px;
  padding: 20px 22px;
  border: 1px solid var(--line-dark);
  border-radius: 8px;
  transition: border-color 200ms ease;
}
.contact-tile:hover { border-color: var(--accent); }
/* Only Copy is pushed out to the far edge; the icon stays beside the address. */
.contact-tile--email .copy-btn { margin-left: auto; }
.contact-tile--email:hover { border-color: var(--line-dark); }
.contact-tile__text {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.contact-tile__text a {
  color: #ffffff;
  font-size: 15px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
}
.contact-tile__text a:hover { color: var(--accent); }
/* On narrow screens the icon, address and Copy button no longer fit one line,
   so Copy drops below the address rather than squeezing it into an ellipsis. */
@media (max-width: 559px) {
  .contact-tile--email {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    column-gap: 14px;
    row-gap: 14px;
  }
  .contact-tile--email .brand-icon { grid-row: 1; }
  .contact-tile--email .contact-tile__text,
  .contact-tile--email .copy-btn { grid-column: 2; }
}
.contact-tile__value { color: #ffffff; font-size: 15px; font-weight: 500; }

/* The group itself is not a link — only the marks inside it are — so the bronze
   border-hover every other tile carries is switched back off here, the same way
   the email tile does it. */
.contact-tile--social {
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 16px;
}
.contact-tile--social:hover { border-color: var(--line-dark); }

.social-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
/* 44px so the ring is a real touch target, not just a decoration round a 24px
   glyph. Border-colour is the only transition, which keeps the reduced-motion
   block above from having anything to undo. */
.social-link {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--line-dark);
  border-radius: 50%;
  transition: border-color 200ms ease;
}
.social-link:hover { border-color: var(--accent); }

/* Brand marks, each in its own colour. They sit at a fixed size so the tiles
   line up whatever the glyph's own proportions are. */
.brand-icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
}
.brand-icon svg {
  width: 100%;
  height: 100%;
  fill: currentColor;
}
.brand-icon--gmail    { color: #ea4335; }
.brand-icon--whatsapp { color: #25d366; }
.brand-icon--telegram { color: #29a9eb; }
/* The X glyph fills its viewBox edge to edge; the others carry their own
   padding, so it needs trimming to read as the same size. */
.brand-icon--x        { color: #ffffff; }
.brand-icon--x svg    { width: 82%; height: 82%; }
.brand-icon--linkedin { color: #0a66c2; }

.copy-btn {
  flex: none;
  height: 36px;
  padding: 0 14px;
  border: 1px solid var(--accent);
  border-radius: 100px;
  background: transparent;
  color: var(--accent);
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 160ms ease, color 160ms ease;
}
.copy-btn:hover { background: var(--accent); color: #ffffff; }

.colophon {
  padding-top: 28px;
  border-top: 1px solid var(--line-dark);
  text-align: center;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-dark);
}

/* ── Scroll reveal ────────────────────────────────────────────────────── */

/* Only hide when JS is running, so a no-JS page still reads. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 420ms ease, transform 420ms cubic-bezier(.2, .7, .3, 1);
}
.js [data-reveal].is-shown {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
  }
  .js [data-reveal] { opacity: 1; transform: none; }
  .rule { transform: scaleX(1); }
}
