/* ==========================================================================
   Corey Michaud · personal site
   Plain HTML + CSS. No JavaScript.

   Look: dark, quiet, and glassy. Soft light fields (colored from the hero
   photo) sit behind translucent "liquid glass" surfaces. Type is SF Pro
   on Apple devices, Inter everywhere else.
   ========================================================================== */

@property --spin {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

:root {
  color-scheme: dark;

  /* surfaces and ink */
  --bg: #050608;
  --ink: #f5f5f7;
  --ink-2: #d1d2d8; /* body text: ~12:1 on the cards */
  --ink-3: #aeb1b9; /* labels: ~8:1 on the cards */
  --hair: rgba(255, 255, 255, 0.08);
  --hair-2: rgba(255, 255, 255, 0.14);
  --link: #2997ff;

  /* chart marks (categorical steps validated on the dark surface) */
  --blue: #3987e5;
  --orange: #d95926;
  --green: #199e70;
  --gray-mark: #5b5f69;
  --up: #30d158;

  /* light fields, sampled from the photo: sky, sweater, field, sun */
  --slate: 58, 98, 170;
  --wine: 138, 36, 72;
  --moss: 46, 104, 78;
  --amber: 160, 104, 36;

  /* liquid glass */
  --glass-fill: linear-gradient(180deg, rgba(255, 255, 255, 0.085) 0%, rgba(255, 255, 255, 0.03) 100%);
  --glass-blur: blur(20px) saturate(170%);
  --glass-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 0 24px rgba(255, 255, 255, 0.02),
    0 1px 1px rgba(0, 0, 0, 0.35),
    0 20px 50px -20px rgba(0, 0, 0, 0.7);
  --glass-rim: linear-gradient(150deg,
    rgba(255, 255, 255, 0.5) 0%,
    rgba(255, 255, 255, 0.1) 22%,
    rgba(255, 255, 255, 0.03) 50%,
    rgba(255, 255, 255, 0.08) 78%,
    rgba(255, 255, 255, 0.3) 100%);

  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Inter", system-ui, "Segoe UI", sans-serif;
  --font-display: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Inter", system-ui, "Segoe UI", sans-serif;

  --gutter: 20px;
  --max: 1080px;
  --spring: cubic-bezier(0.2, 0.8, 0.2, 1);
}

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-top: 24px;
}

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink-2);
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.47;
  letter-spacing: -0.011em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
}

h1, h2, h3, h4, p, ul, ol, dl, dd, figure { margin: 0; }
ul, ol { padding: 0; list-style: none; }
img, svg { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-decoration: none; }
strong { color: var(--ink); font-weight: 600; }
table { border-collapse: separate; }

::selection { background: rgba(41, 151, 255, 0.45); color: #fff; }

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

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip {
  position: absolute;
  left: 16px;
  top: -100px;
  z-index: 200;
  padding: 10px 16px;
  background: var(--ink);
  color: #000;
  border-radius: 999px;
  font-weight: 600;
}
.skip:focus { top: 16px; }

/* ---------- Liquid glass ---------- */
.glass {
  position: relative;
  isolation: isolate;
  background: var(--glass-fill);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow);
}

/* specular rim: a 1px gradient border that catches light top-left */
.glass::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  padding: 1px;
  border-radius: inherit;
  background: var(--glass-rim);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
}

/* ---------- Ambient light ----------
   One fixed layer behind everything. The color fields and the grain are all
   background images on this single box, so nothing inside it can move when
   the viewport changes size. (They used to be separate elements sized in
   vmax, which Lighthouse counted as a full-page layout shift.)
   Each field: a soft circle of color, centered near a corner. */
.ambient {
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    /* fine grain so the dark gradients never band (opacity is in the SVG) */
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.03'/%3E%3C/svg%3E"),
    radial-gradient(circle 50.9vmax at calc(100% - 10vmax) 100%, rgba(var(--amber), 0.3) 0%, rgba(var(--amber), 0) 62%),
    radial-gradient(circle 50.9vmax at 16vmax calc(100% + 2vmax), rgba(var(--moss), 0.42) 0%, rgba(var(--moss), 0) 62%),
    radial-gradient(circle 50.9vmax at calc(100% - 6vmax) 14vmax, rgba(var(--wine), 0.48) 0%, rgba(var(--wine), 0) 62%),
    radial-gradient(circle 50.9vmax at 12vmax 2vmax, rgba(var(--slate), 0.51) 0%, rgba(var(--slate), 0) 62%),
    radial-gradient(140% 90% at 50% -20%, #0c0f17 0%, var(--bg) 60%);
}

/* iPhone and iPad Safari fill the strips behind the status bar and the
   toolbar with the page's background color while those bars are expanded
   (at the top and bottom of the page). Fade the light fields out near those
   edges so the strips blend into the page instead of reading as black bars.
   The @supports test matches iOS/iPadOS Safari only; desktop is unchanged. */
@supports (-webkit-touch-callout: none) {
  .ambient {
    --edge-top: max(env(safe-area-inset-top, 0px), 56px);
    --edge-bottom: max(env(safe-area-inset-bottom, 0px), 88px);
    --edge-fade: linear-gradient(to bottom,
      transparent var(--edge-top),
      #000 calc(var(--edge-top) + 150px),
      #000 calc(100% - var(--edge-bottom) - 150px),
      transparent calc(100% - var(--edge-bottom)));
    -webkit-mask-image: var(--edge-fade);
    mask-image: var(--edge-fade);
  }
}

/* ---------- Navigation ----------
   A plain row at the top of the page that scrolls away with it. No capsule,
   no glass, not fixed: a floating pill near the top looked like Safari's own
   address bar on iPhone. */
.nav {
  position: absolute;
  top: calc(env(safe-area-inset-top, 0px) + 14px);
  left: 0;
  right: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: min(var(--max), 100% - 2 * var(--gutter));
  height: 48px;
  margin-inline: auto;
}

.nav-brand {
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--ink);
  white-space: nowrap;
}

.nav-links {
  display: flex;
  gap: 2px;
  margin-right: -14px; /* lines the last word up with the page edge */
}

.nav-links a {
  display: grid;
  place-items: center;
  height: 40px;
  padding-inline: 14px;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--ink-2);
  border-radius: 999px;
  transition: background-color 0.25s ease, color 0.25s ease;
}

.nav-links a:hover {
  color: var(--ink);
  background: rgba(255, 255, 255, 0.09);
}

/* ---------- Hero ---------- */
.hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  width: min(var(--max), 100% - 2 * var(--gutter));
  margin-inline: auto;
  padding-block: 116px 64px;
}


/* the photo, with a slow halo in the photo's own colors */
.avatar {
  --r: 46px;
  position: relative;
  isolation: isolate;
  width: 176px;
  aspect-ratio: 1;
  border-radius: var(--r);
}

.avatar img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--r);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12), 0 30px 60px -24px rgba(0, 0, 0, 0.8);
  transition: transform 0.6s var(--spring);
}

.avatar::before,
.avatar::after {
  content: "";
  position: absolute;
  background: conic-gradient(from var(--spin), #6f9bff, #e0678f, #f2b25c, #5fc497, #6f9bff);
  pointer-events: none;
  transition: transform 0.6s var(--spring), opacity 0.4s ease;
}

/* crisp 2px ring */
.avatar::before {
  inset: -3px;
  z-index: 0;
  border-radius: calc(var(--r) + 3px);
  opacity: 0.9;
}

/* soft glow */
.avatar::after {
  inset: -22px;
  z-index: -1;
  border-radius: calc(var(--r) + 22px);
  filter: blur(30px);
  opacity: 0.5;
}

@media (prefers-reduced-motion: no-preference) {
  .avatar::before,
  .avatar::after { animation: spin 14s linear infinite; }
}

@keyframes spin { to { --spin: 360deg; } }

/* a little wink on hover */
.avatar:hover img,
.avatar:hover::before { transform: rotate(-3deg) scale(1.03); }
.avatar:hover::after { opacity: 0.75; }

.eyebrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px 14px;
  margin-top: 30px;
}

/* role in the same colors as the glow around the photo */
.eyebrow-role {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  background: linear-gradient(90deg, #92b4ff, #ec93b0, #f4c785, #84d6b1, #92b4ff);
  background-size: 200% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

@media (prefers-reduced-motion: no-preference) {
  .eyebrow-role { animation: shimmer 10s linear infinite; }
}

@keyframes shimmer { to { background-position: -200% 0; } }

.eyebrow-loc {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding-left: 14px;
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.2;
  color: var(--ink-2);
  border-left: 1px solid var(--hair-2);
}

.eyebrow-loc svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

h1 {
  margin-top: 18px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3.25rem, 1.4rem + 7.6vw, 6.75rem);
  line-height: 1.02;
  letter-spacing: -0.04em;
  text-wrap: balance;
  color: var(--ink);
}

.hero-sub {
  max-width: 30rem;
  margin-top: 14px;
  font-family: var(--font-display);
  font-size: clamp(1.1875rem, 1rem + 0.8vw, 1.5rem);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: var(--ink-2);
  text-wrap: balance;
}

.actions {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr); /* three equal columns */
  gap: 10px;
  margin-top: 32px;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 48px;
  padding-inline: 22px;
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
  border-radius: 999px;
  transition: transform 0.35s var(--spring), background-color 0.25s ease, box-shadow 0.25s ease;
}

.btn svg { width: 18px; height: 18px; flex: none; }

.actions .btn { width: 100%; } /* fill the equal-width column */

.btn:hover { transform: translateY(-2px); }
.btn:active { transform: scale(0.96); transition-duration: 0.1s; }

.btn--solid {
  color: #000;
  background: var(--ink);
  box-shadow: 0 10px 30px -12px rgba(255, 255, 255, 0.45), inset 0 -1px 0 rgba(0, 0, 0, 0.12);
}
.btn--solid:hover { background: #fff; }

/* ---------- Sections ---------- */
.section {
  width: min(var(--max), 100% - 2 * var(--gutter));
  margin-inline: auto;
  padding-block: 48px;
}

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 24px;
}

.headline {
  font-family: var(--font-display);
  font-size: clamp(1.875rem, 1.4rem + 2vw, 2.75rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.03em;
  color: var(--ink);
}

.section-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--ink-2);
  white-space: nowrap;
  transition: color 0.2s ease;
}

.section-link svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.section-link:hover { color: var(--ink); }

/* ---------- About ----------
   Glass panel: two paragraphs, then a short facts list. The facts sit in a
   2x2 grid on phones, one row on tablets, and a side column on desktop. */
.about {
  display: grid;
  gap: 24px;
  padding: 24px 22px;
  border-radius: 30px;
}

.about-text {
  display: grid;
  align-content: center;
  gap: 14px;
  max-width: 44rem;
}

.about p { text-wrap: pretty; }

.about-lead {
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: -0.015em;
  color: var(--ink);
}

.about-facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px 16px;
  padding-top: 20px;
  border-top: 1px solid var(--hair);
}

.about-facts dt {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.about-facts dd {
  margin-top: 4px;
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.35;
  color: var(--ink);
}

/* ---------- Chips (shared) ---------- */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 14px;
}

.chips li {
  padding: 5px 11px;
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.3;
  color: var(--ink-2);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--hair);
  border-radius: 999px;
}

/* ---------- Experience ---------- */
.xp {
  padding: 22px 18px 4px;
  border-radius: 30px;
}

.group-label {
  margin-bottom: 18px;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.xp-list + .group-label {
  margin-top: 4px;
  padding-top: 22px;
  border-top: 1px solid var(--hair);
}

.xp-item {
  position: relative;
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  gap: 14px;
  padding-bottom: 26px;
}

/* vertical line from each role's icon down to the next */
.xp-item:not(:last-child)::before {
  content: "";
  position: absolute;
  left: 19.5px;
  top: 50px;
  bottom: 8px;
  width: 1px;
  background: linear-gradient(rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.04));
}

.xp-icon {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  color: var(--ink);
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0.05));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}

.xp-icon svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.xp-icon--now {
  color: #fff;
  background: linear-gradient(160deg, #5c97ff 0%, #2a62d6 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), 0 10px 24px -10px rgba(57, 135, 229, 0.8);
}

.xp-icon--edu {
  color: #fff;
  background: linear-gradient(160deg, #f0b25e 0%, #c47a1f 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), 0 10px 24px -10px rgba(201, 130, 40, 0.7);
}

.xp-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 2px 14px;
}

.xp-head h4 {
  font-family: var(--font-display);
  font-size: 1.1875rem;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.date {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.xp-sub {
  margin-top: 2px;
  font-size: 0.9375rem;
  color: var(--ink-2);
}

.xp-bullets {
  display: grid;
  gap: 8px;
  margin-top: 14px;
  max-width: 46rem;
}

.xp-bullets li {
  position: relative;
  padding-left: 16px;
  font-size: 0.9375rem;
  line-height: 1.5;
  text-wrap: pretty;
}

.xp-bullets li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--ink-3);
}

/* ---------- Projects ---------- */
.bento {
  display: grid;
  gap: 14px;
}

.card {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 10px 10px 20px;
  border-radius: 30px;
  transition: transform 0.6s var(--spring), box-shadow 0.4s ease;
}

/* the whole card opens the repo; the buttons sit above that link */
.card h3 a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
}

.viz {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 16px;
  min-height: 232px;
  padding: 16px;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 20px;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06), inset 0 1px 14px rgba(0, 0, 0, 0.3);
}

.viz-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ink);
}
.viz-head span + span { font-weight: 500; color: var(--ink-3); }

.viz-head .delta {
  padding: 3px 9px;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--up);
  background: rgba(48, 209, 88, 0.14);
  border-radius: 999px;
}

.card-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding-inline: 10px;
}

.kicker {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink-3);
}

.card h3 {
  margin-top: 6px;
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: 700;
  line-height: 1.18;
  letter-spacing: -0.025em;
  color: var(--ink);
}

.desc {
  margin-top: 8px;
  font-size: 0.9375rem;
  line-height: 1.5;
  text-wrap: pretty;
}

.card-links {
  position: relative;
  z-index: 4;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: auto;
  padding-top: 18px;
}

.btn-sm {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 36px;
  padding-inline: 15px;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--hair);
  border-radius: 999px;
  transition: transform 0.35s var(--spring), background-color 0.2s ease;
}

.btn-sm svg {
  width: 13px;
  height: 13px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.btn-sm:hover { background: rgba(255, 255, 255, 0.14); }
.btn-sm:active { transform: scale(0.95); transition-duration: 0.1s; }

.btn-sm--solid {
  color: #000;
  background: var(--ink);
  border-color: transparent;
}
.btn-sm--solid:hover { background: #fff; }

/* ---------- Chart: bars ----------
   Set the axis maximum on the chart: <div class="bars" style="--y-max: 8">.
   Each bar's height is its --v divided by --y-max. */
.bars {
  flex: 1;
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr);
  grid-template-rows: minmax(132px, 1fr) auto;
  gap: 8px;
  padding-top: 18px;
}

.bars-y { position: relative; }

.bars-y span {
  position: absolute;
  right: 0;
  bottom: var(--at);
  transform: translateY(50%);
  font-size: 0.6875rem;
  line-height: 1;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.bars-plot {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: space-around;
  border-bottom: 1px solid var(--hair-2);
  background-image: linear-gradient(to bottom, var(--hair) 1px, transparent 1px);
  background-size: 100% 50%;
}

.bar {
  position: relative;
  width: min(30px, 11%);
  height: calc(var(--v) / var(--y-max, 8) * 100%);
  border-radius: 8px 8px 3px 3px;
  background: linear-gradient(180deg, #6aa8ff 0%, #3577e0 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), 0 10px 24px -12px rgba(57, 135, 229, 0.9);
  transform-origin: bottom;
}

.bar b {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.bars-x {
  grid-column: 2;
  display: flex;
  justify-content: space-around;
  font-size: 0.6875rem;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.bars-x span { width: 30px; text-align: center; }

/* ---------- Chart: big number + split bar ---------- */
.big-number {
  font-family: var(--font-display);
  font-size: clamp(4.25rem, 3.6rem + 2.4vw, 5.5rem);
  font-weight: 700;
  line-height: 0.9;
  letter-spacing: -0.05em;
  color: var(--ink);
}

.split-bar {
  display: flex;
  gap: 3px;
  height: 10px;
}

.split-bar span {
  width: var(--p);
  border-radius: 999px;
  transform-origin: left center;
}
.split-rest { background: var(--gray-mark); }
.split-focus { background: var(--orange); }

.split-labels {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 10px;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--ink-2);
}

.split-labels span,
.legend li {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
}
.dot--blue { background: var(--blue); }
.dot--orange { background: var(--orange); }
.dot--green { background: var(--green); }
.dot--gray { background: var(--gray-mark); }

/* ---------- Chart: confusion matrix ---------- */
.cm-wrap {
  flex: 1;
  display: grid;
  place-items: center;
}

.cm { border-spacing: 5px; margin: -5px; }

.cm th {
  font-size: 0.6875rem;
  font-weight: 500;
  color: var(--ink-3);
  white-space: nowrap;
}

.cm thead th { padding-bottom: 2px; }
.cm tbody th { padding-right: 6px; text-align: right; }

.cm td {
  width: 76px;
  height: 52px;
  text-align: center;
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  border-radius: 14px;
}

.cm-hi {
  color: #fff;
  background: linear-gradient(160deg, #5c97ff, #2c66d8);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0 10px 20px -12px rgba(57, 135, 229, 0.9);
}

.cm-lo {
  color: var(--ink);
  background: rgba(255, 255, 255, 0.06);
  box-shadow: inset 0 0 0 1px var(--hair);
}

.mini-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  text-align: center;
}

.mini-stats div + div { border-left: 1px solid var(--hair); }

.mini-stats dt {
  font-size: 0.6875rem;
  font-weight: 500;
  color: var(--ink-3);
}

.mini-stats dd {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* ---------- Chart: scatter ---------- */
.scatter svg {
  width: 100%;
  height: auto;
  aspect-ratio: 480 / 220;
  overflow: visible;
}

.scatter .grid { stroke: var(--hair); stroke-width: 1; vector-effect: non-scaling-stroke; }
.scatter circle { stroke: rgba(0, 0, 0, 0.35); stroke-width: 0.8; }
.scatter .h2 { fill: var(--blue); filter: drop-shadow(0 0 3px rgba(57, 135, 229, 0.55)); }
.scatter .sy { fill: var(--orange); filter: drop-shadow(0 0 3px rgba(217, 89, 38, 0.55)); }
.scatter .li { fill: var(--green); filter: drop-shadow(0 0 3px rgba(25, 158, 112, 0.55)); }
.scatter .tr { fill: var(--gray-mark); }

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--ink-2);
}

/* ---------- Chart: dot plot with error bars ----------
   Set the axis range on the chart: <div class="dotplot" style="--x-min: 0.8; --x-max: 1">.
   Each row gets its mean and standard deviation: <li style="--m: 0.928; --sd: 0.024">.
   A dot plot doesn't need a zero baseline, so a zoomed axis is honest here. */
.dotplot {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.dp-rows li,
.dp-axis {
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr) 2.5rem;
  align-items: center;
  column-gap: 12px;
}

.dp-rows li {
  height: 34px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--ink-2);
}

.dp-rows li > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dp-rows b {
  font-weight: 600;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.dp-rows .dp-pick { color: var(--ink); }

/* track: quarter gridlines, so the rows join into one continuous grid */
.dp-track {
  position: relative;
  height: 100%;
  background: linear-gradient(to right, var(--hair) 1px, transparent 1px) 0 0 / 25% 100%;
  box-shadow: inset -1px 0 0 var(--hair);
}

/* error bar: mean ± sd */
.dp-track i {
  position: absolute;
  top: calc(50% - 1px);
  left: calc((var(--m) - var(--sd) - var(--x-min)) / (var(--x-max) - var(--x-min)) * 100%);
  width: calc(2 * var(--sd) / (var(--x-max) - var(--x-min)) * 100%);
  height: 2px;
  border-radius: 1px;
  background: rgba(255, 255, 255, 0.3);
}

.dp-track i::before,
.dp-track i::after {
  content: "";
  position: absolute;
  top: -4px;
  width: 2px;
  height: 10px;
  border-radius: 1px;
  background: inherit;
}
.dp-track i::before { left: 0; }
.dp-track i::after { right: 0; }

/* the mean */
.dp-track::after {
  content: "";
  position: absolute;
  top: 50%;
  left: calc((var(--m) - var(--x-min)) / (var(--x-max) - var(--x-min)) * 100%);
  width: 12px;
  height: 12px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: var(--ink-3);
  box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.45);
}

.dp-pick .dp-track i { background: rgba(57, 135, 229, 0.7); }
.dp-pick .dp-track::after {
  background: var(--blue);
  box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.45), 0 0 12px rgba(57, 135, 229, 0.8);
}

.dp-axis { margin-top: 6px; }

.dp-ticks {
  position: relative;
  height: 14px;
}

.dp-ticks span {
  position: absolute;
  left: var(--at);
  transform: translateX(-50%);
  font-size: 0.6875rem;
  line-height: 1;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* legend key for an error bar */
.whisker {
  position: relative;
  width: 16px;
  height: 2px;
  background: rgba(255, 255, 255, 0.4);
}
.whisker::before,
.whisker::after {
  content: "";
  position: absolute;
  top: -4px;
  width: 2px;
  height: 10px;
  background: inherit;
}
.whisker::before { left: 0; }
.whisker::after { right: 0; }

/* ---------- Chart: pipeline ---------- */
.flow {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 16px;
}

.flow-src {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
}

.flow-src li {
  padding: 4px 10px;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--ink-2);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--hair);
  border-radius: 999px;
}

/* one line from the sources into the first step */
.flow-src::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 100%;
  width: 1px;
  height: 16px;
  background: var(--hair-2);
}

.flow-steps {
  display: grid;
  gap: 6px;
}

.flow-steps li {
  position: relative;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 14px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--hair);
  border-radius: 12px;
}

.flow-steps li + li::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -7px;
  width: 1px;
  height: 6px;
  background: var(--hair-2);
}

.flow-steps span {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ink);
}

.flow-steps small {
  font-size: 0.75rem;
  color: var(--ink-3);
}

.flow-steps .flow-out {
  background: rgba(25, 158, 112, 0.16);
  border-color: rgba(25, 158, 112, 0.55);
}

/* ---------- Writing ----------
   Each post is its own glass card (same hover lift as the project cards).
   Thumbnails are 14:10, the ratio Substack uses for post previews. */
.posts {
  display: grid;
  gap: 14px;
}

.post {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: 14px;
  padding: 10px 10px 22px;
  border-radius: 30px;
  transition: transform 0.6s var(--spring), box-shadow 0.4s ease;
}

.post-thumb {
  grid-column: 1 / -1;
  width: 100%;
  aspect-ratio: 14 / 10;
  object-fit: cover;
  margin-bottom: 18px;
  border-radius: 20px; /* card radius 30 minus 10px padding */
  background: rgba(0, 0, 0, 0.3);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06);
}

.post h3 {
  grid-column: 1;
  align-self: center;
  padding-left: 10px;
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 1.1rem + 0.5vw, 1.5rem);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.025em;
  color: var(--ink);
  text-wrap: balance;
}

.post-desc {
  grid-column: 1 / -1;
  max-width: 40rem;
  margin-top: 8px;
  padding-inline: 10px;
  font-size: 0.9375rem;
  line-height: 1.5;
  text-wrap: pretty;
}

/* round arrow button. The arrow's stroke color is --ink-2, written into the
   SVG because CSS variables can't reach inside it. */
.post::after {
  content: "";
  grid-column: 2;
  grid-row: 2;
  align-self: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23d1d2d8' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 17 17 7M8 7h9v9'/%3E%3C/svg%3E") center / 15px no-repeat,
    rgba(255, 255, 255, 0.07);
  box-shadow: inset 0 0 0 1px var(--hair);
  transition: background-color 0.2s ease;
}

.post:hover::after { background-color: rgba(255, 255, 255, 0.14); }

/* ---------- Footer ---------- */
.footer {
  width: min(var(--max), 100% - 2 * var(--gutter));
  margin-inline: auto;
  padding-block: 24px calc(32px + env(safe-area-inset-bottom, 0px));
}

.footer-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding-top: 32px;
  border-top: 1px solid var(--hair);
}

.footer-inner p {
  font-size: 0.8125rem;
  color: var(--ink-3);
}

.social {
  display: flex;
  gap: 10px;
}

.social a {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  color: var(--ink-2);
  border-radius: 50%;
  transition: transform 0.35s var(--spring), color 0.2s ease;
}

.social a:hover {
  color: var(--ink);
  transform: translateY(-2px);
}
.social a:active { transform: scale(0.94); }

.social svg { width: 18px; height: 18px; }

/* ---------- Chart motion (where supported) ---------- */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .bar,
    .split-bar span {
      animation: grow-x linear both;
      animation-timeline: view();
      animation-range: entry 20% cover 40%;
    }
    .bar { animation-name: grow-y; }
  }
}

@keyframes grow-y { from { transform: scaleY(0.05); } }
@keyframes grow-x { from { transform: scaleX(0.05); } }

/* ==========================================================================
   Responsive
   ========================================================================== */

/* phones: the four section links fill the row. The name is left out because
   it's in large type right below in the hero. */
@media (max-width: 639px) {
  .nav-brand { display: none; }
  .nav-links {
    flex: 1;
    justify-content: space-between;
    margin-inline: -10px;
  }
  .nav-links a { padding-inline: 10px; }
}

/* phones: dates sit under the title so every entry lines up the same way */
@media (max-width: 559px) {
  .xp-head { flex-direction: column; align-items: flex-start; }
  .xp-head .date { order: 2; }
  .viz { min-height: 0; }
}

@media (max-width: 419px) {
  .nav-links a { font-size: 0.875rem; }
  .actions {
    width: 100%;
    gap: 8px;
  }
  .btn { padding-inline: 6px; font-size: 0.875rem; gap: 6px; }
}

@media (min-width: 640px) {
  :root { --gutter: 32px; }
}

@media (min-width: 720px) {
  .hero { padding-block: 148px 88px; }

  .avatar { --r: 60px; width: 232px; }

  .section { padding-block: 64px; }
  .section-head { margin-bottom: 32px; }

  .xp { padding: 30px 30px 8px; }
  .xp-item { grid-template-columns: 44px minmax(0, 1fr); gap: 18px; }
  .xp-icon { width: 44px; height: 44px; border-radius: 13px; }
  .xp-item:not(:last-child)::before { left: 21.5px; top: 54px; }
  .xp-head h4 { font-size: 1.3125rem; }

  .about { padding: 30px; }
  .about-facts { grid-template-columns: repeat(4, minmax(0, 1fr)); }

  .post {
    grid-template-columns: 15rem minmax(0, 1fr) auto;
    grid-template-rows: 1fr auto auto 1fr; /* centers the text against the thumbnail */
    column-gap: 28px;
    padding: 10px 26px 10px 10px;
  }
  .post-thumb { grid-column: 1; grid-row: 1 / -1; margin: 0; }
  .post h3 { grid-column: 2; grid-row: 2; padding: 0; }
  .post-desc { grid-column: 2; grid-row: 3; padding: 0; }
  .post::after { grid-column: 3; grid-row: 1 / -1; width: 40px; height: 40px; }

  /* tablet: two columns. Every card is the same size at every width. */
  .bento {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
  }

  /* cards in a row share figure and text rows */
  .card {
    display: grid;
    grid-row: span 2;
    grid-template-rows: subgrid;
    gap: 18px;
  }

  .card:hover,
  .post:hover {
    transform: translateY(-4px);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.2),
      0 1px 1px rgba(0, 0, 0, 0.35),
      0 34px 70px -24px rgba(0, 0, 0, 0.8);
  }
}

@media (min-width: 1024px) {
  :root { --gutter: 40px; }

  .hero { padding-block: 156px 96px; }
  .avatar { --r: 64px; width: 248px; }

  .section { padding-block: 80px; }

  .xp { padding: 36px 40px 12px; }

  .about {
    grid-template-columns: minmax(0, 1fr) 17rem;
    gap: 40px;
    padding: 36px 40px;
  }
  .about-facts {
    grid-template-columns: 1fr;
    align-content: center;
    gap: 20px;
    padding: 0 0 0 32px;
    border-top: 0;
    border-left: 1px solid var(--hair);
  }

  /* desktop: three equal columns */
  .bento { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px; }

  .viz { min-height: 248px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}
