:root {
  color-scheme: light;
  --bg: #fafafa;
  --fg: #2e3338;
  --border: #d0d7de;
  --mono-font: "Maple Mono", "Fira Code", "JetBrains Mono", "SFMono-Regular", ui-monospace, Menlo, Consolas, monospace;
  /* CRT overlay tuning — strength of the texture layer over the terminal. */
  --crt-scan: rgba(0, 0, 0, 0.03);
  --crt-vignette: rgba(0, 0, 0, 0.13);
}

@font-face {
  font-family: "Maple Mono";
  src: url("/fonts/MapleMono.woff2") format("woff2");
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Maple Mono";
  src: url("/fonts/MapleMono-Italic.woff2") format("woff2");
  font-weight: 300 700;
  font-style: italic;
  font-display: swap;
}

* { box-sizing: border-box; }

/* Zero-size SVG that only hosts <defs> (the grain filter). Kept out of layout. */
.defs-only { position: absolute; width: 0; height: 0; overflow: hidden; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--mono-font);
}

#app {
  height: 100vh;
  display: flex;
  justify-content: center;
  padding: 12px;
}

#term-host {
  position: relative;
  flex: 1;
  min-height: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  /* Spacing between the terminal content and the rounded frame; extra bottom
     padding also absorbs sub-pixel row overflow so the last line isn't
     clipped by overflow:hidden. */
  padding: 16px 18px 28px 18px;
  overflow: hidden;
  /* Cap at ~80 columns. Padding lives on this outer frame; xterm mounts in
     the padding-free #term-screen below, so FitAddon measures only the
     content width (80ch) — otherwise it counts the padding as extra columns
     and text overflows the right edge. */
  max-width: calc(80ch + 38px);
  /* Hidden until the terminal has been fit at final (post-font-load)
     metrics, then faded in — masks the pre-JS full-width frame and the
     web-font swap reflow that would otherwise flash on load. */
  opacity: 0;
  transition: opacity 150ms ease-out;
}
#term-host.ready { opacity: 1; }

/* xterm mount point — padding-free so its measured width is exactly the
   terminal area (no phantom columns from the frame's padding). The smudge
   filter is applied here, to the actual terminal pixels (foreground text). */
#term-screen {
  height: 100%;
  filter: url(#crt-smudge);
}
#term-screen .xterm { height: 100%; }

/* An attached session replays raw PTY history into a fresh xterm instance.
   Keep that fast-forward hidden and reveal only the fully parsed screen. */
#term-host.restoring #term-screen { visibility: hidden; }
#session-restore {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  color: #6a737d;
  background: var(--bg);
  font: 15px/20px var(--mono-font);
}
#session-restore[hidden] { display: none; }

/* Enable OpenType ligatures consistently. Chrome doesn't enable them by
   default for this font while Safari does, so the italic 'll' (and
   programming ligatures like =>, ==) only showed in Safari. Maple Mono's
   ligatures are width-stable, so they don't break xterm's cell alignment. */
#term-screen .xterm-rows,
#term-screen .xterm-rows span {
  font-feature-settings: "liga" 1, "calt" 1;
}

/* CRT overlay — a pure visual layer above the terminal. It never distorts the
   pixels beneath (no SVG filter / displacement), so there's no ghost, no
   Safari breakage, and text stays crisp. pointer-events:none keeps input and
   selection reaching xterm. */
#term-host::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: 10;
  /* Scanlines: the CRT phosphor mask ("颗粒" grain). */
  background: repeating-linear-gradient(
    to bottom,
    var(--crt-scan) 0 1px,
    transparent 1px 3px
  );
  mix-blend-mode: multiply;
}
#term-host::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: 11;
  /* Vignette: edges fall off, reading as curved glass depth without warping. */
  background: radial-gradient(
    ellipse 120% 120% at 50% 50%,
    transparent 55%,
    var(--crt-vignette) 100%
  );
}

/* xterm hard-codes the viewport to black. When the available height is not an
   exact multiple of the cell height, that color otherwise leaks out as a
   thick line below the last row. */
#term-screen .xterm .xterm-viewport {
  background-color: var(--bg);
  overflow-x: hidden;
  scrollbar-width: thin;
  scrollbar-color: #c0c7cf transparent;
}
#term-screen .xterm .xterm-viewport::-webkit-scrollbar { width: 10px; }
#term-screen .xterm .xterm-viewport::-webkit-scrollbar-track { background: transparent; }
#term-screen .xterm .xterm-viewport::-webkit-scrollbar-thumb {
  background: #c0c7cf;
  border-radius: 5px;
}
#term-screen .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover { background: #a8afb7; }

/* Terminal link confirmation. The in-page dialog avoids window.confirm and
   Safari suppressing the default action of a target="_blank" link. */
.link-confirm {
  width: min(520px, calc(100vw - 32px));
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--mono-font);
  font-size: 15px;
  font-weight: 400;
  line-height: 20px;
  box-shadow: none;
  font-feature-settings: "liga" 1, "calt" 1;
}
.link-confirm::backdrop { background: rgba(46, 51, 56, 0.24); }
.link-confirm::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: 2;
  background:
    radial-gradient(ellipse 120% 120% at 50% 50%, transparent 55%, var(--crt-vignette) 100%),
    repeating-linear-gradient(to bottom, var(--crt-scan) 0 1px, transparent 1px 3px);
  mix-blend-mode: multiply;
}
.link-confirm form {
  position: relative;
  z-index: 1;
  padding: 20px;
  background: var(--bg);
  color: var(--fg);
  font: inherit;
}
.link-confirm h2 {
  margin: 0 0 8px;
  font: inherit;
  font-weight: 400;
}
.link-confirm p { margin: 0 0 10px; color: var(--fg); font: inherit; }
.link-confirm-url {
  display: block;
  max-height: 8em;
  overflow: auto;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  color: var(--fg);
  font: inherit;
  letter-spacing: normal;
  overflow-wrap: anywhere;
  white-space: normal;
}
.link-confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 16px;
}
.link-confirm-actions button {
  padding: 7px 14px;
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--fg);
  background: var(--bg);
  font: inherit;
  appearance: none;
  -webkit-appearance: none;
  text-decoration: none;
  cursor: pointer;
}
.link-confirm-actions button:hover { background: rgba(46, 51, 56, 0.06); }
.link-confirm-actions button:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: 2px;
}
.link-confirm-open {
  border-color: #0969da !important;
  color: #0969da !important;
}
.link-confirm p.link-confirm-error {
  margin: 8px 0 0 !important;
  color: #cf222e !important;
  font-size: 13px;
  line-height: 18px;
}

/* Phones: the home ASCII banner needs ~35 cols. The default frame paddings eat
   too much horizontal space on a narrow screen and force the banner to wrap,
   so tighten the outer margins and the terminal's own padding here. Desktop
   keeps the comfortable spacing above. */
@media (max-width: 640px) {
  #app { padding: 4px; }
  #term-host {
    padding: 12px 8px 22px 8px;
    border-radius: 6px;
  }
}

/* Read-only comments on generated blog pages. */
.comments { margin-top: 2.5rem; border-top: 1px solid var(--border); padding-top: 1rem; }
.comments h2 { margin: 0 0 .75rem; font-size: 1.2rem; }
.comments-status { color: #6a737d; font-size: 13px; }
.comment-list { list-style: none; margin: 0; padding: 0; }
.comment-item { padding: .8rem 0; border-top: 1px dashed var(--border); }
.comment-meta, .comment-text { margin: 0; }
.comment-meta { color: #6a737d; font-size: 13px; }
.comment-meta strong { color: var(--fg); }
.comment-text { padding: .35rem 0 0 2rem; white-space: pre-wrap; overflow-wrap: anywhere; }
