/* ============================================================
   tanmaykhanna.com

   Rules this file holds to:
   - Two registers, one system. Monospace is the chrome — nav,
     age, ping, shell, metadata, lists. A serif is the prose,
     and only on a post. The site reads like a terminal; a post
     reads like a book.
   - Monochrome. Colour is data, never decoration — the only
     hues on the page are the ping and a diff, because both
     mean something.
   - Links are body colour with a faint underline, not a colour.
   - Left-anchored off a hairline. Not a centred column.
   - Every instrument is opt-in per page. The homepage is the
     playground; a post carries nothing that competes with
     the writing.
   ============================================================ */

:root {
  /* Everything sized in rem — headings, nav, gutters, spacing — scales off
     this rather than the browser default, so a size nudge is one number. */
  font-size: 15px;

  --bg: #fdfdfc;
  --fg: #26251f;
  --muted: #86847c;
  --faint: #b3b0a8;
  --rule: #e6e4dd;
  --tint: rgba(38, 37, 31, 0.045);
  --tint-firm: rgba(38, 37, 31, 0.07);

  /* Lighthouse's own three tiers — a browser convention, not a
     signal-strength meter. */
  --good: #0cce6b;
  --mid:  #ffa400;
  --poor: #ff4e42;

  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  /* ui-serif is New York on Apple platforms; the rest are the good
     system serifs. No webfont, so no request and no layout shift. */
  --serif: ui-serif, "Iowan Old Style", Charter, "Palatino Linotype",
           "Book Antiqua", Palatino, Georgia, serif;

  /* syntax colours, warm-leaning to match the cream ground */
  --syn-key:  #8b3a9e;
  --syn-str:  #3d7a4b;
  --syn-fn:   #8a6516;
  --syn-num:  #a44e26;
  --syn-type: #1c6b70;
  --syn-com:  #9a968c;

  --gutter: clamp(1.25rem, 8vw, 7rem);
  --measure: 38rem;  /* mono pages */
  --prose: 44rem;    /* serif posts */
  --rail: 13rem;     /* table of contents */
  --stack: var(--measure);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #121212;
    --fg: #e3e0d9;
    --muted: #8a867e;
    --faint: #56534e;
    --rule: #272727;
    --tint: rgba(227, 224, 217, 0.055);
    --tint-firm: rgba(227, 224, 217, 0.085);

    --syn-key:  #c4a0cf;
    --syn-str:  #a9c489;
    --syn-fn:   #e3c07b;
    --syn-num:  #d99a70;
    --syn-type: #86c1bd;
    --syn-com:  #6e6a63;
  }
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--fg);
  font: 14.5px/1.7 var(--mono);
  margin: 0;
  padding: 3.5rem 0 2.5rem;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  -webkit-text-size-adjust: 100%;
}

/* content hangs off a hairline set in from the left edge */
.stack,
#shell,
.social {
  margin-left: var(--gutter);
  max-width: var(--stack);
  padding-right: 1.25rem;
}
.stack { flex: 1 0 auto; }

/* ---------------------------------------------------------- links ----- */

a {
  color: var(--fg);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: var(--faint);
}
a:hover { text-decoration-color: var(--fg); }

:focus-visible { outline: 2px solid var(--fg); outline-offset: 3px; border-radius: 2px; }

.skip {
  position: absolute;
  left: -9999px;
  top: 0.5rem;
  background: var(--bg);
  padding: 0.5rem 0.75rem;
  font-size: 0.8rem;
  z-index: 20;
}
.skip:focus { left: 1rem; }

/* --------------------------------------------- reading progress ------- */
/* A 2px hairline. It is the only fixed thing on a post. */

#progress {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 2px;
  z-index: 10;
  pointer-events: none;
}
#progress i {
  display: block;
  height: 100%;
  width: 0;
  background: var(--fg);
  opacity: 0.55;
}

/* ------------------------------------------------------------ age ----- */
/* top left, in the flow, above everything else. Homepage only. */

#age {
  font-size: 0.72rem;
  line-height: 1.5;
  letter-spacing: 0.02em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
  user-select: none;
  margin-bottom: 2.25rem;
}

/* A page with no age counter reserves its exact box anyway, invisibly, so
   nav lands at the same height whether or not the real one is above it. */
#age.quiet { visibility: hidden; }

/* ------------------------------------------------------------ nav ----- */

nav.top { margin-bottom: 3rem; display: flex; gap: 1.5rem; font-size: 0.875rem; }
nav.top a { color: var(--muted); text-decoration: none; }
nav.top a:hover { color: var(--fg); }

/* a post gets a way back and a wordmark, and nothing else */
nav.back { justify-content: space-between; gap: 1rem; margin-bottom: 3.25rem; }
nav.back .wordmark { color: var(--faint); }

/* ------------------------------------- terminal register (default) ---- */

h1, h2, h3 { font-size: 1rem; font-weight: 600; line-height: 1.45; margin: 2.5rem 0 1rem; }
h1 { margin-top: 0; }

p, ul, ol, pre, blockquote { margin: 0 0 1.4rem; }
main > :last-child, main > *:last-child > :last-child { margin-bottom: 0; }

.muted, time, .dot { color: var(--muted); }
.dot { margin: 0 0.5em; color: var(--faint); }
.draft { color: var(--muted); font-style: normal; }

.page-title { margin-bottom: 2.5rem; }

ul.plain { list-style: none; padding: 0; }
ul.plain li { margin-bottom: 0.4rem; }

/* ---------------------------------------------------- the blog log ---- */

.year { margin-bottom: 3rem; }
.year > h2 {
  margin: 0 0 1.25rem;
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.14em;
  color: var(--faint);
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--rule);
}

ul.log { list-style: none; padding: 0; margin: 0; }
ul.log li { margin-bottom: 1.75rem; }
.log-title {
  font-size: 1.0625rem;
  text-decoration-color: transparent;
  transition: text-decoration-color 0.15s;
}
.log-title:hover { text-decoration-color: var(--fg); }
.log-meta { margin: 0.3rem 0 0; font-size: 0.72rem; color: var(--muted); }
.log-summary { margin: 0.4rem 0 0; font-size: 0.875rem; color: var(--muted); max-width: 30rem; }

/* ================================ prose register — posts only ======== */

/* A post centres in the window, with the contents out on the far left, so
   the page isn't all weight down one edge the way the homepage is.
   Flex rather than block: the contents have to be able to jump above the
   article when there's no room for a rail. */
body.post .stack,
body.post .social {
  margin-left: auto;
  margin-right: auto;
  /* the padding is outside the measure, so the text itself is --prose wide */
  max-width: calc(var(--prose) + 2.5rem);
  padding-left: 1.25rem;
  padding-right: 1.25rem;
}

.post-grid { display: flex; flex-direction: column; }

.prose {
  font-family: var(--serif);
  font-size: 1.1875rem;
  line-height: 1.72;
  min-width: 0;
}

.prose h1 {
  font-size: clamp(1.95rem, 5.5vw, 2.5rem);
  line-height: 1.12;
  letter-spacing: -0.021em;
  font-weight: 600;
  margin: 0 0 0.7rem;
  text-wrap: balance;
}

.post-meta {
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--muted);
  margin: 0 0 2.25rem;
  padding-bottom: 1.75rem;
  border-bottom: 1px solid var(--rule);
}

.prose h2, .prose h3, .prose h4 {
  font-weight: 600;
  letter-spacing: -0.012em;
  line-height: 1.25;
  scroll-margin-top: 2.5rem;
  text-wrap: balance;
}
.prose h2 { font-size: 1.45rem; margin: 2.9rem 0 0.9rem; }
.prose h3 { font-size: 1.15rem; margin: 2.1rem 0 0.6rem; }
.prose h4 { font-size: 1rem; margin: 1.8rem 0 0.5rem; color: var(--muted); }

.prose p { margin: 0 0 1.35em; }
.prose ul, .prose ol { margin: 0 0 1.35em; padding-left: 1.35em; }
.prose li { margin-bottom: 0.4em; }
.prose li > ul, .prose li > ol { margin: 0.4em 0 0; }

.prose a { text-decoration-color: var(--muted); text-underline-offset: 0.18em; }

.prose strong { font-weight: 600; }

.prose blockquote {
  margin: 1.8rem 0;
  padding-left: 1.25rem;
  border-left: 2px solid var(--rule);
  font-style: italic;
  color: var(--muted);
}
.prose blockquote p:last-child { margin-bottom: 0; }

.prose hr { border: none; border-top: 1px solid var(--rule); margin: 2.75rem 0; }

.prose img { max-width: 100%; height: auto; border-radius: 4px; display: block; margin: 1.8rem 0; }

/* click target for a section, revealed on hover of the heading */
.prose .anchor {
  margin-left: 0.4em;
  font-family: var(--mono);
  font-size: 0.7em;
  color: var(--faint);
  text-decoration: none;
  opacity: 0;
  transition: opacity 0.15s;
}
.prose :is(h2, h3):hover .anchor,
.prose .anchor:focus-visible { opacity: 1; }

/* tables step back into the mono register — they are data */
.prose table {
  border-collapse: collapse;
  width: 100%;
  font-family: var(--mono);
  font-size: 0.8125rem;
  margin: 1.8rem 0;
  display: block;
  overflow-x: auto;
}
.prose th, .prose td {
  border-bottom: 1px solid var(--rule);
  padding: 0.5rem 1rem 0.5rem 0;
  text-align: left;
  vertical-align: top;
}
.prose th { color: var(--muted); font-weight: 400; letter-spacing: 0.04em; }

/* footnotes */
.prose .footnote-ref { font-family: var(--mono); font-size: 0.7em; text-decoration: none; padding: 0 0.1em; }
.prose .footnotes {
  margin-top: 3rem;
  padding-top: 0.5rem;
  font-size: 0.9375rem;
  color: var(--muted);
}
.prose .footnotes hr { margin: 0 0 1.5rem; }
.prose .footnotes ol { padding-left: 1.2em; }
.prose .footnote-backref { text-decoration: none; }

/* generic table/img/quote outside the prose register */
table { border-collapse: collapse; width: 100%; }
img { max-width: 100%; height: auto; }
hr { border: none; border-top: 1px solid var(--rule); margin: 2.5rem 0; }
blockquote { border-left: 2px solid var(--rule); margin-left: 0; padding-left: 1rem; color: var(--muted); }

/* ------------------------------------------------------ code ---------- */

code { font-family: var(--mono); font-size: 0.9em; }

.prose :not(pre) > code {
  font-size: 0.84em;
  background: var(--tint);
  padding: 0.14em 0.36em;
  border-radius: 3px;
  overflow-wrap: break-word;
}

.code {
  margin: 1.8rem 0;
  border: 1px solid var(--rule);
  border-radius: 6px;
  overflow: hidden;
  background: var(--tint);
}

.code-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.4rem 0.5rem 0.4rem 0.85rem;
  border-bottom: 1px solid var(--rule);
  font: 0.66rem/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

.code-copy {
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: var(--muted);
  background: none;
  border: 0;
  padding: 0.25rem 0.4rem;
  border-radius: 3px;
  cursor: pointer;
}
.code-copy:hover { color: var(--fg); background: var(--tint-firm); }
.code-copy[data-done] { color: var(--fg); }

.code pre, pre.chroma {
  margin: 0;
  padding: 0.95rem 1rem;
  background: none;
  overflow-x: auto;
  font-size: 0.8125rem;
  line-height: 1.62;
  -webkit-text-size-adjust: 100%;
}
.code pre code { font-size: inherit; background: none; padding: 0; }

/* a bare pre, outside a post */
pre {
  background: var(--tint);
  border-radius: 3px;
  overflow-x: auto;
  padding: 0.9rem 1rem;
}
pre code { font-size: 0.85rem; }

/* --- chroma tokens -----------------------------------------------------
   Five hues, all pulled toward the warm ground the rest of the site sits
   on, so code reads as part of the page rather than a pasted screenshot.
   Colour does the work, so nothing here is bold. */

.code .c, .code .ch, .code .cm, .code .c1, .code .cs,
.code .cp, .code .cpf { color: var(--syn-com); font-style: italic; }

.code .k, .code .kc, .code .kd, .code .kn, .code .kp, .code .kr,
.code .ow, .code .nt { color: var(--syn-key); }

.code .kt, .code .nc, .code .ne, .code .nb, .code .bp,
.code .no { color: var(--syn-type); }

.code .nf, .code .fm, .code .na, .code .nd { color: var(--syn-fn); }

.code .s, .code .sa, .code .sb, .code .sc, .code .dl, .code .sd, .code .s2,
.code .se, .code .sh, .code .si, .code .sx, .code .sr, .code .s1,
.code .ss { color: var(--syn-str); }

.code .m, .code .mb, .code .mf, .code .mh, .code .mi, .code .mo,
.code .il { color: var(--syn-num); }

.code .o, .code .p, .code .pi { color: var(--muted); }
.code .err { color: var(--poor); }

.code .gd { background: color-mix(in srgb, var(--poor) 14%, transparent); display: block; }
.code .gi { background: color-mix(in srgb, var(--good) 14%, transparent); display: block; }
.code .gs { font-weight: 600; }
.code .ge { font-style: italic; }

/* ------------------------------------------- table of contents -------- */

/* Stacked above the article by default; pinned to the left edge once the
   window is wide enough for a rail (see the min-width rule below). */
.toc {
  order: -1;
  font: 0.78rem/1.5 var(--mono);
  margin-bottom: 2.75rem;
  padding-bottom: 1.75rem;
  border-bottom: 1px solid var(--rule);
}

.toc summary {
  color: var(--faint);
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  list-style: none;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 0.45rem;
}
.toc summary::-webkit-details-marker { display: none; }
.toc summary::before {
  content: "";
  width: 0.3rem; height: 0.3rem;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.18s;
}
.toc[open] summary::before { transform: rotate(-135deg); }
.toc summary:hover { color: var(--muted); }

.toc ol { list-style: none; margin: 1rem 0 0; padding: 0; border-left: 1px solid var(--rule); }
.toc li { margin: 0; }
.toc li a {
  display: block;
  padding: 0.32rem 0 0.32rem 0.9rem;
  margin-left: -1px;
  border-left: 1px solid transparent;
  color: var(--muted);
  text-decoration: none;
}
.toc li a:hover { color: var(--fg); }
.toc li.on > a { color: var(--fg); border-left-color: var(--fg); }
.toc .lvl-3 a { padding-left: 1.8rem; font-size: 0.95em; }

/* --------------------------------------------------- post footer ------ */

.post-nav {
  display: flex;
  gap: 2rem;
  justify-content: space-between;
  margin-top: 4rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
  font-size: 0.875rem;
}
.post-nav a { flex: 0 1 auto; max-width: 48%; text-decoration-color: transparent; }
.post-nav a:hover { text-decoration-color: var(--fg); }
.post-nav span {
  display: block;
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 0.3rem;
}
.post-nav .newer { margin-left: auto; text-align: right; }

/* ------------------------------------------------ social, very last --- */

.social {
  flex: none;
  margin-top: 3.5rem;
  font-size: 0.85rem;
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}
.social a { color: var(--muted); text-decoration: none; }
.social a:hover { color: var(--fg); }

/* On a post the footer lines up with the centred column. Everywhere else the
   column is hard left, so centring the footer keeps the page from tipping. */
body:not(.post) .social {
  max-width: none;
  margin-left: 0;
  margin-right: 0;
  justify-content: center;
}

/* ---------------------------------------------- ping, bottom right ---- */

#hud {
  position: fixed;
  right: 1.75rem;
  bottom: 1.5rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font: inherit;
  font-size: 0.72rem;
  line-height: 1;
  color: var(--muted);
  background: none;
  border: 0;
  padding: 0.25rem 0;
  cursor: pointer;
  user-select: none;
  --q: var(--faint);
}
#hud[data-q="good"] { --q: var(--good); }
#hud[data-q="fair"] { --q: var(--mid); }
#hud[data-q="poor"] { --q: var(--poor); }

.hud-bars { display: flex; align-items: flex-end; gap: 2px; height: 9px; }
.hud-bar { width: 3px; background: var(--rule); transition: background 0.25s; }
.hud-bar:nth-child(1) { height: 4px; }
.hud-bar:nth-child(2) { height: 6.5px; }
.hud-bar:nth-child(3) { height: 9px; }
.hud-bar.on { background: var(--q); }
.hud-value { color: var(--fg); font-variant-numeric: tabular-nums; }
.hud-spark { width: 36px; height: 10px; color: var(--q); }

/* --------------------------------------------- shell, bottom left ----- */
/* A capped, self-scrolling frame rather than a window with chrome — it grows
   in place instead of growing the whole page, and JS keeps it scrolled to
   the newest line, the way a real terminal viewport behaves. */

#shell {
  flex: none;
  display: none;
  font-size: 0.85rem;
  line-height: 1.7;
  margin-top: 3rem;
}
#shell.open {
  display: block;
  animation: shell-in 0.5s ease both;
  max-height: min(58vh, 26rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-top: 0.75rem;
  padding-right: 0.75rem;
  border-top: 1px solid var(--rule);
  scrollbar-width: none;      /* firefox */
  -ms-overflow-style: none;   /* old edge */
}
/* still scrolls — wheel, trackpad, arrow keys, follow() — just no track drawn */
#shell.open::-webkit-scrollbar { display: none; }
@keyframes shell-in { from { opacity: 0; } }

.sh-line { white-space: pre-wrap; word-break: break-word; }
.sh-dim { color: var(--muted); }
.sh-note { color: var(--muted); padding-left: 12ch; }

.sh-edit { display: flex; white-space: pre-wrap; word-break: break-word; }
.sh-prompt { flex: none; color: var(--muted); }

.sh-caret {
  display: inline-block;
  width: 0.6em;
  background: var(--fg);
  color: var(--bg);
  animation: sh-blink 1.05s step-end infinite;
}
#shell:not(.focused) .sh-caret {
  background: transparent;
  outline: 1px solid var(--muted);
  color: var(--fg);
  animation: none;
}
@keyframes sh-blink { 50% { background: transparent; color: inherit; } }

/* fixed, not absolute-off-at--9999px: a focused input parked far outside the
   document makes the browser scroll to try to reveal it on every keystroke,
   since caret movement counts as a focus-visibility change. Anchored to the
   viewport corner, it's always "in view" already, so nothing ever scrolls. */
.sh-capture { position: fixed; opacity: 0; width: 1px; height: 1px; border: 0; padding: 0; left: 0; top: 0; }

/* ------------------------------------------- idle art, after 5 min ---- */
/* A small figure that drops in, works its way down the page by landing on
   real elements, asks whether you're still there, and leaves. The stage is
   fixed and JS translates it; everything in here is the drawing itself. */

#art {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 5;
  width: 112px;
  height: 112px;
  pointer-events: none;
  user-select: none;
  color: var(--fg);
  opacity: 0.9;
  will-change: transform;
}

.art-svg {
  display: block;
  overflow: visible;
  transform-origin: 50% 100%; /* squash on landing, from the feet */
}

.art-svg line,
.art-svg path,
.art-svg circle {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.art-head { fill: var(--bg); }
.art-hair path, .art-mouth { stroke-width: 1.5; }
.art-eyes circle { fill: currentColor; stroke: none; }

.art-board { fill: var(--bg); stroke: currentColor; stroke-width: 1.6; }
.art-text {
  fill: currentColor;
  stroke: none;
  font: 9px var(--mono);
  text-anchor: middle;
}

/* The sign doesn't exist until it's held up, and it springs rather than fades */
.art-sign {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: 50% 100%;
  transform: scale(0.2) translateY(8px);
}
.art-arms-up { opacity: 0; }

.art-svg.holding .art-sign {
  opacity: 1;
  transform: none;
  transition: transform 0.45s cubic-bezier(0.2, 1.7, 0.4, 1), opacity 0.2s;
}
.art-svg.holding .art-arms-up { opacity: 1; }
.art-svg.holding .art-arms-down { opacity: 0; }

.art-eyes {
  transform-box: fill-box;
  transform-origin: 50% 50%;
  animation: art-blink 4.2s infinite;
}
@keyframes art-blink {
  0%, 93%, 100% { transform: scaleY(1); }
  96% { transform: scaleY(0.1); }
}

.art-leg { transform-box: fill-box; transform-origin: 50% 0; }
.art-svg.running .art-leg-l { animation: art-step 0.26s linear infinite; }
.art-svg.running .art-leg-r { animation: art-step 0.26s linear infinite reverse; }
@keyframes art-step {
  0%, 100% { transform: rotate(22deg); }
  50% { transform: rotate(-22deg); }
}

/* facing the way it's headed */
.art-svg.left .art-figure { transform-box: fill-box; transform-origin: 50% 50%; transform: scaleX(-1); }

/* ---------------------------------------------------------- narrow ---- */

/* Wide enough for a rail: pin the contents to the left edge and leave the
   article centred. Below this the two would collide, so they stay stacked. */
@media (min-width: 82rem) {
  .toc {
    position: fixed;
    left: clamp(1.5rem, 3.5vw, 3.25rem);
    top: 3.5rem;
    width: var(--rail);
    max-height: calc(100vh - 6rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    margin-bottom: 0;
    padding-bottom: 0;
    border-bottom: 0;
  }
}

@media (max-width: 40rem) {
  body { padding: 2.5rem 0 3.5rem; }
  .stack, #shell, .social { margin-left: 1.25rem; margin-right: 1.25rem; }
  #age { font-size: 0.66rem; }
  #hud { right: 1.25rem; bottom: 1rem; }
  .hud-spark { display: none; }
  .sh-note { padding-left: 0; }

  .prose { font-size: 1.0625rem; }
  .post-nav { flex-direction: column; gap: 1.5rem; }
  .post-nav a { max-width: 100%; }
  .post-nav .newer { margin-left: 0; text-align: left; }
  .social { gap: 1.1rem; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.001s !important; transition-duration: 0.001s !important; }
}

@media print {
  #hud, #shell, #art, #progress, .toc, nav.top, .social, .code-copy { display: none !important; }
  body { padding: 0; color: #000; background: #fff; }
  .prose { font-size: 11pt; }
}
