/* ============================================================
   The experience timeline — /experience/.

   One rail, one node per role, newest at the top. The rail is the
   whole point of the page: a list of jobs answers "what has he
   done", and a line down the side answers "for how long, and in
   what order" without the reader having to subtract dates in their
   head. That is the question this page exists for, so the dates get
   their own column rather than being the first words of a paragraph.

   Everything else is deliberately plain. There are no cards here —
   a boxed entry per role turns a career into a component gallery,
   and the rail already does the grouping a border would.
   ============================================================ */

/* ---------- the summary strip ----------
   Four facts, above the rail, in the order a reader asks for them: what he is
   doing now, what he is responsible for, what has shipped, what he is deep in.

   It is a definition list drawn as two columns rather than a row of cards on
   purpose. The page's rule is that a career is not a component gallery, and a
   summary in four boxes would be the first thing to break it — worse, boxes
   would make the summary louder than the timeline it summarises. A narrow
   label column and a hairline between rows says "reference table", which is
   what this is.

   The label column is fixed rather than auto: four labels of different lengths
   left the values on four different verticals, and a column the eye can run
   down is the entire reason for setting this as a table rather than as prose. */
.tl-glance{
  list-style:none;
  margin:0 0 26px;
  padding:0;
  border-top:1px solid var(--line);
  max-width:60ch;
}
.tl-glance li{
  display:grid;
  grid-template-columns:5.5rem minmax(0,1fr);
  gap:16px;
  padding:11px 0;
  border-bottom:1px solid var(--line);
}
.tl-glance .k{
  font-size:var(--t-micro);
  letter-spacing:0.12em;
  text-transform:uppercase;
  color:var(--muted);
  /* aligned to the first line of the value beside it, which is a size larger */
  padding-top:0.2em;
}
.tl-glance .v{
  font-size:var(--t-base);
  line-height:1.5;
  color:var(--text);
}

.timeline{
  list-style:none;
  margin:0;
  padding:0 0 8px;
  /* Where the rail sits: the dates column's width plus half the gutter beside
     it. Written once because the line, the nodes and the column all have to
     agree on it, and three hand-matched numbers drift the moment one changes. */
  --date-col:8.5rem;
  --gutter-col:34px;
  --rail-x:calc(var(--date-col) + (var(--gutter-col) / 2));
}

.tl-item{
  position:relative;
  display:grid;
  grid-template-columns:var(--date-col) minmax(0,1fr);
  column-gap:var(--gutter-col);
  padding-bottom:44px;
}

/* The rail, drawn per item rather than once down the whole list. Per item it
   can stop exactly where the last entry's node is instead of running on past
   it into empty space, and each segment starts level with its own node, so a
   short entry never leaves a gap in the line. */
.tl-item::before{
  content:"";
  position:absolute;
  left:var(--rail-x);
  top:0.55rem;
  bottom:0;
  width:1px;
  background:var(--line);
}
/* The last segment has nothing below it to connect to, so it fades out rather
   than ending on a hard stop that reads like a cut-off list. */
.tl-item:last-child::before{
  bottom:auto;
  height:52px;
  background:linear-gradient(180deg, var(--line), transparent);
}

/* The node. A ring on the page background, so the rail visibly passes behind
   it instead of the two overlapping into a blob. */
.tl-item::after{
  content:"";
  position:absolute;
  left:calc(var(--rail-x) - 4px);
  top:calc(0.55rem - 4px);
  width:9px;
  height:9px;
  border-radius:50%;
  background:var(--bg);
  box-shadow:0 0 0 2px var(--muted);
}
/* The role that is still running. It is the one fact on the page a reader
   wants before any other — "is he available, and what is he doing now" — so
   it is the only filled node, and it carries a halo the others do not. */
.tl-item.is-current::after{
  background:var(--role-nav);
  box-shadow:0 0 0 2px var(--role-nav),
             0 0 0 7px color-mix(in srgb, var(--role-nav) 14%, transparent);
}
@supports not (background: color-mix(in srgb, red 10%, blue)){
  .tl-item.is-current::after{
    box-shadow:0 0 0 2px var(--role-nav), 0 0 0 7px rgba(90,169,255,0.14);
  }
}

/* ---------- the date column ----------
   Right-aligned against the rail so every date ends on the same vertical, a
   hairline away from the node it belongs to. Ragged-left is the correct
   setting for a column of dates read as a sequence: the eye follows the edge
   nearest the line. */
.tl-when{
  grid-column:1;
  margin:0;
  text-align:right;
  font-size:var(--t-mini);
  line-height:1.5;
  letter-spacing:0.02em;
  color:var(--muted);
  /* fixed-width figures so the years stack in columns rather than shimmying */
  font-variant-numeric:tabular-nums;
}
.tl-when .tl-now{ color:var(--role-nav); }
/* The length of the stint, under the dates. It is the arithmetic the reader
   would otherwise be doing themselves. */
.tl-len{
  display:block;
  margin-top:3px;
  font-size:var(--t-micro);
  color:color-mix(in srgb, var(--muted) 75%, transparent);
}
@supports not (color: color-mix(in srgb, red 10%, blue)){
  .tl-len{ color:#6c717a; }
}

/* ---------- the entry ---------- */
.tl-body{ grid-column:2; min-width:0; }

.tl-role{
  font-size:var(--t-h4);
  line-height:1.25;
  /* an h2 element, so it would inherit the h2 tracking; that value is set
     for 30px and is too tight at 18 */
  letter-spacing:-0.008em;
  margin:0 0 4px;
}
.tl-where{
  margin:0 0 14px;
  font-size:var(--t-base);
  color:var(--muted);
}
.tl-where strong{ color:var(--text); font-weight:600; }

/* ---------- weight by recency ----------
   The entries are not equal and the page should not draw them as though they
   are. The longest entry here is the previous job — six bullets against the
   current job's three — so left alone, the block a skimmer's eye lands on is a
   role that ended in 2024. On a page whose whole claim is "senior, leading a
   team, now", that is the layout arguing against the text.

   The fix is hierarchy rather than padding: the current role is set a step
   larger and a shade brighter, and everything below it recedes slightly. It
   costs no words and states the right thing — this is what he does; that is
   what he did. Deliberately small amounts. A current entry that shouted would
   just move the imbalance to the other end.

   Both colours here are one step up from what the entry would otherwise take
   — --muted for the org line, --ink-3 for the bullets. They are deliberately
   not on the reading ramp (tokens.css): what matters is the *gap* between
   this entry and the ones below it, and a ramp step is a level rather than a
   relationship. Naming them as levels would say the current role's bullets
   are a different kind of prose, which is exactly wrong — they are the same
   prose, lifted. If --ink-3 is ever retuned, this pair moves with it by hand. */
.tl-item.is-current .tl-role{ font-size:var(--t-h3); }
.tl-item.is-current .tl-where{ color:#9aa0a9; }
.tl-item.is-current .tl-points li{ color:#c3c8d0; }

.tl-points{
  margin:0;
  padding:0;
  list-style:none;
  max-width:64ch;
}
.tl-points li{
  position:relative;
  padding-left:18px;
  margin-bottom:9px;
  color:var(--ink-3);
  font-size:var(--t-base);
  line-height:1.55;
}
/* A dash rather than a disc: at this size a bullet next to a rail full of
   nodes reads as a second, competing set of markers. */
.tl-points li::before{
  content:"";
  position:absolute;
  left:0;
  top:0.72em;
  width:8px;
  height:1px;
  background:var(--muted);
}
.tl-points strong{ color:var(--text); font-weight:600; }
/* A bolded proper noun ("HustleVerse") and a bolded figure ("81,521") are both
   inside <strong> and are not the same kind of thing: one names, the other
   measures. The .fig span sits inside the strong rather than on it, so the
   rule above styles the phrase and .fig styles the number within it — a
   direct rule on the child, which beats the colour it would otherwise
   inherit without needing to out-specify anything. */

/* An inline link out of a bullet — the LinkedIn write-up on the 81,521 props,
   reached from the sentence that makes the claim. It is a `.link` (base.css)
   and takes the whole recipe from there, including the green it gets for
   leaving the site: the sentence it sits in ends "…holding 81,521 physics
   props in a single scene", with the figure two words earlier in red. Claim,
   then the proof of it, in one line of running text.

   All that is left here is the one thing that is true of this link and no
   other: it ends in an arrow, and a wrap that leaves "↗" alone on the next
   line reads as a stray glyph rather than as part of the label. */
.tl-link{ white-space:nowrap; }

.tl-points + .pill-row{ margin-top:14px; }

/* ---------- the closing blocks ----------
   Education and honours are not roles, so they are not on the rail. They sit
   below it as a plain two-column strip — present, dated, and clearly not part
   of the sequence above. */
.tl-aside{
  display:grid;
  grid-template-columns:repeat(2, minmax(0,1fr));
  gap:24px clamp(24px, 4vw, 56px);
  padding-top:34px;
  margin-top:8px;
  border-top:1px solid var(--line);
}
.tl-aside h2{
  font-size:var(--t-mini);
  font-family:var(--font-sans);
  font-weight:600;
  letter-spacing:0.14em;
  text-transform:uppercase;
  color:var(--muted);
  margin:0 0 14px;
}
.tl-aside ul{ list-style:none; margin:0; padding:0; }
.tl-aside li{ margin-bottom:14px; }
.tl-aside li:last-child{ margin-bottom:0; }
.tl-aside .k{
  display:block;
  font-size:var(--t-base);
  color:var(--text);
  font-weight:600;
}
.tl-aside .v{
  display:block;
  font-size:var(--t-small);
  color:var(--muted);
  margin-top:2px;
}

/* ---------- responsive ---------- */

/* Below this the dates column costs more width than it earns: the entries are
   down to about forty characters a line while a third of the screen holds two
   short dates. So the date moves above its own role, the rail moves to the far
   left, and the page becomes one column with a spine. */
@media (max-width: 720px){
  /* The summary keeps its two columns here rather than stacking. Stacking would
     put each label on its own line and double the strip's height at exactly the
     width where vertical space is scarcest — and the label column is what makes
     the four rows scannable in the first place. It narrows instead. */
  .tl-glance li{ grid-template-columns:4.5rem minmax(0,1fr); gap:12px; padding:10px 0; }

  .timeline{ --date-col:0px; --gutter-col:0px; --rail-x:4px; }

  .tl-item{
    grid-template-columns:minmax(0,1fr);
    padding-left:24px;
    padding-bottom:32px;
  }
  .tl-item::before,
  .tl-item::after{ top:0.45rem; }
  .tl-item::after{ top:calc(0.45rem - 4px); }
  .tl-item:last-child::before{ height:40px; }

  .tl-when{
    grid-column:1;
    text-align:left;
    margin-bottom:6px;
  }
  /* Side by side with the dates now that there is a full line for them. */
  .tl-len{ display:inline; margin:0 0 0 8px; }
  .tl-len::before{ content:"· "; }

  .tl-body{ grid-column:1; }
  /* The role sizes are not rescaled here any more. They used to be, because the
     desktop pair was 20px and 23px and the second of those is wide on a phone.
     The scale replaced them with 18 and 22, which fit a 375px column as they
     are — and rescaling them now would only close the one-step lead the
     current role is meant to keep. */

  .tl-aside{ grid-template-columns:minmax(0,1fr); gap:26px; }
}
