/* ============================================================
   SECTIONS: internals of each block.

   Every section uses a different layout family, and no two in a
   row share one. Work is an index of rows in two weights, About is
   a reading column over a band of facts, Experience is a stitched timeline,
   Process is a ruled band of four columns, Skills is a two-column
   list, Testimonials is one display quote over an uneven grid, and
   Contact is the single inverted surface. That sequence is the
   rhythm; there is no repeated card doing the work.
   ============================================================ */

/* ── About ─────────────────────────────────────────────────────
   First section after the hero, text only.

   There is not much content here for a 1240 container, and every layout
   that tried to spread it across that width left holes: a column capped
   at its measure with two thirds empty beside it, then a picture brought
   in to cover that, then two columns with the paragraphs floating in the
   top right corner and the space under them dead.

   The fix is structure, not distribution. One statement across the whole
   measure, one rule, then two columns that are sized to finish level
   with each other. Nothing floats and nothing is left over. */
.about__lead {
  font-family: var(--font-display);
  font-weight: 700;
  font-optical-sizing: auto;
  /* One step under the section title, never over it. Its own clamp
     rather than a token: the scale has 40px above and 26px below, and
     this role wants the gap between them. Now: title 52, statement 32,
     body 17, which is three clear steps down. */
  font-size: clamp(1.5rem, 2.4vw, 2rem);
  line-height: 1.16;
  letter-spacing: var(--ls-d3);
  margin-block-start: var(--p-space-6);
  /* Capped so it breaks into two lines rather than running as one long
     line across the whole container. `balance` then evens the two. */
  max-width: 44ch;
  text-wrap: balance;
}
.about__lead em { font-style: normal; color: var(--color-text-accent); white-space: nowrap; }

/* No rule between the statement and the detail. It was tried and taken
   out: the change of scale already divides them, and a line there was a
   second answer to a question the type had already answered. The page
   keeps its fourteen horizontal rules (see LINES, §34). */
.about__detail {
  display: grid;
  gap: var(--space-block-y);
  margin-block-start: var(--space-block-y);
}

.about__prose { display: grid; gap: var(--p-space-5); align-content: start; }
.about__prose p {
  font-size: var(--t-body);
  line-height: var(--lh-body);
  color: var(--color-text-mute);
  /* Capped for the one-column layout, where the column is the whole
     container and the line ran to 79 characters. In two columns the
     track is already narrower than this. */
  max-width: var(--measure);
  text-wrap: pretty;
}

.register { display: grid; gap: var(--p-space-5); align-content: start; }
.register__row { display: grid; gap: var(--p-space-2); }
.register dt {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  font-weight: 700;
  color: var(--color-text);
}
.register__meta { font-size: var(--t-body-sm); color: var(--color-text-mute); }

/* ── Experience, the thread runs the whole timeline ───────────
   The rail is stitched as the section passes through the viewport,
   so the thread advances with the reading rather than on a timer.
   The rail and its markers are the separation; the roles carry no
   rules of their own. */
.timeline {
  position: relative;
  padding-inline-start: var(--p-space-6);
}
/* The rail is always fully drawn, so the shape of the timeline reads
   at a glance. The thread on top of it is what tracks the reading. */
.timeline::before,
.timeline::after {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: var(--p-border-med);
  background-image: repeating-linear-gradient(
    to bottom,
    var(--color-stitch) 0 var(--seam-run),
    transparent var(--seam-run) calc(var(--seam-run) * 2)
  );
}
.timeline::after {
  background-image: repeating-linear-gradient(
    to bottom,
    var(--color-stitch-active) 0 var(--seam-run),
    transparent var(--seam-run) calc(var(--seam-run) * 2)
  );
  transform: scaleY(0);
  transform-origin: top center;
}
@supports (animation-timeline: view()) {
  @keyframes stitch-rail {
    from { transform: scaleY(0); }
    to   { transform: scaleY(1); }
  }
  .timeline::after {
    animation: stitch-rail linear both;
    animation-timeline: view();
    animation-range: cover 15% cover 85%;
  }
}
@media (prefers-reduced-motion: reduce) {
  .timeline::after { animation: none; transform: scaleY(1); }
}

/* Every role is open, and there is nothing to click.

   The accordion is gone on purpose. A work history hides exactly what
   the reader came for, six roles is not an amount worth hiding, and the
   control had nowhere good to sit: pinned to the right edge of a row
   that spanned the whole canvas while its content stopped at a third of
   it, the chevron ended up 794px from the label it belonged to,
   measured at 1440. Removing the control removes the problem rather
   than moving it somewhere less bad.

   The empty right half goes with it: the responsibilities now live
   there instead of underneath. */
.timeline { display: grid; gap: var(--p-space-7); }
.timeline__item { position: relative; }
.timeline__item::before {
  content: "";
  position: absolute;
  inset-block-start: 0.4em;
  inset-inline-start: calc(var(--p-space-6) * -1 - 3px);
  inline-size: var(--stitch-unit);
  block-size: var(--stitch-unit);
  background: var(--color-stitch-active);
}

.role { display: grid; gap: var(--p-space-5); }
.role__head { align-self: start; }

.role__period {
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  letter-spacing: var(--ls-meta);
  color: var(--color-text-mute);
}
.role__company {
  font-family: var(--font-display);
  font-size: var(--t-h4);
  line-height: var(--lh-h4);
  letter-spacing: var(--ls-h4);
  font-weight: 600;
}
.role__title { font-size: var(--t-body-sm); color: var(--color-text-mute); }

.role__body { max-width: var(--measure); }
.role__subhead {
  font-size: var(--t-h5);
  font-weight: 600;
  font-family: var(--font-body);
  margin-block-end: var(--p-space-3);
}
.role__list { display: grid; gap: var(--p-space-2); }
.role__list li {
  position: relative;
  padding-inline-start: var(--p-space-5);
  font-size: var(--t-body-sm);
}
/* The bullet is the module itself. */
.role__list li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0.55em;
  inline-size: var(--stitch-gap);
  block-size: var(--stitch-gap);
  outline: 3px solid var(--color-stitch-active);
}
/* Terms in these three lists run inline, separated by a middle dot.
   Tried and reverted: marking each term with a stitch, and stripping the
   dots to leave only a gap. Client decision, and the comparison lives in
   lab-skills-2.html if it ever comes up again. */
.role__stack {
  margin-block-start: var(--p-space-4);
  font-size: var(--t-body-sm);
  color: var(--color-text-mute);
}

/* ── Process, a ruled band of four columns ─────────────────────
   Hairlines above and below turn the four steps into one band of
   cloth rather than four cards standing next to each other. */
/* No rule above or below. The seams that open and close the section are
   already drawing that boundary, and with a rule of its own there were
   four lines inside 250px: seam, band top, band bottom, seam. The
   vertical hairlines between the columns stay, because four columns
   with no rule between them would run together. */
.process {
  display: grid;
  gap: var(--p-space-7);
  padding-block: var(--p-space-8);
}
.process__step { display: grid; gap: var(--p-space-3); align-content: start; }
.process__title {
  font-size: var(--t-h4);
  line-height: var(--lh-h4);
  letter-spacing: var(--ls-h4);
  font-weight: 600;
}
.process__text { font-size: var(--t-body-sm); color: var(--color-text-mute); }

.stitch-mark { color: var(--color-text); margin-block-end: var(--p-space-2); }
.stitch-mark__fill { fill: var(--color-accent); }

/* ── Skills ────────────────────────────────────────────────────
   Five named skills at display size over a rule, then everything
   else quiet underneath in three columns.

   The old version gave every skill the same weight, so Figma and
   Notion looked equally important and the section only answered
   "what is she good at" to someone who read all six lines. */
.skills__core {
  display: flex;
  flex-wrap: wrap;
  gap: var(--p-space-3) var(--p-space-6);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--t-h4);
  line-height: var(--lh-h4);
  letter-spacing: var(--ls-h4);
  font-optical-sizing: auto;
  padding-block-end: var(--space-block-y);
  margin-block-end: var(--space-block-y);
  border-block-end: var(--p-border-hair) solid var(--color-line);
}
/* One stitch per skill, in thread. The module marks the item rather
   than sitting between two of them as a separator would. */
.skills__core span { position: relative; padding-inline-start: var(--p-space-5); }
.skills__core span::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0.45em;
  inline-size: var(--stitch-unit);
  block-size: var(--stitch-unit);
  background: var(--color-accent);
}

.skills__rest { display: grid; gap: var(--p-space-6); }
.skills__group { display: grid; gap: var(--p-space-2); align-content: start; }
/* The group label carries the page's full text colour at 700, the same
   setting the About register uses. The terms under it are the quiet
   layer, so the label has to come forward or the whole block reads as
   one flat grey field. The two-step contrast is what lets the eye run
   down the labels alone and stop at the group it wants. */
.skills__rest dt {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  /* Already the darkest text value the page owns, and the page does not
     use pure black anywhere. What still made it read as grey is the
     stroke: mono at 12px with 0.10em tracking is thin, so the value that
     looks black in the body face looks washed here. Weight is the lever,
     not another colour. Measured as ink on the label area: 500 is 9%
     more than the 400 it started at, 600 is 13%, 700 is 17%. */
  font-weight: 700;
  color: var(--color-text);
}
/* Quieter than the five above them, which is the whole point. */
.skills__rest dd { font-size: var(--t-body-sm); color: var(--color-text-mute); }

/* ── Testimonials, one display quote, then an uneven grid ───── */
.quote-lead blockquote p {
  font-family: var(--font-display);
  font-size: var(--t-quote);
  line-height: var(--lh-quote);
  letter-spacing: var(--ls-d3);
  font-weight: 500;
  text-wrap: pretty;
  max-width: var(--measure-quote);
}

/* Two blocks of section spacing between the lead quote and the grid,
   and no rule: at that distance a line has nothing left to separate. */
.quote-grid {
  display: grid;
  gap: var(--p-space-8);
  margin-block-start: calc(var(--space-block-y) * 2);
}
.quote blockquote p { max-width: var(--measure-quote); text-wrap: pretty; }

/* ── Contact, the single inverted surface ──────────────────────
   Allowed as a deliberate one-time inversion: it is the finale of
   the composition, it runs edge to edge, and it carries a complete
   parallel token set so contrast holds in both themes. */
.contact {
  background: var(--color-bg-inverse);
  color: var(--color-on-inverse);
  margin-block-start: var(--space-block-y);
  padding-block: var(--space-section-y);
}
/* The surface runs edge to edge; the words stay on the page's width. */
.contact__inner {
  position: relative;
  max-width: calc(var(--grid-max) + var(--pad-l) + var(--pad-r));
  margin-inline: auto;
  padding-inline-start: var(--pad-l);
  padding-inline-end: var(--pad-r);
}
/* The inner box carries its own gutters, so the marker measures from
   the text edge rather than from the bleeding surface edge. */
.contact .mark {
  inset-block-start: 0.5em;
  inset-inline-start: calc(var(--pad-l) - var(--mark-inset));
}

/* The words on the left, the ways to reach her on the right. */
.contact__grid { display: grid; gap: var(--space-block-y); }
.contact__ways { display: grid; gap: var(--p-space-6); align-content: start; }
@media (min-width: 900px) {
  .contact__grid {
    grid-template-columns: 1fr 1fr;
    column-gap: var(--p-space-9);
    align-items: start;
  }
}

.contact__lead {
  font-size: var(--t-lead);
  line-height: var(--lh-lead);
  color: var(--color-on-inverse-mute);
  max-width: 42ch;
  margin-block-start: var(--p-space-5);
}
.contact__label {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--color-on-inverse-mute);
  margin-block-end: var(--p-space-3);
}

.contact__mail {
  position: relative;
  display: inline-block;
  padding-block: var(--p-space-1);
  font-family: var(--font-display);
  font-size: var(--contact-mail-size);
  line-height: var(--lh-d3);
  letter-spacing: var(--ls-d3);
  font-weight: 700;
  font-optical-sizing: auto;
  overflow-wrap: anywhere;
}
/* At the small end of the clamp the line box is only 30px tall. Growing
   the padding would push the stitched underline away from the letters,
   so the hit area is grown separately instead. */
.contact__mail::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block: -8px;
}
.contact__mail::after {
  content: "";
  position: absolute;
  inset-block-end: -0.1em;
  inset-inline-start: 0;
  inline-size: 100%;
  block-size: var(--p-border-med);
  background-image: repeating-linear-gradient(
    to right,
    var(--color-accent) 0 var(--seam-run),
    transparent var(--seam-run) calc(var(--seam-run) * 2)
  );
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--p-dur-3) var(--p-ease-out);
}
.contact__mail:hover::after,
.contact__mail:focus-visible::after { transform: scaleX(1); }

/* Stacked, not in a row: in a column each destination gets its own
   line and its own 44px, and the three stop competing for one line. */
.contact__links {
  font-size: var(--t-body-sm);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.contact__links a {
  display: inline-flex;
  align-items: center;
  gap: var(--p-space-3);
  min-height: var(--tap-min);
  color: var(--color-on-inverse);
  border-block-end: var(--p-border-hair) solid transparent;
  transition: border-color var(--p-dur-1) var(--p-ease-out);
}
.contact__links a:hover { border-block-end-color: var(--color-on-inverse-accent); }

/* The marks sit a step quieter than their label and take the accent
   under the pointer, so the row still reads as one link and not as an
   icon with some text next to it. Sized in em against the mono label,
   so they track it if the label size ever changes. */
.contact__glyph {
  flex: none;
  inline-size: 1.35em;
  block-size: 1.35em;
  fill: currentColor;
  color: var(--color-on-inverse-mute);
  transition: color var(--p-dur-1) var(--p-ease-out);
}
.contact__glyph--stroke { fill: none; }
.contact__links a:hover .contact__glyph,
.contact__links a:focus-visible .contact__glyph { color: var(--color-on-inverse-accent); }
.contact :focus-visible { outline-color: var(--color-on-inverse-accent); }

/* ══ Responsive ═══════════════════════════════════════════════ */

@media (min-width: 768px) {
  .process { grid-template-columns: repeat(2, 1fr); gap: var(--p-space-8); }
  .quote-grid { grid-template-columns: repeat(2, 1fr); column-gap: var(--p-space-9); }
  /* Two columns here, three only from 1024 up. At three on a tablet the
     groups were 188px wide and ran at 14 to 24 characters a line, which
     is a column of fragments rather than a list. */
  .skills__rest {
    grid-template-columns: repeat(2, 1fr);
    column-gap: var(--p-space-8);
  }
}

@media (min-width: 900px) {
  /* Period, company and title on the left, what she did on the right.
     300px holds the longest period line, `Sep 2023 - Dec 2023 (Project
     Work)`, on one line, and what is left still gives the body its full
     measure at 1240. */
  .role {
    grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
    column-gap: clamp(40px, 6vw, 96px);
    align-items: start;
  }
  /* Wider apart once the roles are side by side rather than stacked:
     with no rules between them the gap is the only separation. */
  .timeline { gap: var(--p-space-9); }

  /* Prose left, facts right, and the ratio is chosen so the two finish
     at roughly the same depth: the paragraphs run at their measure, the
     three facts stack in a narrower column and take about the same
     height doing it. */
  .about__detail {
    grid-template-columns: minmax(0, var(--measure)) minmax(280px, 1fr);
    column-gap: var(--p-space-9);
  }
}

@media (min-width: 1024px) {
  /* Four columns stay, the padding does not. A 32px gap plus 32px of
     padding on each side of every column was taking 96px of measure out
     of a 1240 container, which left the text running at 25 to 31
     characters a line over six lines. The hairline still needs air, so
     it keeps half of what it had. */
  .skills__rest { grid-template-columns: repeat(3, 1fr); column-gap: var(--p-space-8); }

  .process { grid-template-columns: repeat(4, 1fr); gap: var(--p-space-5); }
  .process__step { padding-inline-end: var(--p-space-4); }
  .process__step + .process__step {
    border-inline-start: var(--p-border-hair) solid var(--color-line);
    padding-inline-start: var(--p-space-4);
  }
}

@media (max-width: 767px) {
  /* Four steps stacked in a 375px column. The 48px gap and the 64px
     padding were drawn for four columns side by side, where they read
     as breathing room; stacked, they read as four separate screens. */
  .process { gap: var(--p-space-6); padding-block: var(--p-space-6); }
  .process__step + .process__step {
    border-block-start: var(--p-border-hair) solid var(--color-line);
    padding-block-start: var(--p-space-6);
  }
  .quote-grid { gap: var(--p-space-7); }
  .person__avatar { inline-size: var(--avatar-size-sm); block-size: var(--avatar-size-sm); }
  /* Never below 16px body / 14px secondary on phones. */
  body { font-size: 1rem; }
  .register dd,
  .role__list li,
  .process__text,
  .skills__rest dd,
  .quote blockquote p { font-size: 1rem; }
  /* The stack, not the title. A job title outranks the list of tools it
     was done with, and this rule used to take the title down to 14px
     while leaving the stack at 15, so the ladder ran the wrong way on a
     phone and only on a phone. */
  .role__stack,
  .person__role { font-size: 0.875rem; }
}
