/* ============================================================
   Tokens
   Change these five colours and the whole page follows.
   ============================================================ */

:root {
  --ink:        #17282b;   /* body text */
  --paper:      #f3f5f2;   /* page background */
  --muted:      #5f7378;   /* dates, orgs, secondary text */
  --accent:     #0e6b5e;   /* links only — keep it rare */
  --rule:       #d5dcd8;   /* hairlines and the timeline spine */

  --measure:    64ch;      /* max line length for prose */
  --gutter:     clamp(1.5rem, 5vw, 4rem);

  --font: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system,
          "Segoe UI", Roboto, sans-serif;
}


/* ============================================================
   Base
   ============================================================ */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.0625rem);
  font-weight: 400;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  padding-bottom: 0.05em;
}

a:hover {
  border-bottom-color: var(--accent);
}

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

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

/* Keyboard users get a way past the header. */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--ink);
  color: var(--paper);
  padding: 0.6rem 1rem;
  border: 0;
  z-index: 10;
}

.skip:focus {
  left: 0;
}


/* ============================================================
   Page shell
   ============================================================ */

.page {
  max-width: 56rem;
  margin: 0 auto;
  padding: clamp(3rem, 9vw, 7rem) var(--gutter) 4rem;
}


/* ============================================================
   Masthead

   Scaled back from the resume version. The page is now about the
   projects, so the name introduces them rather than dominating —
   raise the upper clamp value back to 5.25rem to undo this.
   ============================================================ */

.masthead {
  margin-bottom: clamp(2.75rem, 7vw, 4.5rem);
}

.name {
  margin: 0;
  font-size: clamp(2.5rem, 1.5rem + 4.75vw, 4.25rem);
  font-weight: 600;
  line-height: 0.95;
  letter-spacing: -0.035em;
}

.role {
  margin: 0.75rem 0 0;
  max-width: var(--measure);
  font-size: clamp(1.125rem, 1rem + 0.6vw, 1.5rem);
  font-weight: 400;
  color: var(--muted);
  line-height: 1.35;
}

.contact {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.5rem;
  margin-top: 2rem;
  font-size: 0.9375rem;
  color: var(--muted);
}


/* ============================================================
   Sections
   ============================================================ */

.section + .section {
  margin-top: clamp(2.75rem, 6vw, 4.5rem);
}

.section-heading {
  margin: 0 0 1.75rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--rule);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.01em;
}

.lede {
  max-width: var(--measure);
  margin: 0;
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.25rem);
  line-height: 1.55;
}

/* Background — one short paragraph standing in for the full
   employment history that lives on the resume. */
.background {
  max-width: var(--measure);
  margin: 0;
}


/* ============================================================
   Projects

   The main content of the page, so the entries get room and the
   titles get real size. Separation is whitespace rather than
   rules: the hairlines elsewhere each mean something (a section
   boundary, a timeline spine) and adding six more would dilute
   them into decoration.
   ============================================================ */

.projects {
  display: flex;
  flex-direction: column;
}

.project { max-width: var(--measure); }

.project + .project {
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
}

.project-name {
  margin: 0 0 0.5rem;
  font-size: clamp(1.25rem, 1.15rem + 0.45vw, 1.5rem);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.015em;
}

/* Six accent-coloured headings would shout. The title links stay
   in ink and pick up the accent on hover and focus instead. */
.project-name a {
  color: inherit;
  border-bottom-color: var(--rule);
}

.project-name a:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.project-desc { margin: 0; }

/* What it's built on. Metadata, so it sits back. */
.project-stack {
  margin: 0.75rem 0 0;
  font-size: 0.875rem;
  color: var(--muted);
  line-height: 1.5;
}

/* The reason to open the page. Marked with the same tick used in
   the timeline, so it reads as a pointer rather than a caption. */
.project-hook {
  position: relative;
  margin: 0.9rem 0 0;
  padding-left: 1.1rem;
  font-size: 0.9375rem;
  line-height: 1.55;
}

.project-hook::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.7em;
  width: 5px;
  height: 1px;
  background: var(--muted);
}


/* ============================================================
   Timeline — now used by Certifications, and by the project
   detail pages if you want a build log or an incident sequence.

   The date hangs in the left margin on wide screens, against a
   spine. Only use it where the content genuinely is a sequence.
   ============================================================ */

.timeline {
  display: flex;
  flex-direction: column;
  gap: 2.5rem;
}

.entry {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.4rem;
}

.entry-date {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.entry-body { max-width: var(--measure); }

.entry-role {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.3;
}

.entry-org {
  margin: 0.15rem 0 0;
  color: var(--muted);
  font-size: 0.9375rem;
}

.entry-points {
  margin: 0.9rem 0 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.entry-points li {
  position: relative;
  padding-left: 1.1rem;
}

.entry-points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.65em;
  width: 5px;
  height: 1px;
  background: var(--muted);
}

@media (min-width: 46rem) {
  .timeline {
    padding-left: 11rem;
    border-left: 1px solid var(--rule);
  }

  .entry {
    position: relative;
    padding-left: 2rem;
  }

  .entry-date {
    position: absolute;
    left: -11rem;
    top: 0.2rem;
    width: 9rem;
    text-align: right;
  }

  /* The tick where this entry meets the spine. */
  .entry::before {
    content: "";
    position: absolute;
    left: -1px;
    top: 0.75rem;
    width: 1.25rem;
    height: 1px;
    background: var(--rule);
  }
}


/* ============================================================
   Skills
   ============================================================ */

.skills {
  margin: 0;
  display: grid;
  gap: 1rem 2.5rem;
}

.skill-group {
  display: grid;
  gap: 0.15rem;
}

.skills dt {
  font-weight: 600;
  font-size: 0.9375rem;
}

.skills dd {
  margin: 0;
  color: var(--muted);
}

@media (min-width: 46rem) {
  .skill-group {
    grid-template-columns: 9rem 1fr;
    gap: 0 2rem;
  }
}


/* ============================================================
   Footer
   ============================================================ */

.footer {
  margin-top: clamp(4rem, 10vw, 7rem);
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
  font-size: 0.875rem;
  color: var(--muted);
}

.footer p { margin: 0; }


/* ============================================================
   Preferences and print
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  :root {
    --paper: #fff;
    --ink: #000;
    --muted: #444;
    --accent: #000;
  }

  .page { max-width: none; padding: 0; }
  .skip { display: none; }
  .name { font-size: 2.25rem; }
  .section + .section { margin-top: 2rem; }
  .entry { break-inside: avoid; }
  .project { break-inside: avoid; }
  .project + .project { margin-top: 1.5rem; }
  a { border-bottom: none; }
}

/* ============================================================
   PROJECT DETAIL PAGES
   Append this block to the end of styles.css.

   Nothing here overrides the existing rules — it only adds the
   classes the detail pages use. The one new token is a monospace
   stack for code and file trees.
   ============================================================ */

:root {
  --mono: ui-monospace, SFMono-Regular, "SF Mono", "IBM Plex Mono",
          Menlo, Consolas, monospace;
}


/* ============================================================
   Detail page masthead

   Smaller than the landing page — the project title is the
   subject here, not the person's name.
   ============================================================ */

.masthead--project {
  margin-bottom: clamp(2.5rem, 6vw, 4rem);
}

.backlink {
  margin: 0 0 1.75rem;
  font-size: 0.9375rem;
}

.project-title {
  margin: 0;
  font-size: clamp(2rem, 1.4rem + 2.75vw, 3.25rem);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.03em;
}

.project-summary {
  max-width: var(--measure);
  margin: 1rem 0 0;
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.25rem);
  line-height: 1.55;
  color: var(--muted);
}

.meta {
  margin: 1.5rem 0 0;
  font-size: 0.875rem;
  color: var(--muted);
}


/* ============================================================
   Body copy

   Scoped to direct children of a section so it doesn't reach
   into the diagram or the figure caption, which set their own
   spacing.
   ============================================================ */

.prose .section > p {
  max-width: var(--measure);
  margin: 0 0 1.1rem;
}

.prose .section > p:last-child { margin-bottom: 0; }

.sub-heading {
  max-width: var(--measure);
  margin: 2rem 0 0.6rem;
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.35;
}

.sub-heading:first-of-type { margin-top: 0; }

/* A observation pulled out of the narrative. Marked with the
   same tick as the timeline bullets rather than a tinted box. */
.prose .aside {
  position: relative;
  max-width: var(--measure);
  margin: 1.6rem 0 0;
  padding-left: 1.1rem;
  color: var(--muted);
}

.prose .aside::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.7em;
  width: 5px;
  height: 1px;
  background: var(--muted);
}


/* ============================================================
   Code and file trees

   Monospace here is information, not decoration — it preserves
   the alignment the tree depends on.
   ============================================================ */

code {
  font-family: var(--mono);
  font-size: 0.875em;
  overflow-wrap: break-word;
}

.tree,
.code {
  max-width: var(--measure);
  margin: 1.4rem 0;
  padding: 1.1rem 1.25rem;
  background: color-mix(in srgb, var(--ink) 4%, var(--paper));
  border-left: 2px solid var(--rule);
  overflow-x: auto;
  font-size: 0.8125rem;
  line-height: 1.65;
  -webkit-overflow-scrolling: touch;
}

.tree code,
.code code {
  font-size: inherit;
  white-space: pre;
}


/* ============================================================
   Pipeline diagram

   A vertical flow against the same spine the timeline uses. A
   deployment is genuinely a sequence, so the rule is carrying
   information rather than decorating. Built in HTML rather than
   an image so it reflows on a phone, stays selectable, and
   needs no JavaScript.
   ============================================================ */

.figure {
  margin: 1.75rem 0 0;
}

.flow {
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.flow-stage {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.3rem;
}

.flow-where {
  margin: 0;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--muted);
}

.flow-body { max-width: var(--measure); }

.flow-title {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.3;
}

.flow-detail {
  margin: 0.3rem 0 0;
  font-size: 0.9375rem;
  line-height: 1.55;
}

.figcaption {
  margin: 1.5rem 0 0;
  font-size: 0.875rem;
  color: var(--muted);
}

@media (min-width: 46rem) {
  .flow {
    padding-left: 8rem;
    border-left: 1px solid var(--rule);
  }

  .flow-stage {
    position: relative;
    padding-left: 2rem;
  }

  .flow-where {
    position: absolute;
    left: -8rem;
    top: 0.15rem;
    width: 6rem;
    text-align: right;
  }

  /* The tick where this stage meets the spine. */
  .flow-stage::before {
    content: "";
    position: absolute;
    left: -1px;
    top: 0.7rem;
    width: 1.25rem;
    height: 1px;
    background: var(--rule);
  }

  .figcaption { padding-left: 8rem; }
}


/* ============================================================
   Print
   ============================================================ */

@media print {
  .flow-stage { break-inside: avoid; }
  .tree,
  .code {
    break-inside: avoid;
    background: none;
    border-left: 1px solid #999;
  }
}