:root {
  --bg: #fafaf7;
  --text: #17171a;
  --muted: #6b6b72;
  --rule: #e6e6e0;
  --accent: #ff4401;
  /* RGB components of --accent, for rgba() uses (hover wash, softened
     text). Keep in sync with --accent if it ever changes. */
  --accent-rgb: 255, 68, 1;
  --placeholder-bg: #fff3b8;
  --placeholder-text: #5c4a00;
  --toggle-bg: #ffffff;
  --toggle-muted-icon: #c8c8d0;
  --max-width: 640px;
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  /* System monospace stack — zero-dependency, matches the OS default
     terminal font. Used for section labels, tenures, dates and other
     numeric/metadata bits; claude-mode overrides this to a coder-style
     stack (see html.theme-claude). */
  --font-mono: ui-monospace, "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}

/* Dark theme — applied by JS via data-theme="dark" (from sunset-based
   auto default OR manual toggle). The @media fallback below kicks in
   only when JS is disabled, so the OS preference is still respected
   in that edge case. */
:root[data-theme="dark"] {
  --bg: #111113;
  --text: #e9e9ec;
  --muted: #8a8a94;
  --rule: #26262a;
  --accent: #ff4401;
  --placeholder-bg: #3a2f00;
  --placeholder-text: #ffe88a;
  --toggle-bg: #22222a;
  --toggle-muted-icon: #4a4a52;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) {
    --bg: #111113;
    --text: #e9e9ec;
    --muted: #8a8a94;
    --rule: #26262a;
    --accent: #ff4401;
    --placeholder-bg: #3a2f00;
    --placeholder-text: #ffe88a;
    --toggle-bg: #22222a;
    --toggle-muted-icon: #4a4a52;
  }
}

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  /* 14px base (14 / 16 = 87.5%). Using a percentage so the scale respects
     users who have bumped their browser default size for accessibility.
     All rem-based sizes in this file derive from this value. */
  font-size: 87.5%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

main {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 5rem 1.5rem 4rem;
}

/* --- typography ------------------------------------------------ */

h1 {
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 0.75rem;
}

h2 {
  font-family: var(--font-mono);
  font-size: 1rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin: 0 0 1.5rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--rule);
}

h3 {
  font-size: 1rem;
  font-weight: 600;
  margin: 0 0 0.25rem;
}

h3 a {
  color: inherit;
  border-bottom-color: transparent;
}

h3 a:hover,
h3 a:focus-visible {
  color: var(--accent);
  border-bottom-color: currentColor;
}

p { margin: 0 0 1rem; }

a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  transition: border-color 120ms ease, color 120ms ease;
}

a:hover,
a:focus-visible {
  color: var(--accent);
  border-bottom-color: currentColor;
}

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

/* --- header ---------------------------------------------------- */

.intro {
  margin-bottom: 3.5rem;
}

.intro > p {
  font-size: 1.05rem;
  color: var(--text);
}

.inline-links {
  font-family: var(--font-mono);
  font-size: 0.95rem;
  color: var(--muted);
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
}

.inline-links span { color: var(--rule); }

/* Nav contact links inherit the muted container colour at rest so the
   accent stays reserved for hover (signal, not decoration). No underline
   at rest. On hover, explicit rule restores the underline via currentColor
   — needed because .inline-links a and a:hover share specificity, so
   without this the transparent border would leak into the hover state. */
.inline-links a {
  border-bottom-color: transparent;
}

.inline-links a:hover,
.inline-links a:focus-visible {
  border-bottom-color: currentColor;
}

/* --- theme toggle pill ---------------------------------------- */
/* Pinned bottom-right. Sun + moon icons always visible; a coloured
   "thumb" slides behind whichever matches the current theme. */

.theme-toggle {
  position: fixed;
  bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
  right:  calc(1.5rem + env(safe-area-inset-right, 0px));
  z-index: 100;

  width: 68px;
  height: 36px;
  padding: 4px;
  border: 0;
  border-radius: 999px;
  background: var(--toggle-bg);
  cursor: pointer;

  box-shadow:
    0 2px 10px rgba(0, 0, 0, 0.08),
    0 1px 3px  rgba(0, 0, 0, 0.06);
  transition:
    background-color 200ms ease,
    box-shadow 200ms ease,
    transform 160ms ease;
}

.theme-toggle:hover {
  box-shadow:
    0 4px 14px rgba(0, 0, 0, 0.12),
    0 2px 5px  rgba(0, 0, 0, 0.08);
  transform: translateY(-1px);
}

.theme-toggle:active { transform: translateY(0); }

.theme-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.theme-toggle__track {
  position: relative;
  display: flex;
  align-items: center;
  gap: 4px;
  width: 100%;
  height: 100%;
}

.theme-toggle__thumb {
  position: absolute;
  top: 0;
  left: 0;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--accent);
  transition: transform 260ms cubic-bezier(0.4, 0, 0.2, 1);
}

:root[data-theme="dark"] .theme-toggle__thumb {
  transform: translateX(32px);
}

.theme-toggle__icon {
  position: relative;
  z-index: 1;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 200ms ease;
}

.theme-toggle__icon svg {
  width: 16px;
  height: 16px;
  display: block;
}

:root[data-theme="light"] .theme-toggle__icon--sun  { color: #fff; }
:root[data-theme="light"] .theme-toggle__icon--moon { color: var(--toggle-muted-icon); }
:root[data-theme="dark"]  .theme-toggle__icon--sun  { color: var(--toggle-muted-icon); }
:root[data-theme="dark"]  .theme-toggle__icon--moon { color: #fff; }

/* --- sections -------------------------------------------------- */

section { margin-bottom: 3.5rem; }

/* --- work: companies and nested roles ------------------------- */

.companies {
  display: flex;
  flex-direction: column;
  gap: 2.75rem;
}

.company-header {
  margin-bottom: 1.1rem;
}

.company-header h3 {
  margin: 0 0 0.15rem;
  font-size: 1.1rem;
}

.tenure {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 500;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.roles {
  list-style: none;
  margin: 0;
  padding: 0 0 0 1.25rem;
  border-left: 1px solid var(--rule);
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.role-title {
  font-weight: 600;
  margin: 0;
  font-size: 0.98rem;
}

.role-meta {
  font-family: var(--font-mono);
  font-size: 0.88rem;
  color: var(--muted);
  margin: 0.1rem 0 0;
  font-variant-numeric: tabular-nums;
}

.role-description {
  margin-top: 0.75rem;
  color: var(--text);
  font-size: 0.95rem;
}

.role-description p {
  margin: 0 0 0.75rem;
}

.role-description p:last-child { margin-bottom: 0; }

/* "Read more" / "Read less" expand on older roles. Native <details>
   for accessibility (keyboard, screen readers) and zero-JS dependency.
   Kept off the most recent role so the headline read stays full-fat. */
.role-description details {
  margin-top: 0.75rem;
}

.role-description details summary {
  display: inline;
  cursor: pointer;
  color: var(--muted);
  border-bottom: 1px solid var(--rule);
  transition: color 0.15s ease, border-color 0.15s ease;
}

/* Hide the default disclosure marker in every browser. The display:inline
   above already strips it in Chromium; these handle Firefox + Safari. */
.role-description details summary { list-style: none; }
.role-description details summary::-webkit-details-marker { display: none; }
.role-description details summary::marker { content: ''; }

.role-description details summary:hover,
.role-description details summary:focus-visible {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.role-description details summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: 1px;
}

/* One-way reveal: once expanded, hide the "Read more" summary entirely.
   No collapse path back, by design — the content is short enough that
   re-hiding it would feel like a needless extra click. */
.role-description details[open] summary { display: none; }

.company-summary {
  margin: 0;
  font-size: 0.95rem;
  color: var(--text);
}

/* --- writing / speaking lists -------------------------------- */
/* Three-column grid via CSS subgrid: title+arrow | location | date.
   Title and arrow share col 1 via an inline-flex wrapper (.entry-head),
   keeping them visually together. Location (col 2) is optional —
   podcasts without a city just leave it empty, date stays in col 3. */

.writing {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: 1fr auto auto;
  column-gap: 1rem;
}

.writing li {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  align-items: baseline;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--rule);
}

.writing li:last-child { border-bottom: none; }

/* No underline on writing/speaking links — ever. Row dividers are
   the structural cue. */
.writing a {
  border-bottom-color: transparent;
}

/* Head wrapper: title + optional arrow, sitting together in col 1.
   Flex inside keeps them adjacent with a tight gap. */
.entry-head {
  grid-column: 1;
  display: flex;
  align-items: baseline;
  gap: 0.3rem;
  min-width: 0;
}

/* Location in col 2 — muted, smaller, contextual. Mono matches the
   .date in col 3 so the right half of each row shares one typographic
   register (metadata) while the title column stays sans (content). */
.entry-location {
  grid-column: 2;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.9rem;
}

/* Arrow rendering — subtle at rest. Animation triggers on row-level
   hover (see the :hover block below), not on arrow hover alone. */
.writing a.entry-arrow {
  color: var(--muted);
  font-size: 0.95em;
  line-height: 1;
  display: inline-block;
  transition: transform 180ms ease, color 160ms ease;
}

/* Row-as-link: a transparent stretched ::before on the title anchor
   covers the whole li, so clicks anywhere on the row (empty space,
   location, date) route to the title's href. :has() scopes this to
   rows that actually have a link — unlinked rows stay inert. */
.writing li:has(a.entry-title) {
  position: relative;
  transition: background-color 160ms ease, color 160ms ease;
  cursor: pointer;
}

.writing li a.entry-title::before {
  content: '';
  position: absolute;
  inset: 0;
  /* Transparent overlay: captures pointer events (which bubble to the
     anchor) while leaving the visible text, location and date below
     untouched. No z-index needed — default paint order works. */
}

/* Keep the arrow above the pseudo hit-area so its own focus outline
   and any divergent href stay independently usable. */
.writing li a.entry-arrow {
  position: relative;
}

/* Highlighter hover: soft orange wash on the row + softened-orange
   text across every cell. rgba() auto-tints against whichever bg is
   active, so no dark-mode override is needed. */
.writing li:has(a.entry-title):hover {
  background-color: rgba(var(--accent-rgb), 0.1);
}

.writing li:has(a.entry-title):hover .entry-title,
.writing li:has(a.entry-title):hover .entry-arrow,
.writing li:has(a.entry-title):hover .entry-location,
.writing li:has(a.entry-title):hover .date {
  color: rgba(var(--accent-rgb), 0.8);
}

.writing li:has(a.entry-title):hover .entry-arrow {
  transform: translate(1px, -1px);
}

/* Date always in col 3, with extra breathing room ahead of it so the
   location / date pair is easy to scan as two distinct bits. */
.writing .date {
  grid-column: 3;
  padding-left: 1rem;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}

/* --- cursor-tied hover preview ------------------------------- */
/* A small 16:9 floating preview that follows the cursor when hovering
   any link with a data-preview attribute. Disabled on touch devices
   (see the JS gate) so it doesn't fire on tap. */

.link-preview {
  position: fixed;
  top: 0;
  left: 0;
  width: 320px;
  aspect-ratio: 16 / 9;
  pointer-events: none;
  z-index: 1000;

  border-radius: 8px;
  overflow: hidden;
  background: var(--rule);
  box-shadow:
    0 12px 32px rgba(0, 0, 0, 0.18),
    0 2px 8px  rgba(0, 0, 0, 0.08);

  opacity: 0;
  transform: translateY(8px) scale(0.97);
  transition: opacity 160ms ease, transform 160ms ease;
  will-change: left, top, opacity, transform;
}

.link-preview.is-visible {
  opacity: 1;
  transform: translateY(0) scale(1);
}

.link-preview img,
.link-preview video {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}

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

footer {
  margin-top: 4rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
  color: var(--muted);
  font-size: 0.85rem;
}

footer p { margin: 0; }

/* --- placeholder markers -------------------------------------- */
/* these highlight unfilled content so edits are obvious.
   delete the .placeholder class from an element once you've
   filled it in, and the highlight disappears. */

.placeholder {
  background: var(--placeholder-bg);
  color: var(--placeholder-text);
  padding: 0 0.25em;
  border-radius: 2px;
}

a.placeholder {
  border-bottom-color: var(--placeholder-text);
}

/* --- small screens -------------------------------------------- */

@media (max-width: 480px) {
  main { padding: 3rem 1.25rem 3rem; }

  /* On narrow screens, stack entry rows: title+arrow on row 1,
     location+date on row 2. Two columns. .entry-head spans both so
     its internal flex layout (title + arrow) gets the full width. */
  .writing {
    grid-template-columns: 1fr auto;
    row-gap: 0.15rem;
  }
  .writing li { row-gap: 0.15rem; }
  .entry-head     { grid-column: 1 / -1; grid-row: 1; }
  .entry-location { grid-column: 1; grid-row: 2; }
  .writing .date  { grid-column: 2; grid-row: 2; }
}

/* ============================================================ */
/* Easter egg: terminal/CLI theme                                */
/* Activated by typing "/claude" anywhere on the page.           */
/* Inspired by the aesthetic of modern terminal CLIs — monospace */
/* font, $ prompt prefixes, tree-draw characters, orange accent. */
/* ============================================================ */

html.theme-claude {
  --bg:   #0a0a0a;
  --text: #d6d6d6;
  --muted: #6e6e6e;
  --rule:  #1a1a1a;
  --accent: #ff4401;
  --toggle-bg: #1a1a1a;
  --toggle-muted-icon: #3a3a3a;
  --placeholder-bg: #2a1700;
  --placeholder-text: #ff8a5a;

  /* Override --font-mono with a developer-flavoured stack so claude-mode
     has a stronger "coder" feel than the default system mono used for
     h2 / tenure / date in the hybrid base. Body font-family is set via
     var(--font-mono) below, so redefining the token cascades to every
     element that opted into mono. */
  --font-mono: "JetBrains Mono", "SF Mono", "Fira Code", Menlo, Monaco, Consolas, "Courier New", monospace;

  /* Terminal ANSI-style palette, used semantically below. Each colour
     maps to a role (identifier, keyword, path, number, etc.) the way
     a code editor syntax-highlights source code. */
  --claude-yellow: #e5c07b;   /* primary identifier   — the name       */
  --claude-purple: #c678dd;   /* keywords             — section headers */
  --claude-cyan:   #56b6c2;   /* paths + all links    — clickable       */
  --claude-blue:   #61afef;   /* secondary identifier — role titles     */
  --claude-green:  #98c379;   /* numeric / temporal   — dates, tenures  */
  --claude-red:    #e06c75;   /* reserved             — errors / emph.  */
}

html.theme-claude body {
  font-family: var(--font-mono);
}

/* "$ whoami" shell-prompt label above the name. */
html.theme-claude h1::before {
  content: "$ whoami";
  display: block;
  font-size: 0.72rem;
  font-weight: 400;
  color: var(--accent);
  opacity: 0.85;
  letter-spacing: 0.08em;
  margin-bottom: 0.6rem;
}

/* Name — primary identifier in yellow. */
html.theme-claude h1 {
  color: var(--claude-yellow);
}

/* Section headings (h2): $ prompt in orange, heading text in purple. */
html.theme-claude h2 {
  color: var(--claude-purple);
}

html.theme-claude h2::before {
  content: "$ ";
  color: var(--accent);
}

/* Company names (h3) — path-like, cyan. */
html.theme-claude .company-header h3 {
  color: var(--claude-cyan);
}

/* Heading links inherit company colour. */
html.theme-claude h3 a { color: inherit; }

/* Tree-draw characters on company + role headers — structural grey. */
html.theme-claude .company-header h3::before {
  content: "├─ ";
  color: var(--muted);
  opacity: 1;
  font-weight: 400;
}

html.theme-claude .role-title::before {
  content: "│  ";
  color: var(--muted);
  opacity: 0.8;
  font-weight: 400;
}

/* Role titles — secondary identifier in blue. */
html.theme-claude .role-title {
  color: var(--claude-blue);
}

/* Dates, tenures, role meta — numeric/temporal, green (the classic
   "numbers are green" convention from terminal output). */
html.theme-claude .role-meta,
html.theme-claude .tenure,
html.theme-claude .writing .date {
  color: var(--claude-green);
}

/* Body-copy links (intro paragraph + role-description) — cyan. */
html.theme-claude .intro p a,
html.theme-claude .role-description a {
  color: var(--claude-cyan);
}

/* Nav contact links — cyan. */
html.theme-claude .inline-links a {
  color: var(--claude-cyan);
}

/* Writing / Speaking list titles — cyan. */
html.theme-claude .writing a {
  color: var(--claude-cyan);
}

/* Blinking cursor at end of intro — orange Claude signature. */
html.theme-claude .intro p:last-of-type::after {
  content: "▊";
  color: var(--accent);
  animation: claude-blink 1.1s step-end infinite;
  margin-left: 3px;
  vertical-align: baseline;
}

@keyframes claude-blink { 50% { opacity: 0; } }

/* Hide the sun/moon toggle while in easter-egg mode. */
html.theme-claude .theme-toggle { display: none; }

/* Typewriter-style element reveal on activation. Each "line-like"
   element animates in sequence (staggered via --claude-delay set by
   JS). The blur + translate gives it a CRT-tube "focusing in" feel
   rather than a flat opacity fade. */
html.theme-claude .claude-reveal {
  animation: claude-focus-in 0.18s cubic-bezier(0.25, 1, 0.5, 1) both;
  animation-delay: var(--claude-delay, 0ms);
}

@keyframes claude-focus-in {
  from {
    opacity: 0;
    transform: translateY(4px);
    filter: blur(2px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
    filter: blur(0);
  }
}

/* Very subtle CRT-style scanlines for retro texture. At ~2% white on
   a near-black bg, they're perceptible on solid dark areas but don't
   reduce text legibility. Pointer-events none so they never block
   hover or click. */
html.theme-claude body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 100;
  background-image: repeating-linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0.022) 0,
    rgba(255, 255, 255, 0.022) 1px,
    transparent 1px,
    transparent 3px
  );
}

/* Top status bar: visible announcement that theme-claude is active, with
   instructions for exiting. Fixed overlay so it doesn't shift layout. */
.claude-mode-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1001;
  padding: 6px 14px;
  background: #ff4401;
  color: #0a0a0a;
  font-family: "JetBrains Mono", "SF Mono", Menlo, Monaco, Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: center;
}

.claude-mode-bar kbd {
  font-family: inherit;
  background: rgba(0, 0, 0, 0.18);
  padding: 1px 5px;
  border-radius: 2px;
  font-size: inherit;
}
