/* ============================================================
   PLATES — composition for each sheet.
   ============================================================ */

/* ============================================================
   SHEET 01 — HERO
   ============================================================ */

.hero {
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, 0.98fr);
  gap: clamp(var(--s-6), 5vw, var(--s-9));
  align-items: center;
  width: 100%;
}

.hero__lead {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-5);
}

.hero__name {
  font-size: var(--t-h1);
  color: var(--chalk);
  /* Two lines by design — the surname carries more weight than
     the given name at this scale, so it gets the accent. */
}

.hero__name span {
  display: block;
}

.hero__name .hero__surname {
  color: transparent;
  -webkit-text-stroke: 1.3px var(--slate-600);
}

.hero__role {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  color: var(--cyanotype);
}

.hero__role::after {
  content: "";
  width: clamp(24px, 6vw, 64px);
  height: var(--hair);
  background: var(--cyanotype-dim);
}

.hero__tagline {
  font-size: var(--t-body-lg);
  line-height: 1.5;
  color: var(--chalk-dim);
  max-width: 34ch;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
}

.hero__stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
  gap: var(--s-5) var(--s-4);
  width: 100%;
  margin-top: var(--s-4);
  padding-top: var(--s-5);
  border-top: var(--hair) solid var(--vellum-line);
}

/* ---- The exploded axonometric ------------------------------
   The signature element. A layered assembly seen in
   axonometric projection: drag to orbit, and it re-assembles
   into a single object as you scroll past.

   --ox / --oz  orbit, written by JS (degrees)
   --sep        layer separation in px, 0 = fully assembled
   --i          layer index, set per layer inline
   ------------------------------------------------------------ */

.axono {
  --ox: 58deg;
  --oz: -34deg;
  --sep: 58px;
  position: relative;
  display: grid;
  place-items: center;
  min-height: clamp(320px, 46vh, 480px);
  /* pan-y, not none: a vertical swipe must still scroll the page.
     Horizontal drag orbits, vertical drag scrolls. Locking both
     axes here would trap the finger on mobile, where the assembly
     is the first thing on screen. */
  touch-action: pan-y;
  cursor: grab;
}

.axono:active { cursor: grabbing; }

.axono__stage {
  position: relative;
  width: clamp(180px, 22vw, 240px);
  aspect-ratio: 1;
  transform-style: preserve-3d;
  transform: rotateX(var(--ox)) rotateZ(var(--oz));
}

.axono__layer {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transform: translateZ(calc(var(--i) * var(--sep)));
  transition: transform var(--dur-slow) var(--ease-out);
}

/* JS drives orbit and separation every frame while dragging, so
   transitions are suppressed to avoid fighting the input. */
.axono.is-dragging .axono__layer,
.axono.is-scrolling .axono__layer {
  transition: none;
}

.axono__plane {
  position: absolute;
  inset: 0;
  border: var(--hair) solid var(--vellum-line-strong);
  border-radius: var(--radius-sm);
  background-color: rgba(26, 29, 37, 0.72);
  background-image: repeating-linear-gradient(45deg,
    var(--vellum-line) 0 var(--hair),
    transparent var(--hair) 8px);
  box-shadow: var(--lift-2);
  /* Deliberately no backdrop-filter here. On several engines a
     filter on a child of a preserve-3d subtree forces the whole
     subtree flat, which would collapse the entire assembly. */
}

/* One layer is marked as the strongest. It gets the accent, and
   because only one does, that reads as a claim rather than
   decoration. */
.axono__layer--accent .axono__plane {
  border-color: var(--cyanotype);
  background-color: rgba(76, 125, 255, 0.13);
  background-image: repeating-linear-gradient(45deg,
    rgba(122, 160, 255, 0.28) 0 var(--hair),
    transparent var(--hair) 8px);
  box-shadow: 0 0 32px -6px var(--cyanotype-glow), var(--lift-2);
}

/* Corner registration notch on every plane. */
.axono__plane::after {
  content: "";
  position: absolute;
  top: 6px;
  left: 6px;
  width: 12px;
  height: 12px;
  border-top: var(--hair) solid var(--cyanotype);
  border-left: var(--hair) solid var(--cyanotype);
  opacity: 0.7;
}

/* Parts callout: a leader line out to a counter-rotated label,
   so text stays upright however the assembly is orbited. */
.axono__callout {
  position: absolute;
  top: 50%;
  left: 100%;
  display: flex;
  align-items: center;
  gap: var(--s-2);
  transform: translateY(-50%);
  transform-style: preserve-3d;
  white-space: nowrap;
}

.axono__leader {
  width: clamp(18px, 3vw, 34px);
  height: var(--hair);
  background: var(--vellum-line-strong);
  flex: none;
}

.axono__layer--accent .axono__leader { background: var(--cyanotype); }

/* Undo the stage rotation so the label faces the reader. */
.axono__tag {
  display: flex;
  flex-direction: column;
  gap: 1px;
  transform: rotateZ(calc(var(--oz) * -1)) rotateX(calc(var(--ox) * -1));
  transform-origin: left center;
}

.axono__tag-label {
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--chalk);
}

.axono__layer--accent .axono__tag-label { color: var(--cyanotype-bright); }

.axono__tag-caption {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  color: var(--slate-600);
}

/* Graph-paper groundplane. Gives the assembly something to sit
   on, which is what makes the projection legible as 3D. */
.axono__ground {
  position: absolute;
  inset: -34%;
  transform: translateZ(-46px);
  border: var(--hair) solid var(--vellum-line);
  background-image:
    linear-gradient(var(--vellum-line) var(--hair), transparent var(--hair)),
    linear-gradient(90deg, var(--vellum-line) var(--hair), transparent var(--hair));
  background-size: 22px 22px;
  opacity: 0.5;
  -webkit-mask-image: radial-gradient(circle at 50% 50%, #000 28%, transparent 74%);
  mask-image: radial-gradient(circle at 50% 50%, #000 28%, transparent 74%);
}

.axono__hint {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--s-2);
  color: var(--slate-700);
  transition: opacity var(--dur) var(--ease-out);
}

.axono.is-touched .axono__hint { opacity: 0; }

/* ============================================================
   SHEET 02 — PROFILE
   ============================================================ */

.profile {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: clamp(var(--s-6), 5vw, var(--s-8));
  align-items: start;
}

.profile__aside {
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
  padding: var(--s-5);
}

.profile__row {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding-bottom: var(--s-4);
  border-bottom: var(--hair) solid var(--vellum-line);
}

.profile__row:last-child {
  padding-bottom: 0;
  border-bottom: none;
}

.profile__key { color: var(--slate-700); }

.profile__val {
  color: var(--chalk);
  font-size: var(--t-small);
}

/* ============================================================
   SHEET 03 — TIMELINE
   Drawn as a dimension line: a continuous vertical run with
   arrow terminators, witness ticks at each event, and extension
   lines out to the entry cards.
   ============================================================ */

.timeline {
  position: relative;
  --tl-gutter: 116px;
  --tl-track: 26px;
}

/* The dimension line itself. */
.timeline__run {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: calc(var(--tl-gutter) + var(--tl-track) / 2);
  width: var(--hair);
  background: linear-gradient(180deg,
    var(--cyanotype-dim) 0%,
    var(--graphite-600) 55%,
    var(--graphite-600) 100%);
}

/* Arrow terminators, top and bottom — the detail that makes it
   read as a dimension rather than a decorative rule. */
.timeline__run::before,
.timeline__run::after {
  content: "";
  position: absolute;
  left: 50%;
  width: 0;
  height: 0;
  border-left: 3.5px solid transparent;
  border-right: 3.5px solid transparent;
  transform: translateX(-50%);
}

.timeline__run::before {
  top: -1px;
  border-bottom: 6px solid var(--cyanotype);
}

.timeline__run::after {
  bottom: -1px;
  border-top: 6px solid var(--graphite-600);
}

.timeline__entry {
  position: relative;
  display: grid;
  grid-template-columns: var(--tl-gutter) var(--tl-track) minmax(0, 1fr);
  align-items: start;
  padding-bottom: var(--s-6);
}

.timeline__entry:last-child { padding-bottom: 0; }

.timeline__date {
  padding-top: 14px;
  text-align: right;
  color: var(--slate-500);
  white-space: nowrap;
}

.timeline__date b {
  display: block;
  color: var(--chalk);
  font-weight: 500;
}

/* Witness tick + extension line out to the card. */
.timeline__mark {
  position: relative;
  height: 100%;
  padding-top: 18px;
  display: flex;
  justify-content: center;
}

.timeline__tick {
  position: relative;
  z-index: 2;
  width: 9px;
  height: 9px;
  background: var(--graphite-900);
  border: var(--hair) solid var(--slate-600);
  flex: none;
  transition: border-color var(--dur) var(--ease-out),
              background var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-spring);
}

/* Marker shape encodes the kind of event: square for education,
   diamond for a role, filled circle for a one-off milestone. */
.timeline__entry[data-kind="education"] .timeline__tick {
  border-radius: var(--radius-sm);
}

.timeline__entry[data-kind="work"] .timeline__tick {
  transform: rotate(45deg);
}

.timeline__entry[data-kind="milestone"] .timeline__tick {
  border-radius: 50%;
  background: var(--oxide);
  border-color: var(--oxide-bright);
}

.timeline__entry:hover .timeline__tick {
  border-color: var(--cyanotype);
  background: var(--cyanotype);
}

.timeline__entry[data-kind="work"]:hover .timeline__tick {
  transform: rotate(45deg) scale(1.18);
}

/* Extension line from the tick to the card edge. */
.timeline__mark::after {
  content: "";
  position: absolute;
  top: 22px;
  left: 50%;
  width: 100%;
  height: var(--hair);
  background: var(--vellum-line);
}

.timeline__card {
  padding: var(--s-5);
  transform-style: preserve-3d;
  transition: transform var(--dur-slow) var(--ease-out),
              border-color var(--dur) var(--ease-out);
}

.timeline__entry:hover .timeline__card {
  border-color: var(--vellum-line-strong);
  transform: translateX(4px);
}

.timeline__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  margin-bottom: var(--s-2);
}

.timeline__title {
  font-family: var(--font-display);
  font-variation-settings: "wdth" 108, "wght" 700;
  font-size: var(--t-h4);
  text-transform: uppercase;
  letter-spacing: var(--track-display);
  color: var(--chalk);
  line-height: var(--lh-snug);
}

.timeline__org {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin-bottom: var(--s-3);
  color: var(--cyanotype);
}

.timeline__loc { color: var(--slate-700); }

.timeline__summary {
  color: var(--chalk-dim);
  font-size: var(--t-small);
  line-height: 1.6;
}

.timeline__highlights {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  margin-top: var(--s-4);
}

.timeline__highlight {
  display: flex;
  gap: var(--s-3);
  color: var(--slate-500);
  font-size: var(--t-small);
  line-height: 1.5;
}

/* Leader dash instead of a bullet — stays inside the drawing
   vernacular rather than importing a generic list glyph. */
.timeline__highlight::before {
  content: "";
  flex: none;
  width: 10px;
  height: var(--hair);
  margin-top: 0.72em;
  background: var(--cyanotype-dim);
}

.timeline__tags { margin-top: var(--s-4); }

/* ============================================================
   SHEET 04 — PROJECTS
   ============================================================ */

.projects {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: var(--s-5);
}

.projects__item.is-hidden { display: none; }

.card--project { height: 100%; }

.card__metrics {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-5);
  margin-top: var(--s-2);
}

.card__links {
  display: flex;
  gap: var(--s-4);
}

@media (min-width: 880px) {
  .projects__item--featured { grid-column: span 2; }

  /* A featured card puts the plate beside the copy instead of
     above it, so the extra width buys layout rather than just
     stretching the same card. */
  .projects__item--featured .card__inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
    grid-template-rows: 1fr auto;
  }

  .projects__item--featured .plate {
    grid-row: 1 / 3;
    aspect-ratio: auto;
    height: 100%;
    border-bottom: none;
    border-right: var(--hair) solid var(--vellum-line);
  }
}

/* ============================================================
   SHEET 05 — HACKATHONS
   The interesting axis is the result and the constraint, so the
   layout leads with placement and time, not with the tech.
   ============================================================ */

.hacks {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

.hack {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr) 160px;
  gap: var(--s-5);
  align-items: start;
  padding: var(--s-5);
  position: relative;
  overflow: hidden;
  transition: border-color var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-out);
}

.hack:hover {
  border-color: var(--vellum-line-strong);
  transform: translateX(3px);
}

/* Cyanotype wash sweeps in from the left on hover. */
.hack::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, var(--cyanotype-wash), transparent 46%);
  opacity: 0;
  transition: opacity var(--dur) var(--ease-out);
  pointer-events: none;
}

.hack:hover::before { opacity: 1; }

/* The wash is absolutely positioned, so it would otherwise paint
   over the in-flow text. Lifting the real content above it keeps
   the copy crisp. */
.hack > * {
  position: relative;
  z-index: 1;
}

.hack__rank {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.hack__place {
  font-family: var(--font-display);
  font-variation-settings: "wdth" 112, "wght" 800;
  font-size: var(--t-h3);
  line-height: 0.95;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  color: var(--chalk);
}

/* A podium finish earns the accent. Everything else stays quiet,
   which is what makes the accent mean something. */
.hack--podium .hack__place { color: var(--cyanotype-bright); }

.hack--entry .hack__place {
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  letter-spacing: var(--track-mono);
  color: var(--slate-600);
  font-variation-settings: normal;
}

.hack__name {
  font-family: var(--font-display);
  font-variation-settings: "wdth" 106, "wght" 700;
  font-size: var(--t-h4);
  text-transform: uppercase;
  letter-spacing: var(--track-display);
  color: var(--chalk);
  margin-bottom: var(--s-2);
}

.hack__project {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-bottom: var(--s-3);
  color: var(--cyanotype);
}

.hack__summary {
  color: var(--chalk-dim);
  font-size: var(--t-small);
  line-height: 1.6;
  margin-bottom: var(--s-4);
}

.hack__meta {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  position: relative;
}

.hack__meta-row {
  display: flex;
  justify-content: space-between;
  gap: var(--s-3);
  padding-bottom: var(--s-2);
  border-bottom: var(--hair) solid var(--vellum-line);
}

.hack__meta-key { color: var(--slate-700); }
.hack__meta-val { color: var(--chalk); }

.hack__links {
  display: flex;
  gap: var(--s-4);
  margin-top: var(--s-2);
}

/* ============================================================
   SHEET 06 — CERTIFICATES
   Horizontal track in perspective. JS writes --t per card (its
   signed distance from the viewport centre, roughly -1..1) and
   the transform is derived from that, so the depth follows the
   scroll instead of being a fixed decoration.
   ============================================================ */

.certs {
  position: relative;
  margin: 0 calc(var(--sheet-pad-x) * -1);
  padding: var(--s-5) 0 var(--s-6);
  perspective: 1400px;
}

.certs__track {
  display: flex;
  gap: var(--s-5);
  padding: 0 var(--sheet-pad-x);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  transform-style: preserve-3d;
  scrollbar-width: none;
  cursor: grab;
}

.certs__track::-webkit-scrollbar { display: none; }

.cert {
  --t: 0;
  flex: 0 0 clamp(240px, 27vw, 310px);
  scroll-snap-align: center;
  transform-style: preserve-3d;
  transform:
    rotateY(calc(var(--t) * -21deg))
    translateZ(calc(var(--t) * var(--t) * -84px))
    scale(calc(1 - (var(--t) * var(--t)) * 0.07));
  transition: transform 120ms linear, border-color var(--dur) var(--ease-out);
}

.cert:hover { border-color: var(--vellum-line-strong); }

.cert__inner {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  height: 100%;
  padding: var(--s-5);
}

.cert__seal {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  margin-bottom: var(--s-2);
  border: var(--hair) solid var(--cyanotype-dim);
  border-radius: 50%;
  color: var(--cyanotype);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0;
}

.cert__title {
  font-size: var(--t-h4);
  font-family: var(--font-display);
  font-variation-settings: "wdth" 104, "wght" 700;
  text-transform: uppercase;
  letter-spacing: var(--track-display);
  line-height: var(--lh-snug);
  color: var(--chalk);
}

.cert__issuer { color: var(--cyanotype); }

.cert__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  margin-top: auto;
  padding-top: var(--s-4);
  border-top: var(--hair) solid var(--vellum-line);
}

.cert__id {
  color: var(--slate-700);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.certs__rail {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  padding: 0 var(--sheet-pad-x);
  margin-top: var(--s-4);
}

.certs__hint { color: var(--slate-700); }

.certs__arrows {
  display: flex;
  gap: var(--s-2);
  margin-left: auto;
}

.certs__arrow {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  color: var(--slate-500);
  border: var(--hair) solid var(--vellum-line);
  border-radius: var(--radius-sm);
  transition: color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

.certs__arrow:hover {
  color: var(--cyanotype);
  border-color: var(--cyanotype);
}

/* ============================================================
   SHEET 07 — SKILLS
   ============================================================ */

.skills {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(248px, 1fr));
  gap: var(--s-5);
}

.skillgroup { padding: var(--s-5); }

.skillgroup__name {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding-bottom: var(--s-4);
  margin-bottom: var(--s-4);
  border-bottom: var(--hair) solid var(--vellum-line);
  color: var(--chalk);
}

.skillgroup__name::after {
  content: "";
  flex: 1;
  height: var(--hair);
  background: var(--vellum-line);
}

.skill {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-2) 0;
  cursor: default;
}

.skill__name {
  font-size: var(--t-small);
  color: var(--chalk-dim);
  transition: color var(--dur-fast) var(--ease-out);
}

.skill:hover .skill__name { color: var(--chalk); }

/* Five ticks rather than a percentage bar: a bar implies a
   precision nobody actually has about their own skill level. */
.skill__level {
  display: flex;
  gap: 3px;
  flex: none;
}

.skill__tick {
  width: 14px;
  height: 3px;
  background: var(--graphite-600);
  border-radius: 1px;
  transition: background var(--dur) var(--ease-out);
}

.skill__tick.is-on { background: var(--cyanotype-dim); }
.skill:hover .skill__tick.is-on { background: var(--cyanotype); }

.skill__note {
  color: var(--slate-700);
  font-size: var(--t-micro);
}

/* ============================================================
   SHEET 08 — CONTACT
   ============================================================ */

.contact {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: clamp(var(--s-6), 5vw, var(--s-8));
  align-items: start;
}

.contact__email {
  display: inline-block;
  font-family: var(--font-display);
  font-variation-settings: "wdth" 108, "wght" 700;
  font-size: clamp(1.5rem, 1rem + 2.4vw, 2.75rem);
  letter-spacing: var(--track-display);
  text-transform: none;
  color: var(--chalk);
  line-height: var(--lh-snug);
  word-break: break-word;
  background-image: linear-gradient(var(--cyanotype), var(--cyanotype));
  background-size: 0% var(--hair);
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: color var(--dur) var(--ease-out),
              background-size var(--dur-slow) var(--ease-out);
}

.contact__email:hover {
  color: var(--cyanotype-bright);
  background-size: 100% var(--hair);
}

.contact__blurb {
  margin: var(--s-5) 0 var(--s-6);
  max-width: 46ch;
}

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

.social {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-4) var(--s-2);
  border-bottom: var(--hair) solid var(--vellum-line);
  color: var(--chalk-dim);
  transition: color var(--dur-fast) var(--ease-out),
              padding-left var(--dur) var(--ease-out);
}

.social:first-child { border-top: var(--hair) solid var(--vellum-line); }

.social:hover {
  color: var(--chalk);
  padding-left: var(--s-4);
}

.social__icon {
  flex: none;
  color: var(--slate-600);
  transition: color var(--dur-fast) var(--ease-out);
}

.social:hover .social__icon { color: var(--cyanotype); }

.social__label { font-size: var(--t-small); }

.social__handle {
  margin-left: auto;
  color: var(--slate-600);
}

.social__arrow {
  flex: none;
  opacity: 0;
  color: var(--cyanotype);
  transform: translateX(-4px);
  transition: opacity var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-out);
}

.social:hover .social__arrow {
  opacity: 1;
  transform: none;
}

/* ============================================================
   RESPONSIVE — plates collapse to one column, and the timeline
   gutter folds so dates sit above the card on narrow screens.
   ============================================================ */

@media (max-width: 1040px) {
  .hack { grid-template-columns: 130px minmax(0, 1fr); }
  .hack__meta {
    grid-column: 1 / -1;
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--s-5);
  }
  .hack__meta-row {
    border-bottom: none;
    padding-bottom: 0;
    gap: var(--s-2);
  }
}

@media (max-width: 900px) {
  .hero {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-7);
  }

  /* Assembly first on mobile: it is the most striking thing on
     the page and it establishes the concept immediately. */
  .hero__lead { order: 2; }
  .hero__figure { order: 1; }

  .profile,
  .contact {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 680px) {
  .timeline { --tl-gutter: 0px; --tl-track: 20px; }

  .timeline__entry {
    grid-template-columns: var(--tl-track) minmax(0, 1fr);
    gap: var(--s-2);
  }

  .timeline__date {
    grid-column: 2;
    grid-row: 1;
    padding-top: 0;
    padding-bottom: var(--s-2);
    text-align: left;
  }

  /* Stacked at desktop, inline here — so the start date needs its
     own gap rather than relying on whitespace between elements,
     which textContent assignment does not produce. */
  .timeline__date b {
    display: inline;
    margin-right: 0.35em;
  }

  .timeline__mark {
    grid-column: 1;
    grid-row: 1 / 3;
    padding-top: 4px;
  }

  .timeline__mark::after { display: none; }

  .timeline__card { grid-column: 2; grid-row: 2; }

  .timeline__run {
    left: calc(var(--tl-track) / 2);
  }

  .hack {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-4);
  }

  .hack__meta { gap: var(--s-4); }
}

@media (max-width: 480px) {
  .hero__name .hero__surname { -webkit-text-stroke-width: 1px; }
  .hero__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .card__metrics { gap: var(--s-4); }
}
