/*
 * theme.css — Abhay Dixit's terminal portfolio. Dark by default: a console
 * left running, near-black ground, phosphor-green accent, hairline boxes.
 * Light mode is the same terminal with the lights on — not an inversion.
 */

:root {
  color-scheme: dark;
  --canvas: #0b0f0d;
  --surface: #232725;
  --surface-2: #2c312e;
  --border: #313633;
  --border-strong: #454b47;
  --ink: #e8ece9;
  --muted: #969a97;
  --accent: #3ddc84;
  --accent-hover: #58e69c;
  --accent-ink: #06170f;
  --accent-text: #3ddc84;
  --accent-strong: #7be8ac;
  --accent-soft: #142a1f;
  --accent-border: #2b5b40;
  --success: #3ddc84;
  --success-ink: #06170f;
  --success-soft: #142a1f;
  --success-strong: #7be8ac;
  --warning: #e6b350;
  --warning-ink: #1f1503;
  --warning-soft: #2e260f;
  --warning-strong: #f0cb80;
  --danger: #ef6a6a;
  --danger-ink: #200606;
  --danger-soft: #331515;
  --danger-strong: #f79a9a;
  --chart-1: #3ddc84;
  --chart-2: #58a1e6;
  --chart-3: #e6b350;
  --chart-4: #d97ad9;
  --chart-5: #6fe6d0;
  --chart-6: #ef8a6a;

  --font-display: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --font-body: "Inter", ui-sans-serif, system-ui, sans-serif;
  --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --display-weight: 700;
  --display-tracking: -0.02em;
  --eyebrow-tracking: 0.06em;

  --radius-btn: 4px;
  --radius-card: 4px;
  --radius-input: 4px;
  --border-w: 1px;
  --border-strong-w: 1px;
  --shadow-card: none;
  --shadow-raised: 0 12px 32px -12px rgba(0,0,0,0.55);
  --shadow-btn: none;
  --card-pad: 1.5rem;
  --caps: none;
  --caps-tracking: 0;
  --btn-weight: 600;
  --measure: 62ch;
}

html[data-theme="light"] {
  color-scheme: light;
  --canvas: #f2f4f1;
  --surface: #ffffff;
  --surface-2: #e9ece8;
  --border: #d7dbd6;
  --border-strong: #b7bdb6;
  --ink: #10140f;
  --muted: #4c534e;
  --accent: #0f7a4a;
  --accent-hover: #0c6b40;
  --accent-ink: #ffffff;
  --accent-text: #0f7a4a;
  --accent-strong: #0b5c38;
  --accent-soft: #e1f2e7;
  --accent-border: #a9d7bc;
  --success: #0f7a4a;
  --success-ink: #ffffff;
  --success-soft: #e1f2e7;
  --success-strong: #0b5c38;
  --warning: #9a6a10;
  --warning-ink: #ffffff;
  --warning-soft: #f4e9d3;
  --warning-strong: #7a5209;
  --danger: #b7332b;
  --danger-ink: #ffffff;
  --danger-soft: #f6dedc;
  --danger-strong: #932822;
  --chart-1: #0f7a4a;
  --chart-2: #2166b0;
  --chart-3: #9a6a10;
  --chart-4: #a4319a;
  --chart-5: #158a79;
  --chart-6: #b7502c;
}

/*
 * app.css — Abhay Dixit's terminal portfolio. The code-editor shell (file
 * rail + content pane), the terminal-window chrome, the file-per-section
 * headers, the git-log timeline and the ONE moving thing on the page: the
 * projects grid, which perspective-tilts into place as it scrolls in.
 * Everything else rests still. Tokens only.
 */

@keyframes blink {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0; }
}

html, body { overflow-x: hidden; }

body {
  position: relative;
  background-image: radial-gradient(ellipse 60rem 40rem at 20% -10%, color-mix(in srgb, var(--accent) 9%, transparent), transparent 60%);
  background-repeat: no-repeat;
}

/* ---- The buffer's background: a faint grid, and a green spotlight that --
   scans it under the pointer. Fixed to the viewport (not the page) so it
   reads as the terminal's own surface, not page content — z-index -2/-1
   keeps both layers behind everything, whatever stacking context a normal-
   flow child happens to pick up. --mx/--my are written by app.js on
   mousemove; unset, they default to the middle of the screen. */
body::before,
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(color-mix(in srgb, var(--border-strong) 70%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--border-strong) 70%, transparent) 1px, transparent 1px);
  background-size: 42px 42px;
}
body::before { z-index: -2; opacity: 0.3; }
body::after {
  z-index: -1;
  opacity: 0.9;
  background-image:
    linear-gradient(color-mix(in srgb, var(--accent) 85%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--accent) 85%, transparent) 1px, transparent 1px);
  -webkit-mask-image: radial-gradient(circle 240px at var(--mx, 60vw) var(--my, 30vh), black 0%, transparent 70%);
  mask-image: radial-gradient(circle 240px at var(--mx, 60vw) var(--my, 30vh), black 0%, transparent 70%);
}
html.reduced-motion body::after { display: none; }
@media (hover: none) { body::after { display: none; } }

/* ---- Shell: a slim file-rail, one content pane -------------------------- */
.shell { display: flex; min-height: 100vh; align-items: stretch; }

.rail {
  position: fixed;
  inset-block: 0;
  left: 0;
  width: 15rem;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  padding: 1.75rem 1.25rem;
  background: var(--surface);
  border-right: 1px solid var(--border);
}

.rail-brand {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  text-decoration: none;
}
.rail-brand:hover { text-decoration: none; color: var(--ink); }
.rail-caret { color: var(--accent-text); }
.rail-cursor { color: var(--accent-text); animation: blink 1.1s steps(1) infinite; }

.rail-nav { list-style: none; display: flex; flex-direction: column; gap: 0.2rem; flex: 1; margin: 0; padding: 0; }
.rail-link {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.5rem 0.6rem;
  border-radius: 4px;
  border-left: 2px solid transparent;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--muted);
  text-decoration: none;
  transition: color 0.15s, background-color 0.15s, border-color 0.15s;
}
.rail-link:hover { color: var(--ink); background: var(--surface-2); text-decoration: none; }
.rail-link.is-active { color: var(--accent-text); background: var(--accent-soft); border-left-color: var(--accent); }
.rail-icon { width: 15px; height: 15px; flex-shrink: 0; }

.rail-foot { display: flex; align-items: center; gap: 0.35rem; padding-top: 1rem; border-top: 1px solid var(--border); }
.rail-social { display: inline-flex; color: var(--muted); padding: 0.4rem; border-radius: 4px; }
.rail-social:hover { color: var(--accent-text); background: var(--surface-2); }
.rail-toggle { margin-left: auto; }

.pane { flex: 1; min-width: 0; margin-left: 15rem; }

@media (max-width: 900px) {
  .shell { flex-direction: column; }
  .rail {
    position: sticky;
    inset-block: auto;
    top: 0;
    left: auto;
    width: auto;
    height: auto;
    flex-direction: row;
    align-items: center;
    gap: 1rem;
    padding: 0.85rem 1rem;
    overflow-x: auto;
    border-right: 0;
    border-bottom: 1px solid var(--border);
  }
  .rail-nav { flex-direction: row; flex: none; gap: 0.15rem; }
  .rail-link span { display: none; }
  .rail-link { padding: 0.5rem; }
  .rail-foot { padding-top: 0; border-top: 0; margin-left: auto; }
  .pane { margin-left: 0; }
}

/* ---- Section rhythm ------------------------------------------------------ */
/* Centred in the pane, not pinned to its left edge — on a wide monitor the
   pane is far wider than any one section wants to read at, so the block
   itself sits in the middle of the remaining space instead of flush against
   the rail with a wall of empty canvas past its right edge. */
.scr {
  padding: clamp(3.5rem, 9vw, 6rem) clamp(1.5rem, 5vw, 5rem);
  max-width: 78rem;
  margin-inline: auto;
  width: 100%;
  box-sizing: border-box;
  position: relative;
}
.file-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--muted);
  margin-bottom: 2.25rem;
  padding-bottom: 0.85rem;
  border-bottom: 1px dashed var(--border);
  width: 100%;
}
.file-tag::before { content: "//"; color: var(--border-strong); }

@media (max-width: 640px) {
  .scr { padding: 4rem 1.25rem; }
  /* A group of terminal commands either fits one line or stacks as one
     deliberate column — never two sharing a row with the last one alone. */
  .hero-cmds { flex-direction: column; align-items: stretch; }
  .term-cmd { width: 100%; }
}

/* ---- Terminal window chrome ------------------------------------------------ */
.term-window { border: 1px solid var(--border); border-radius: 4px; background: var(--surface); overflow: hidden; box-shadow: var(--shadow-raised); }
.term-bar { display: flex; align-items: center; gap: 0.65rem; padding: 0.6rem 0.9rem; background: var(--surface-2); border-bottom: 1px solid var(--border); }
.term-dots { display: inline-flex; gap: 0.35rem; }
.dot { width: 0.6rem; height: 0.6rem; border-radius: 999px; display: inline-block; }
.dot-r { background: var(--danger); }
.dot-y { background: var(--warning); }
.dot-g { background: var(--accent); }
.term-path { font-family: var(--font-mono); font-size: 0.72rem; color: var(--muted); }
.term-body { padding: 2rem; }
@media (max-width: 640px) { .term-body { padding: 1.5rem; } }

.term-line { font-family: var(--font-mono); font-size: 0.85rem; color: var(--muted); margin: 0 0 1.25rem; }
.term-prompt { color: var(--accent-text); }
.term-colon { color: var(--muted); margin-right: 0.3rem; }

/* ---- Hero: whoami.sh ------------------------------------------------------- */
.hero-scr { min-height: 100svh; display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 1.5rem; padding-top: 7rem; padding-bottom: 4rem; }
/* A soft green light sits low behind the hero card's text — the same glow
   the page-wide grid carries, scaled to one window. It is a background-image
   layered under term-body's own (transparent) background, so it never has
   to sit above the copy to be seen. Hovering tilts and lifts the whole card
   toward whichever corner the pointer is over — --rx/--ry are written by
   app.js's initTiltCards, the same one that drives every repo-tile below;
   unset (no JS, or a touch device) it falls back to the fixed tilt here. */
.hero-term {
  width: 100%;
  max-width: 58rem;
  position: relative;
  background-image: radial-gradient(circle 320px at 50% 45%, color-mix(in srgb, var(--accent) 16%, transparent), transparent 70%);
  background-repeat: no-repeat;
  transform: perspective(1100px) rotateX(0) rotateY(0);
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.35s ease;
}
.hero-term:hover {
  transform: perspective(1100px) rotateX(var(--rx, 3deg)) rotateY(var(--ry, -3deg)) translateY(-4px);
  transition: transform 0.15s linear, box-shadow 0.35s ease;
  box-shadow: 0 26px 54px -24px color-mix(in srgb, var(--accent) 45%, transparent), var(--shadow-raised);
}
html.reduced-motion .hero-term { transform: none !important; transition: none !important; }
.hero-name {
  font-family: var(--font-display);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 0.95;
  font-size: clamp(2.75rem, 9vw, 6.75rem);
  color: var(--ink);
  margin: 0;
  word-break: break-word;
}
/* inline, not inline-block: an inline-block glyph with no preceding
   whitespace can still wrap onto its own line when the name fills the
   width (word-break: break-word allows it), leaving the cursor floating
   under the name on narrow screens. Inline keeps it glued to the last
   character always. */
.caret { color: var(--accent-text); animation: blink 1.1s steps(1) infinite; display: inline; white-space: nowrap; }
.hero-role { font-family: var(--font-mono); color: var(--accent-text); margin: 1rem 0 0; font-size: 1.05rem; }
.hero-mission { margin: 1rem 0 0; max-width: 44rem; color: var(--muted); font-size: 1.1rem; line-height: 1.65; }
.hero-cmds { margin-top: 2rem; display: flex; flex-wrap: wrap; gap: 0.75rem; }
.term-cmd {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  padding: 0.6rem 1.1rem;
  text-decoration: none;
  transition: border-color 0.15s, color 0.15s, background-color 0.15s;
}
.term-cmd:hover { border-color: var(--accent); color: var(--accent-text); background: var(--accent-soft); text-decoration: none; }
.term-cmd .term-colon { color: var(--accent-text); }
.scroll-hint { font-family: var(--font-mono); font-size: 0.75rem; color: var(--muted); display: flex; align-items: center; gap: 0.35rem; }
/* Replaces a "▾" character JetBrains Mono has no glyph for — it rendered as
   a hollow tofu box in every capture. A drawn icon always has one. */
.scroll-caret { width: 13px; height: 13px; color: var(--accent-text); animation: blink 1.1s steps(1) infinite; }

/* ---- about.md --------------------------------------------------------------- */
/* Solid ground, same reasoning as .projects-scr below: the page-wide grid is
   fixed to the viewport, and its mouse-follow spotlight brightens right as
   the pointer crosses this reading column — a bright grid line struck
   through a sentence is unreadable, not atmospheric. */
.about-scr { perspective: 1400px; position: relative; background: var(--canvas); }
.md-block { font-family: var(--font-body); max-width: var(--measure); color: var(--ink); font-size: 1.05rem; line-height: 1.85; }
.md-block p { margin: 0 0 1.5rem; }
.md-block .cmt { font-family: var(--font-mono); color: var(--muted); margin-right: 0.5rem; }
.md-block code { font-family: var(--font-mono); background: var(--surface-2); color: var(--accent-text); padding: 0.1rem 0.4rem; border-radius: 3px; font-size: 0.9em; }
.pull-quote {
  margin-top: 1.5rem;
  max-width: var(--measure);
  padding: 1.25rem 1.5rem;
  border-left: 2px solid var(--accent);
  background: var(--surface);
  font-family: var(--font-mono);
  color: var(--accent-text);
  font-size: 0.95rem;
}

/* ---- Scroll-entrance: real perspective tilts, never a resting opacity:0 --
   Each block rests fully visible and offset; app:inview (fired once, from
   the platform) adds .in-view, which these transitions animate from. */
.reveal-tilt, .reveal-swing-l, .reveal-swing-r, .reveal-pop {
  transition: transform 0.75s var(--ease-out, ease);
  transition-delay: calc(var(--i, 0) * 100ms);
}
html.js-ready .reveal-tilt[data-inview]:not(.in-view) { transform: translateY(38px) rotateX(-13deg); transform-origin: bottom center; }
html.js-ready .reveal-swing-l[data-inview]:not(.in-view) { transform: translateX(-34px) rotateY(20deg); transform-origin: left center; }
html.js-ready .reveal-swing-r[data-inview]:not(.in-view) { transform: translateX(34px) rotateY(-20deg); transform-origin: right center; }
html.js-ready .reveal-pop[data-inview]:not(.in-view) { transform: translateY(30px) scale(0.93); }
.reveal-tilt.in-view, .reveal-swing-l.in-view, .reveal-swing-r.in-view, .reveal-pop.in-view { transform: none; }
html.reduced-motion [data-inview] { transform: none !important; transition: none !important; }

/* ---- stack.json — three dependency blocks side by side, not one long list */
.stack-scr { perspective: 1400px; position: relative; background: var(--canvas); }
.json-block { font-family: var(--font-mono); font-size: 0.95rem; max-width: 100%; }
.json-line { color: var(--muted); margin: 0; }
.json-key { color: var(--ink); margin: 0 0 0.5rem; }
.json-groups-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2.5rem; margin: 1.25rem 0 0.5rem; }
.json-group { margin-left: 1.25rem; min-width: 0; }
@media (max-width: 900px) {
  .json-groups-grid { grid-template-columns: 1fr; gap: 2rem; }
  .json-group { margin-left: 0; }
}
.dep-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.65rem 0.25rem; border-bottom: 1px solid var(--border); }
.dep-row:last-child { border-bottom: 0; }
.dep-name { color: var(--ink); }
.dep-tag { color: var(--accent-text); font-size: 0.78rem; }

/* ---- projects/ — the one thing that moves ------------------------------------- */
/* The page-wide grid (body::before/after, fixed to the viewport) used to show
   through the gaps between tiles — a second, smaller grid sitting inside the
   big one. This section gets its own solid ground so the gaps between repo
   tiles read as plain canvas, not as more grid. */
.projects-scr { position: relative; background: var(--canvas); }
.repo-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); gap: 1.5rem; margin-top: 0.5rem; perspective: 1600px; }
/* Rests fully visible, just offset — never opacity 0, so a visitor whose
   script fails (or a capture before the entrance fires) still sees the card.
   :not(.in-view) matters: without it this rule (3 class/attr selectors) beat
   .repo-tile.in-view (2 classes) on specificity alone, so the "arrived" state
   below could never win and every tile sat frozen at its offset forever —
   the bug that made the reveal invisible. */
html.js-ready .repo-tile[data-inview]:not(.in-view) {
  transform: translateY(46px) rotateX(-16deg) scale(0.96);
  transform-origin: top center;
}
.repo-tile {
  transition: transform 0.7s var(--ease-out, ease), box-shadow 0.35s ease;
  transition-delay: calc(var(--i, 0) * 110ms);
}
.repo-tile.in-view { transform: none; }
/* Once settled, the tile pops on hover, tilted toward whichever corner the
   pointer is over — --rx/--ry are written per-card by app.js on
   pointermove (rotateX from how far up/down the pointer sits, rotateY from
   how far left/right), so every corner tilts its own way instead of the
   card always popping the same fixed direction. Unset (no JS, or a touch
   device with no hover) it falls back to the same fixed tilt as before.
   The specificity here (class + class + pseudo) is what it takes to
   outrank .repo-tile.in-view above for the transform property. */
.repo-tile.in-view:hover {
  transform: perspective(1100px) rotateX(var(--rx, 4deg)) rotateY(var(--ry, -4deg)) translateY(-6px);
  transition: transform 0.15s linear, box-shadow 0.35s ease;
  box-shadow: 0 26px 54px -24px color-mix(in srgb, var(--accent) 45%, transparent), var(--shadow-raised);
}
html.reduced-motion .repo-tile[data-inview] { transform: none !important; transition: none !important; }
html.reduced-motion .repo-tile.in-view:hover { box-shadow: none; }
.repo-desc { color: var(--muted); font-size: 0.92rem; line-height: 1.55; margin: 0 0 1.25rem; min-height: 2.7em; }
.repo-meta { display: flex; align-items: center; gap: 0.9rem; margin-bottom: 1.25rem; flex-wrap: wrap; }
.repo-lang { background: var(--accent-soft); color: var(--accent-strong); }
.repo-stat { display: inline-flex; align-items: center; gap: 0.3rem; font-family: var(--font-mono); font-size: 0.8rem; color: var(--muted); }
.repo-icon { width: 14px; height: 14px; }
.repo-link { font-family: var(--font-mono); font-size: 0.85rem; color: var(--accent-text); text-decoration: none; }
.repo-link:hover { text-decoration: underline; }

/* ---- log.git ------------------------------------------------------------------- */
.log-scr { perspective: 1400px; position: relative; background: var(--canvas); }
.git-log { list-style: none; margin: 1rem 0 0; padding-left: 2.25rem; position: relative; }
.git-log::before { content: ""; position: absolute; left: 0.4rem; top: 0.4rem; bottom: 0.4rem; width: 1px; background: var(--border-strong); }
.log-entry { position: relative; padding-bottom: 2.75rem; }
.log-entry:last-child { padding-bottom: 0; }
.log-dot { position: absolute; left: -2.25rem; top: 0.3rem; width: 0.65rem; height: 0.65rem; border-radius: 999px; background: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.log-hash { font-family: var(--font-mono); font-size: 0.78rem; color: var(--accent-text); }
.log-title { font-family: var(--font-mono); font-weight: 600; color: var(--ink); margin: 0.4rem 0 0; }
.log-detail { color: var(--muted); margin: 0.4rem 0 0; max-width: 42rem; line-height: 1.6; }
.log-date { font-family: var(--font-mono); font-size: 0.75rem; color: var(--muted); margin: 0.5rem 0 0; }

/* ---- contact.sh — closing dark statement band ---------------------------------- */
.contact-scr { background: var(--surface); border-top: 1px solid var(--border); min-height: 70vh; display: flex; flex-direction: column; justify-content: center; perspective: 1400px; }
.contact-head {
  font-family: var(--font-display);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 0.98;
  font-size: clamp(2.25rem, 6.5vw, 5rem);
  max-width: 52rem;
  color: var(--ink);
  margin: 0.5rem 0 0;
}
.contact-foot { font-family: var(--font-mono); font-size: 0.8rem; color: var(--muted); margin-top: 3rem; }

/* ---- contact.sh — the form itself ------------------------------------------------ */
.contact-form { width: 100%; max-width: 42rem; margin-top: 2.5rem; }
.contact-form .field-row { gap: 1.25rem; }
.contact-form .field-row + .field { margin-top: 1.25rem; }
.contact-form .label { font-family: var(--font-mono); font-size: 0.78rem; color: var(--muted); text-transform: lowercase; }
.contact-input { background: var(--surface-2); border-color: var(--border-strong); font-family: var(--font-body); color: var(--ink); }
.contact-input:focus { border-color: var(--accent); }
.contact-textarea { min-height: 7.5rem; }
/* The honeypot: present in the DOM for a bot to fill, invisible and
   unreachable by tab for a real visitor. display:none would tell some bots
   to skip it, so this hides it visually instead. */
.hp-field {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.contact-submit { margin-top: 1.75rem; }
/* .term-colon defaults to --muted, which reads fine on a term-body but is
   near-invisible on this button's solid accent fill — fixed contrast on
   both modes measured 1.47:1 / 1.72:1. Match the button's own label colour
   instead of the generic prompt tint. */
.contact-submit .term-colon { color: var(--accent-ink); }
.contact-result:empty { display: none; }
.contact-result { margin-top: 1.25rem; max-width: 42rem; }
.contact-result-ok .term-body { padding: 1.5rem 2rem; }
.contact-ok-line { color: var(--accent-text); font-family: var(--font-mono); font-size: 0.9rem; margin: 0; }
.contact-ok-line strong { color: var(--ink); }

/* ---- inbox.log — Abhay's own read of what came in -------------------------------- */
/* Same reasoning as .about-scr/.stack-scr/.log-scr: the heading and copy here
   sit directly on the page's fixed grid, and its mouse-follow spotlight would
   streak a bright line through them wherever the cursor happens to be. */
.inbox-shell { max-width: 68rem; margin: 0 auto; padding: 4rem 2rem 6rem; position: relative; background: var(--canvas); }
.inbox-back {
  display: inline-flex; align-items: center; gap: 0.3rem; font-family: var(--font-mono);
  font-size: 0.85rem; color: var(--muted); text-decoration: none; margin-bottom: 2rem;
}
.inbox-back:hover { color: var(--accent-text); text-decoration: none; }
.inbox-back .term-colon { color: var(--accent-text); }
.inbox-head { margin-bottom: 2rem; }
.inbox-title {
  font-family: var(--font-display); font-weight: 800; letter-spacing: -0.02em;
  font-size: clamp(1.75rem, 4vw, 2.75rem); color: var(--ink); margin: 0.4rem 0 0;
}
.inbox-sub { font-family: var(--font-mono); font-size: 0.85rem; color: var(--muted); margin: 0.5rem 0 0; }
.mono-cell { font-family: var(--font-mono); font-size: 0.8rem; color: var(--muted); }
.inbox-message { max-width: 32rem; color: var(--ink); line-height: 1.5; }

/* On a narrow screen the table is wider than the row and scrolls inside its
   own box (table-wrap already prevents the PAGE from scrolling sideways) —
   but with no cue, a cut-off "email"/"message" column just reads as broken
   content. This fade says there is more to swipe to. */
@media (max-width: 720px) {
  .inbox-shell .table-wrap { position: relative; }
  .inbox-shell .table-wrap::after {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 28px;
    pointer-events: none;
    background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--surface) 85%, transparent));
  }
}
