/* ============================================================
   Portfolio — Emmanuel Nguyen
   Journal de bord — the page's own layout.

   Kept out of site.css on purpose: this page tries another grid
   with the same kit, so everything here is scoped to .log and
   nothing else on the site reads it. The journal nav button is the
   exception and lives in site.css, with the rest of the HUD.
   ============================================================ */

/* ---------- Page frame ----------
   One measure for the whole page: the reading column and the telemetry
   gutter beside it. The gutter is decorative — it repeats what the rows
   already say — so it goes when there is no room for it. */

.log {
  --rail: 232px;
  --rail-gap: 40px;
}

/* ---------- Head ----------
   The other pages open on a centred HUD block. This one opens flush
   left with the readout pinned right, which is the whole point of the
   page: same kit, other grid. */

.log__head {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--rail);
  gap: var(--rail-gap);
  align-items: end;
  padding: var(--pad-lg) var(--pad) var(--pad);
  border-bottom: 1px solid var(--line);
}

.log__head > *:not(.dots-canvas) { position: relative; }

.log__title { min-height: 85px; }

.log__lede {
  max-width: 62ch;
  margin: 26px 0 0;
  color: var(--txt-3);
}

/* Head readout: three fixed lines, label left, value right. */
.log__boot { display: grid; gap: 6px; padding-bottom: 6px; }
.log__boot-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 5px;
  border-bottom: 1px solid var(--line-soft);
}
.log__boot-row b { font-weight: 400; color: var(--acc); }

/* ---------- Feed + rail ---------- */

.log__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--rail);
  gap: var(--rail-gap);
  padding: 0 var(--pad);
  border-bottom: 1px solid var(--line);
}

/* ---------- One entry ----------
   A row, not a card: the stamp sits in its own column on the left, the
   way a machine log prints it, and the text keeps a reading measure. */

.log__entry {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr);
  gap: 0 32px;
  padding: 38px 0;
  border-bottom: 1px solid var(--line-soft);
}
.log__entry:last-child { border-bottom: 0; }

.log__stamp {
  display: grid;
  gap: 6px;
  align-content: start;
  padding-top: 4px;
}
.log__stamp .id { transition: color .3s ease; }

/* The date sits next to a 16px id. At .meta's 12px the gap was wide
   enough to read as an afterthought; 14/20 pairs with the id and
   shares its baseline in the grid. */
.log__stamp .meta { font-size: 14px; line-height: 20px; }

/* The entry the rail is pointing at. */
.log__entry.is-current .log__stamp .id { color: var(--acc2); }
.log__entry.is-current .log__stamp::after {
  background: var(--acc2);
  box-shadow: 0 0 8px rgba(255, 154, 0, .7);
}
.log__stamp::after {
  content: '';
  width: 18px;
  height: 1px;
  background: var(--line);
  transition: background .3s ease, box-shadow .3s ease;
}

.log__body { display: grid; gap: 14px; justify-items: start; }

.log__entry-title { max-width: 30ch; }
.log__entry:hover .log__entry-title { color: var(--acc); }

.log__text {
  max-width: 68ch;
  margin: 0;
  font-size: var(--fs-md);
  line-height: var(--lh-md);
  color: var(--txt-3);
}

.log__foot { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }

/* An entry that opens something (a sandbox piece) gets the action; a
   plain note does not. */
.log__entry .link-action { opacity: 0; transition: opacity .25s ease; }
.log__entry:hover .link-action,
.log__entry:focus-within .link-action { opacity: 1; }

/* ---------- Telemetry rail ----------
   Decorative: aria-hidden in the markup. It says nothing the rows do
   not already say, it just says it as an instrument. */

.log__rail { position: relative; }

.log__rail-in {
  position: sticky;
  top: 108px;
  display: grid;
  grid-template-columns: 1px minmax(0, 1fr);
  gap: 0 18px;
  padding: 38px 0;
}

/* The track and the fill that follows the scroll. */
.log__track { position: relative; background: var(--line-soft); }
.log__track-fill {
  position: absolute;
  inset: 0 0 auto;
  height: 100%;
  background: linear-gradient(var(--acc2), var(--acc));
  transform: scaleY(0);
  transform-origin: top;
}

.log__readout { display: grid; gap: 10px; align-content: start; }

.log__readout-row {
  display: grid;
  gap: 3px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line-soft);
}
.log__readout-row b {
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 400;
  color: var(--acc);
}
.log__readout-row .log__val--warn { color: var(--acc2); }

/* Ticks: one per entry, lit as the rail reaches it. */
.log__ticks { display: flex; gap: 5px; margin: 4px 0 0; padding: 0; list-style: none; }
.log__ticks li {
  width: 14px;
  height: 2px;
  background: var(--line-soft);
  transition: background .3s ease, box-shadow .3s ease;
}
.log__ticks li.is-lit { background: var(--acc2); box-shadow: 0 0 6px rgba(255, 154, 0, .6); }

/* ---------- Entry reveal (exploration-rail.js) ----------
   Set by the script once it has taken over, so the entries stay
   readable when GSAP does not load and under reduced motion. */
.log.is-animated .log__entry { opacity: 0; }

/* ---------- Narrow ----------
   Under 1100px the gutter has no room; it goes, and the page falls back
   to the one column it always was underneath. */

@media (max-width: 1100px) {
  .log__head,
  .log__grid { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .log__rail { display: none; }
  .log__boot { max-width: 260px; }
}

@media (max-width: 720px) {
  .log__head { padding: var(--pad) var(--pad) 40px; }
  .log__grid { padding: 0 var(--pad); }
  .log__entry { grid-template-columns: minmax(0, 1fr); gap: 16px; padding: 30px 0; }
  .log__stamp { grid-auto-flow: column; justify-content: start; align-items: center; gap: 14px; padding-top: 0; }
  .log__stamp::after { display: none; }
  .log__entry-title { max-width: none; }
  .log__boot { display: none; }
}
