/* ------------------------------------------------------------- Timeline */

/* Every dated role in the Experience list as an ink line on a time axis.
   timeline.js builds it; every position is a percentage of the axis, so
   the drawing reflows on its own and script only places the labels. */

.timeline {
  --lane-gap: 18px;
  --dim: var(--rule);
  --dim-soft: var(--rule);
  /* Reach into the page margins so the "now" dots and focus rings have
     room, and clip there so nothing can ever widen the page. */
  margin: 0 calc(var(--margin) * -1) clamp(48px, 6vw, 88px);
  padding: 4px var(--margin) 0;
  overflow: hidden;
  overflow: clip;
}
/* Lanes step back by colour, not opacity, so their paper stays opaque. */
@supports (color: color-mix(in srgb, red, blue)) {
  .timeline {
    --dim: color-mix(in srgb, var(--ink) 22%, var(--paper));
    --dim-soft: color-mix(in srgb, var(--ink-soft) 24%, var(--paper));
  }
}

/* Axis: year labels over a ruler with a tick for every month. */
.timeline__axis { position: relative; }
.timeline__years { position: relative; height: 15px; transition: opacity 0.35s var(--ease-out); }
.timeline__year { position: absolute; top: 0; color: var(--ink-soft); white-space: nowrap; }
.timeline__year.is-hidden { visibility: hidden; }
.timeline__year--now { right: 0; color: var(--ink); }

.timeline__ruler { display: block; width: 100%; height: 9px; margin-top: 6px; overflow: visible; }
.timeline__ruler line { stroke: var(--ink-soft); stroke-opacity: 0.38; shape-rendering: crispEdges; }
.timeline__ruler .timeline__base { stroke-opacity: 0.22; }
.timeline__ruler .timeline__tick--year { stroke-opacity: 1; }

/* While a role is active the ruler reads it off like a dimension: its
   months stand in for the years over an ink span of the axis. */
.timeline__marks { position: absolute; left: 0; top: 0; width: 100%; height: 15px; pointer-events: none; }
.timeline__mark {
  position: absolute;
  left: 0;
  top: 0;
  color: var(--ink);
  white-space: nowrap;
  opacity: 0;
  transition: transform 0.6s var(--ease-out), opacity 0.35s var(--ease-out);
}
.timeline__ruler .timeline__measure {
  stroke: var(--ink);
  stroke-width: 2;
  stroke-opacity: 1;
  stroke-linecap: round;
  shape-rendering: auto;
  opacity: 0;
  transition: opacity 0.35s var(--ease-out);
}
.timeline.has-active .timeline__years { opacity: 0; }
.timeline.has-active .timeline__mark:not(.is-off),
.timeline.has-active .timeline__measure { opacity: 1; }

/* Plot: dashed year rules and guides behind the lanes, "now" in front. */
.timeline__plot { position: relative; padding-top: 22px; }

.timeline__grid {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: calc(100% - var(--lane-gap));
  overflow: visible;
  pointer-events: none;
}
.timeline__gridline,
.timeline__guide { stroke-dasharray: 2 4; shape-rendering: crispEdges; }
.timeline__gridline { stroke: var(--rule); }
.timeline__guide { stroke: var(--ink); opacity: 0; transition: opacity 0.35s var(--ease-out); }
.timeline.has-active .timeline__guide { opacity: 0.45; }

.timeline__now {
  position: absolute;
  z-index: 2;
  top: -9px;
  right: 0;
  bottom: var(--lane-gap);
  width: 1px;
  background: var(--ink);
  pointer-events: none;
}

.timeline__lanes { position: relative; z-index: 1; }

.timeline__lane {
  position: relative;
  padding-bottom: var(--lane-gap);
  color: var(--ink);
  transition: color 0.5s var(--ease-out);
}
.timeline.has-active .timeline__lane:not(.is-active) { color: var(--dim); }
.timeline.has-active .timeline__lane:not(.is-active) .timeline__org { color: var(--dim-soft); }

/* Role and organisation ride above the line, from where it starts, on a
   patch of paper so the dashed rules behind never run through the text. */
.timeline__label {
  display: flex;
  align-items: baseline;
  gap: 0.55em;
  width: max-content;
  margin-left: var(--from);
  font-size: 13px;
  line-height: 1.35;
  letter-spacing: -0.005em;
  white-space: nowrap;
  background: var(--paper);
  box-shadow: 0 0 0 3px var(--paper);
}
.timeline__lane.is-end .timeline__label { margin-left: auto; margin-right: max(calc(100% - var(--to)), 8px); }
.timeline__lane.is-wrap .timeline__label { flex-wrap: wrap; max-width: calc(100% - 8px); margin-left: 0; white-space: normal; }
.timeline__role { font-weight: 500; }
.timeline__org { color: var(--ink-soft); transition: color 0.5s var(--ease-out); }

.timeline__ink { display: block; width: 100%; height: 10px; margin-top: 5px; overflow: visible; }
.timeline__ink line { stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.timeline__dot { fill: currentColor; }

/* Open roles end in a dot that breathes, softly, while it is on screen. */
.timeline__halo { fill: currentColor; opacity: 0; transform-box: fill-box; transform-origin: center; }
.timeline.is-live .timeline__halo { animation: timeline-pulse 2.8s var(--ease-out) infinite; }
.timeline.is-idle .timeline__halo { animation-play-state: paused; }

@keyframes timeline-pulse {
  0% { opacity: 0.3; transform: scale(1); }
  100% { opacity: 0; transform: scale(3.4); }
}

.timeline__lane:focus-visible { outline: none; }
.timeline__lane:focus-visible .timeline__label { outline: 2px solid currentColor; outline-offset: 4px; border-radius: 2px; }

/* The Experience list answers the timeline: the matching entry keeps its
   ink while the rest step back, and its rule is drawn in like a lane. */
.record__col--exp .entry { position: relative; }
.record__col--exp .entry::before {
  content: "";
  position: absolute;
  inset: -1px 0 auto;
  height: 1px;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 0.8s var(--ease-out);
}
.record__col--exp .entry > * { transition: opacity 0.5s var(--ease-out); }
.record__col--exp .has-active .entry:not(.is-active) > * { opacity: 0.3; }
.record__col--exp .entry.is-active::before { transform: none; }

@media (max-width: 639px) {
  .timeline { --lane-gap: 15px; }
  .timeline__label { font-size: 12.5px; }
  .timeline__ruler .timeline__tick--month { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .timeline__halo { animation: none !important; }
}
