/* ============================================================
   The engine terminal
   ------------------------------------------------------------
   Shared by /science and the homepage. One dark container: a
   monospace log scrolling up on the left, the catalogue as a
   pixel matrix on the right, a heading and a sentence above.

   It carries its OWN colours. /science is a dark page whose
   tokens are already light-on-dark, but the homepage drops this
   into a dark card on a light page, where --ink is near-black
   and the terminal would have rendered dark text on dark. A
   component that travels has to bring its palette with it.

   The controls are optional. Where a page gives it ticks and
   buttons the handler wires them up; where it does not, the
   walkthrough simply runs once and stops.
   ============================================================ */
.tm{
  --t-ink:#EDE6DA; --t-dim:#A8A196; --t-line:rgba(255,255,255,.085);
  --t-gold:#E7CFA3; --t-bad:#C8614C; --t-ok:#7FA86A; --t-raise:rgba(255,255,255,.03);
}
.tm{padding:0;overflow:hidden;background:#0D0C0B}
.tm-top{display:flex;align-items:center;gap:10px;padding:11px 16px;
  border-bottom:1px solid rgba(255,255,255,.07);background:rgba(255,255,255,.015)}
.tm-dots{display:flex;gap:5px}
.tm-dots i{width:8px;height:8px;border-radius:50%;background:rgba(255,255,255,.14)}
.tm-path{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px;color:var(--t-dim);
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tm-live{margin-left:auto;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--t-dim);
  display:inline-flex;align-items:center;gap:6px}
.tm-live::before{content:"";width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.2)}
.tm-live.is-on{color:var(--t-gold)}
.tm-live.is-on::before{background:var(--t-gold);animation:tm-pulse 1.1s ease-in-out infinite}
@keyframes tm-pulse{0%,100%{opacity:.35}50%{opacity:1}}

.tm-caption{margin:0;padding:20px 22px 16px;text-align:center;min-height:74px;
  font-size:13.5px;line-height:1.55;color:var(--t-ink)}
.tm-head[hidden]{display:none}
.tm-head b{display:block;margin-bottom:4px;font-size:17px;font-weight:600;letter-spacing:-.012em;color:var(--t-ink)}

/* the log gets the room; the matrix sits beside it */
.tm-body{display:grid;grid-template-columns:minmax(0,1.75fr) minmax(0,1fr);gap:18px;padding:0 22px}
/* WHICH COLUMN DECIDES THE HEIGHT. The matrix does, and the log is a window
   cut to fit it.

   The log was a fixed 232px while the matrix sized itself from its cells, so
   the log ran short and the bottom-left sat empty. Making the log flex:1
   inside a column wrap did not fix that, it moved it: a flex item still
   offers its max-content height to the grid row that is sizing itself, so
   the log went on setting the row — now from its line count rather than from
   a number. On the homepage that is 11 lines and came out near the matrix by
   luck; on /science it is 22, the row went to 418 against a 243 matrix, and
   the empty space reappeared on the right instead.

   An absolutely positioned child contributes nothing to its parent's
   intrinsic size. So all three panes come out of flow and the row is the
   matrix column's height, whatever that is, with a floor for the case where
   the matrix is small. The log fills it and clips from the top, which is
   what the mask above the first line was always drawing. */
.tm-logwrap{position:relative;min-width:0;min-height:210px}
.tm-log,.tm-plan,.tm-persona{position:absolute;inset:0}
.tm-log{display:flex;flex-direction:column;justify-content:flex-end;
  overflow:hidden;
  mask-image:linear-gradient(transparent,#000 22%);-webkit-mask-image:linear-gradient(transparent,#000 22%)}
.tm-log[hidden]{display:none}
.tm-line{display:flex;gap:10px;white-space:pre;line-height:19px;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px;
  color:var(--t-ink);animation:tm-in .16s ease-out both}
@keyframes tm-in{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:none}}
.tm-k{color:var(--t-gold);min-width:3.4em}
.tm-i{color:var(--t-dim)}
.tm-f{color:var(--t-ink)}
.tm-v{color:var(--t-dim)}
.tm-s{margin-left:auto;color:var(--t-dim);letter-spacing:.04em}
.tm-line.is-short .tm-f,.tm-line.is-short .tm-s{color:var(--t-gold)}
.tm-line.is-cut .tm-s,.tm-line.is-cut .tm-f{color:var(--t-bad)}
.tm-line.is-ok .tm-s{color:rgba(127,168,106,.85)}
.tm-line.is-pick .tm-s,.tm-line.is-pick .tm-f{color:var(--t-ok)}
.tm-line.is-work .tm-f{color:var(--t-dim);font-style:italic}

/* the plan the log resolves into — terminal output, not three cards.
   Boxed cards read as product UI pasted into a console; a numbered list
   under a header line reads as the thing the log just finished doing. */
.tm-plan{display:flex;flex-direction:column;justify-content:center;gap:14px;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
.tm-plan[hidden]{display:none}
.tm-plan-h{display:flex;gap:14px;align-items:baseline;font-size:11px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--t-gold);padding-bottom:9px;
  border-bottom:1px solid rgba(231,207,163,.22)}
.tm-plan-h span:last-child{margin-left:auto;color:var(--t-dim)}
.tm-plan ol{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:11px}
.tm-plan li{display:grid;grid-template-columns:auto minmax(0,1fr);gap:2px 12px;
  animation:tm-in .3s ease-out both}
.tm-plan li:nth-child(2){animation-delay:.09s}
.tm-plan li:nth-child(3){animation-delay:.18s}
.tm-pi{grid-row:1/3;font-size:12px;color:var(--t-dim);padding-top:2px}
.tm-pn{font-size:13.5px;font-weight:600;color:var(--t-ok)}
.tm-pw{font-family:"Inter","Inter var",system-ui,sans-serif;font-size:12.5px;line-height:1.45;color:var(--t-ink)}

/* the catalogue */
.tm-mxwrap{min-width:0;display:flex;flex-direction:column;gap:10px}
/* Height follows the cells, so no row is ever clipped: 16 square cells
   across sets the row height, and ten rows is what fits beside the log. */
.tm-mx{position:relative;display:grid;grid-template-columns:repeat(16,1fr);gap:3px;align-content:start}
.tm-mx i{display:block;aspect-ratio:1;border-radius:2px;background:rgba(255,255,255,.055);
  transition:background .25s ease,opacity .25s ease}
.tm-mx i.is-idle{background:rgba(231,207,163,.2)}
.tm-mx i.is-on{background:var(--t-gold);opacity:.78}
.tm-mx i.is-cut{background:var(--t-bad);opacity:.95}
.tm-mx i.is-pick{background:var(--t-ok);opacity:.95}
.tm-mx.is-dim i.is-on{opacity:.3}
.tm-sweep{position:absolute;top:0;bottom:0;width:34%;pointer-events:none;opacity:0;
  background:linear-gradient(90deg,transparent,rgba(231,207,163,.16),transparent)}
.tm-sweep.is-on{opacity:1;animation:tm-sweep 3.6s linear}
@keyframes tm-sweep{from{transform:translateX(-120%)}to{transform:translateX(420%)}}
.tm-key{display:flex;flex-wrap:wrap;gap:4px 14px;margin:0;font-size:11px;color:var(--t-dim)}
.tm-key span{display:inline-flex;align-items:center;gap:6px}
.tm-key i{width:8px;height:8px;border-radius:2px}
.k-gold{background:var(--t-gold);opacity:.78}
.k-cut{background:var(--t-bad)}
.k-pick{background:var(--t-ok)}

.tm-ticks{display:flex;gap:6px;padding:18px 22px 0}
.tm-tick{flex:1 1 0;height:3px;border-radius:999px;background:rgba(255,255,255,.12);
  border:0;padding:0;cursor:pointer;transition:background .25s ease}
.tm-tick:hover{background:rgba(231,207,163,.45)}
.tm-tick[aria-current="step"]{background:var(--t-gold)}
.tm-tick.is-done{background:rgba(231,207,163,.5)}
.tm-tick:focus-visible{outline:2px solid var(--t-gold);outline-offset:3px}
.tm-controls{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:14px 22px 18px}
.tm-btn{font-family:inherit;font-size:12.5px;font-weight:600;color:var(--t-ink);cursor:pointer;
  padding:7px 14px;border-radius:999px;border:1px solid var(--t-line);background:transparent;
  min-height:34px;transition:border-color .18s ease,color .18s ease}
.tm-btn:hover{border-color:var(--t-gold);color:var(--t-gold)}
.tm-btn:focus-visible{outline:2px solid var(--t-gold);outline-offset:2px}
.tm-btn--quiet{border-color:transparent;color:var(--t-dim)}
.tm-note{margin-left:auto;font-size:11.5px;color:var(--t-dim)}

@media (max-width:860px){
  .tm-body{grid-template-columns:minmax(0,1fr);gap:14px}
  /* Stacked, so there is no matrix beside it to take a height from, and
     the pane carries its own. One number for every width below 860
     rather than a second breakpoint: the tallest thing it ever holds is
     the plan, which goes from 187 to 241 when its product lines wrap
     somewhere under 560. The log fills whatever it is given and clips
     from the top, and the plan and the persona centre in it, so the
     slack at tablet widths shows as neither a gap nor a clip. */
  .tm-logwrap{min-height:0;height:272px}
  .tm-mx{grid-template-columns:repeat(20,1fr);gap:2px}
  .tm-caption{min-height:92px;padding:16px 16px 12px}
  .tm-body{padding-left:16px;padding-right:16px}
  .tm-ticks,.tm-controls{padding-left:16px;padding-right:16px}
  .tm-line{font-size:10.5px;gap:7px}
  .tm-note{margin-left:0;width:100%}
}
@media (max-width:420px){
  .tm-line .tm-v{display:none}
}

/* Nothing runs. The markup already shows the end of the walkthrough. */
@media (prefers-reduced-motion:reduce){
  .tm-line,.tm-plan li{animation:none}
  .tm-sweep.is-on{animation:none;opacity:0}
  .tm-live.is-on::before{animation:none}
  .tm-mx i{transition:none}
}

/* The profile the answers are read into, shown before the log starts. */
.tm-persona{display:flex;flex-direction:column;gap:12px;justify-content:center;
  animation:tm-in .3s ease-out both}
.tm-persona[hidden]{display:none}
.tm-persona-h{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--t-gold)}
.tm-persona dl{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 22px;margin:0}
.tm-persona dl > div{display:flex;flex-direction:column;gap:2px;padding-bottom:9px;
  border-bottom:1px solid var(--t-line)}
.tm-persona dt{font-size:11px;letter-spacing:.04em;text-transform:uppercase;color:var(--t-dim)}
.tm-persona dd{margin:0;font-size:13.5px;line-height:1.4;color:var(--t-ink)}
@media (max-width:860px){
  .tm-persona{gap:9px}
  .tm-persona dl{gap:7px 16px}
  .tm-persona dd{font-size:12.5px}
}
@media (prefers-reduced-motion:reduce){.tm-persona{animation:none}}

/* ---- corner ticks: a panel that carries a reading ----------------------- */
.tm{position:relative}
.tm::before,.tm::after{content:"";position:absolute;width:10px;height:10px;pointer-events:none;z-index:2;
  border:1px solid var(--t-gold);opacity:.5}
.tm::before{top:-1px;left:-1px;border-right:0;border-bottom:0;border-radius:3px 0 0 0}
.tm::after{bottom:-1px;right:-1px;border-left:0;border-top:0;border-radius:0 0 3px 0}


/* A restart control that is an icon, for pages that carry no transport bar.
   Same target size as a button; it just does not say its name. */
/* flex:0 0 auto is the whole fix for "the reset icon goes weird on a phone".
   It is a flex item in .tm-top with a width but no shrink guard, so once the
   path text stopped fitting the row took the space back out of the icon: 15px
   wide at 390 and 2px at 320, which renders as a sliver of a circle with no
   glyph in it. The path truncates now instead, and the icon never moves.

   The ::after is a 44px hit area over a 30px control. The circle is sized to
   sit in a 30px-tall bar; the thumb target does not have to be. */
.tm-icon{position:relative;display:inline-grid;place-items:center;flex:0 0 auto;
  width:30px;height:30px;margin-left:10px;
  border-radius:50%;border:1px solid var(--t-line);background:transparent;
  color:var(--t-dim);cursor:pointer;padding:0;
  transition:color .18s ease,border-color .18s ease,transform .3s ease}
.tm-icon::after{content:"";position:absolute;inset:-7px;border-radius:50%}
.tm-icon svg{width:15px;height:15px;display:block}
.tm-icon:hover{color:var(--t-gold);border-color:var(--t-gold)}
.tm-icon:active svg{transform:rotate(-180deg);transition:transform .3s ease}
.tm-icon:focus-visible{outline:2px solid var(--t-gold);outline-offset:2px}
@media (prefers-reduced-motion:reduce){.tm-icon,.tm-icon:active svg{transition:none}}
