/* ---------------------------------------------------------------------------
   projects.santoshk.dev

   This site is a sibling of santoshk.dev, which is Hugo + Blowfish (Tailwind v4).
   Nothing here depends on that build. The tokens below reproduce Blowfish's
   `slate` colour scheme by hand, using the SAME variable names and the SAME
   space-separated-RGB-triplet convention, so the `.cv-*` rules copied out of
   santoshk.dev/assets/css/custom.css work unchanged.

   If you restyle the main site, the order of business is:
     1. change the triplets in :root / .dark below to match,
     2. re-copy the `.cv-*` block from that file,
     3. leave the `.pj-*` block alone — it is written in terms of the tokens.
   --------------------------------------------------------------------------- */

/* ===========================================================================
   1. TOKENS
   Tailwind `slate` for primary, Tailwind `gray` for neutral/secondary — the
   exact values Blowfish's colorScheme: slate compiles to.
   =========================================================================== */

:root {
  --color-neutral: 255, 255, 255;
  --color-neutral-50: 249, 250, 251;
  --color-neutral-100: 243, 244, 246;
  --color-neutral-200: 229, 231, 235;
  --color-neutral-300: 209, 213, 219;
  --color-neutral-400: 156, 163, 175;
  --color-neutral-500: 107, 114, 128;
  --color-neutral-600: 75, 85, 99;
  --color-neutral-700: 55, 65, 81;
  --color-neutral-800: 31, 41, 55;
  --color-neutral-900: 17, 24, 39;

  --color-primary-50: 248, 250, 252;
  --color-primary-100: 241, 245, 249;
  --color-primary-200: 226, 232, 240;
  --color-primary-300: 203, 213, 225;
  --color-primary-400: 148, 163, 184;
  --color-primary-500: 100, 116, 139;
  --color-primary-600: 71, 85, 105;
  --color-primary-700: 51, 65, 85;
  --color-primary-800: 30, 41, 59;
  --color-primary-900: 15, 23, 42;

  --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
    "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  --font-mono: ui-monospace, "SF Mono", "Cascadia Code", Consolas, monospace;
}

/* ===========================================================================
   2. RESET + PAGE SHELL
   Blowfish puts its shell on <body> as Tailwind utilities. We have no Tailwind,
   so the same values are written directly. 50.5rem = the CV homepage's 760px
   measure + 2 x 1.5rem padding, matching `body[class]:has(.cv)` upstream.
   =========================================================================== */

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

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
  margin: 0 auto;
  max-width: 50.5rem;
  padding-left: 1.5rem;
  padding-right: 1.5rem;
  min-height: 100vh;
  display: flex;
  flex-direction: column;

  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.75;

  background-color: rgb(var(--color-neutral));
  color: rgb(var(--color-neutral-900));
}

/* The CV homepage lifts the dark background off Blowfish's site-wide
   neutral-800 to a Nord polar night. This site is that page's sibling, so it
   takes the lifted value rather than the theme default. */
.dark body { background-color: rgb(46, 52, 64); color: rgb(var(--color-neutral)); }

h1, h2, h3, p, ul, ol { margin: 0; }
img { max-width: 100%; height: auto; }
button { font: inherit; color: inherit; background: none; border: none; padding: 0; cursor: pointer; }

/* Visually hidden but available to assistive tech — Tailwind's `sr-only`. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

/* Keyboard focus. Blowfish leans on the browser default; make it explicit and
   accent-coloured so it is visible against both backgrounds. */
:focus-visible {
  outline: 2px solid rgb(var(--color-primary-600));
  outline-offset: 2px;
  border-radius: 0.125rem;
}
.dark :focus-visible { outline-color: rgb(var(--color-primary-400)); }

/* Skip link — mirrors Blowfish's, which sits off-canvas until focused. */
.skip-link {
  position: absolute;
  left: 50%;
  transform: translate(-50%, -3rem);
  z-index: 60;
  padding: 0.25rem 0.75rem;
  font-size: 0.875rem;
  border-radius: 0 0 0.5rem 0.5rem;
  background: rgb(var(--color-primary-200));
  color: rgb(var(--color-primary-700));
  text-decoration: none;
  transition: transform 0.15s;
}
.dark .skip-link { background: rgb(var(--color-neutral-600)); color: rgb(var(--color-neutral)); }
.skip-link:focus { transform: translate(-50%, 0); }

/* ===========================================================================
   3. HEADER / FOOTER
   The `SK.` monogram and nav reproduce santoshk.dev's header so the two sites
   share one piece of chrome. Nav links point back at the main site; Projects is
   the current page.
   =========================================================================== */

.main-menu {
  display: flex;
  align-items: center;
  width: 100%;
  gap: 0.5rem;
  padding: 0.25rem 0.25rem 0.25rem 0;
}

/* Copied from santoshk.dev/assets/css/custom.css */
.site-mark {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 1.1rem;
  line-height: 1;
  flex-shrink: 0;
  color: inherit;
  text-decoration: none;
}
.site-mark-dot { color: rgb(var(--color-primary-600)); }
.dark .site-mark-dot { color: rgb(var(--color-primary-400)); }

.main-nav {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  height: 3rem;
  margin-left: auto;
}
.main-nav a {
  font-size: 1rem;
  font-weight: 500;
  color: inherit;
  text-decoration: none;
}
.main-nav a:hover { color: rgb(var(--color-primary-600)); }
.dark .main-nav a:hover { color: rgb(var(--color-primary-400)); }

/* Current page. Blowfish has no equivalent (its nav never marks state), so this
   is additive — it earns its place here because this site IS the Projects item
   and would otherwise give the visitor no orientation at all. */
.main-nav a[aria-current="page"] {
  color: rgb(var(--color-primary-600));
  text-decoration: underline;
  text-underline-offset: 0.35rem;
  text-decoration-thickness: 2px;
}
.dark .main-nav a[aria-current="page"] { color: rgb(var(--color-primary-400)); }

#appearance-switcher { display: flex; align-items: center; color: inherit; }
#appearance-switcher:hover { color: rgb(var(--color-primary-600)); }
.dark #appearance-switcher:hover { color: rgb(var(--color-primary-400)); }
#appearance-switcher svg { width: 1rem; height: 1rem; fill: currentColor; }
#appearance-switcher .icon-sun { display: none; }
.dark #appearance-switcher .icon-moon { display: none; }
.dark #appearance-switcher .icon-sun { display: block; }

/* Nav collapses to a wrapped row on narrow screens. Blowfish swaps in a
   full-screen checkbox-driven drawer at this breakpoint; with four links and no
   search there is nothing here worth hiding behind a hamburger. */
@media (max-width: 34rem) {
  .main-menu { flex-wrap: wrap; gap: 0.75rem; }
  .main-nav { width: 100%; margin-left: 0; height: auto; gap: 1rem; flex-wrap: wrap; }
  .main-nav a { font-size: 0.9rem; }
}

.site-footer { margin-top: auto; padding: 2.5rem 0; }
.site-footer > div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.site-footer p { font-size: 0.875rem; color: rgb(var(--color-neutral-500)); }
.dark .site-footer p { color: rgb(var(--color-neutral-400)); }
.site-footer .footer-meta { font-size: 0.75rem; }
.site-footer a { color: inherit; text-decoration: none; }
.site-footer a:hover { color: rgb(var(--color-primary-500)); text-decoration: underline; }

/* ===========================================================================
   4. THE .cv-* SYSTEM
   Copied from santoshk.dev/assets/css/custom.css and kept in its original
   order. Do not "improve" these — divergence here is what would make the two
   sites stop looking like one site. Only the two Blowfish-specific overrides
   (`body[class]:has(.cv)` and `.dark body:has(.cv)`) are omitted; they existed
   to out-specify Tailwind utilities that do not exist here, and their values
   are applied to `body` in section 2 instead.
   =========================================================================== */

.cv {
  --cv-text: rgb(var(--color-neutral-800));
  --cv-muted: rgb(var(--color-neutral-500));
  --cv-accent: rgb(var(--color-primary-600));
  --cv-border: rgb(var(--color-neutral-200));
  --cv-elevated: rgb(var(--color-neutral-50));

  color: var(--cv-text);
  font-size: 1rem;
  line-height: 1.75;
}

.dark .cv {
  --cv-text: rgb(var(--color-neutral-200));
  --cv-muted: rgb(var(--color-neutral-400));
  /* Elevated and border step *up* from the lightened page background, so pills
     and cards lift off it instead of sinking into it. */
  --cv-accent: rgb(var(--color-primary-400));
  --cv-border: rgb(var(--color-neutral-600));
  --cv-elevated: rgb(var(--color-neutral-700));
}

.cv a { color: var(--cv-accent); text-decoration: none; }
.cv a:hover { text-decoration: underline; }
.cv p { margin: 0 0 1rem; }

/* ---------- Hero ---------- */
.cv-hero { padding: 1rem 0 2.5rem; }
.cv-eyebrow {
  color: var(--cv-accent);
  font-family: var(--font-mono);
  font-size: .9rem;
  margin: 0 0 .5rem !important;
}
.cv-name { font-size: 2.6rem; font-weight: 800; margin: 0 0 .25rem; line-height: 1.15; }
.cv-role { color: var(--cv-muted); font-size: 1.2rem; margin: 0 0 1rem !important; }

.cv-actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.5rem; }
.cv-btn {
  display: inline-block;
  padding: .6rem 1.25rem;
  border-radius: .5rem;
  font-size: .9rem;
  font-weight: 600;
}
.cv-btn:hover { text-decoration: none; }
/* Selectors are qualified with `a` so they outrank the generic `.cv a` colour
   rule above — otherwise the primary button's label inherits the accent colour
   and becomes invisible against its own accent background. */
.cv a.cv-btn-primary { background: var(--cv-accent); color: rgb(var(--color-neutral)); }
.dark .cv a.cv-btn-primary { color: rgb(var(--color-neutral-900)); }
.cv a.cv-btn-primary:hover { opacity: .9; }
.cv a.cv-btn-ghost { border: 1px solid var(--cv-border); color: var(--cv-text); }
.cv a.cv-btn-ghost:hover { border-color: var(--cv-accent); color: var(--cv-accent); }

/* ---------- Sections ---------- */
.cv-section { padding: 2.5rem 0; border-top: 1px solid var(--cv-border); }
.cv-section-title {
  display: flex;
  align-items: center;
  gap: .75rem;
  font-size: 1.4rem;
  font-weight: 700;
  margin: 0 0 1.5rem;
}
.cv-tag {
  font-family: var(--font-mono);
  font-size: .8rem;
  color: var(--cv-accent);
  border: 1px solid var(--cv-border);
  border-radius: .375rem;
  padding: .1rem .5rem;
}
.cv-lead { color: var(--cv-muted); }

/* ---------- Writing-style list ----------
   Used here by the "More work" list, which is the same component as the CV
   homepage's writing list: a baseline-aligned row with a flush-right mono
   column, hairline-separated. */
.cv-writing { list-style: none; margin: 0; padding: 0; }
.cv-writing li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: .75rem 0;
  border-bottom: 1px solid var(--cv-border);
}
.cv-writing li:first-child { border-top: 1px solid var(--cv-border); }
.cv-writing a { color: var(--cv-text); }
.cv-writing a:hover { color: var(--cv-accent); text-decoration: none; }
.cv-writing-date {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: .78rem;
  color: var(--cv-muted);
}
.cv-more { margin: 1.25rem 0 0 !important; font-size: .9rem; }

/* ---------- Contact ---------- */
.cv-links { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.25rem; }
.cv-links a {
  background: var(--cv-elevated);
  border: 1px solid var(--cv-border);
  padding: .5rem 1rem;
  border-radius: .5rem;
  color: var(--cv-text);
  font-size: .9rem;
}
.cv-links a:hover { border-color: var(--cv-accent); color: var(--cv-accent); text-decoration: none; }

/* ===========================================================================
   5. .pj-* — PROJECT COMPONENTS
   The only new design work. Everything is expressed in the .cv-* tokens, and
   the geometry is lifted from existing .cv-* components wherever one exists:
   chips reuse .cv-pills, the tail list reuses .cv-writing, card hover reuses
   .cv-links a:hover. No shadows and no lift — the CV has neither.
   =========================================================================== */

/* ---------- Dark-mode contrast on the elevated surface ----------
   Section 4's tokens are tuned against the page background. On the elevated
   fill (--cv-elevated, neutral-700 #374151) two of them fall short of WCAG AA
   for body text in dark mode, measured:

     --cv-muted  #9ca3af on #374151 = 4.06:1  (needs 4.5)
     --cv-accent #94a3b8 on #374151 = 4.02:1  (needs 4.5)

   Re-declaring the two tokens on the .pj-* surfaces that use that fill fixes
   every descendant — meta lines, stack pills, card links, filter counts, the
   notice — because the rules read tokens instead of hard-coding colours.
   Section 4 is not touched. Light mode already passes (4.63:1 and 7.25:1) and
   is left alone.

     --cv-muted  -> neutral-300  #d1d5db on #374151 = 7.00:1
     --cv-accent -> primary-300  #cbd5e1 on #374151 = 6.94:1

   Both stay comfortable against the page background too (8.48:1 and 8.41:1),
   so nothing outside these surfaces shifts. Border and background pairs are
   deliberately NOT adjusted: they are hairline separators inherited verbatim
   from santoshk.dev, and matching that site outranks the non-text threshold.

   Scoped to .pj-* components only, for the same reason. `.cv-links a:hover`
   puts the same accent on the same fill (4.02:1), but that pill is section 4's
   and exists on santoshk.dev too — overriding it here would make the two sites
   diverge on hover, which is a bigger loss than the shortfall. It needs fixing
   upstream, in both sites at once, not patched on one side. */
.dark .pj-card,
.dark .pj-filter,
.dark .pj-notice {
  --cv-muted: rgb(var(--color-neutral-300));
  --cv-accent: rgb(var(--color-primary-300));
}

/* ---------- Site notice ----------
   Rendered only when meta.notice is set in data/projects.json, so these rules
   go unused the moment that key is deleted. Deliberately quiet: footnote-sized
   text in the muted colour, a hairline border and the same elevated fill the
   cards and contact pills already use. No warning colour, no animation, no
   lift — the site is unfinished, not broken. */
.pj-notice {
  display: flex;
  align-items: baseline;
  gap: .55rem;
  /* !important for the same reason as .pj-status and .pj-card-blurb: `.cv p`
     in section 4 out-specifies a single class. */
  margin: 1.25rem 0 0 !important;
  padding: .6rem .85rem;
  background: var(--cv-elevated);
  border: 1px solid var(--cv-border);
  border-radius: .5rem;
  font-size: .85rem;
  line-height: 1.6;
  color: var(--cv-muted);
}
.pj-notice-mark { flex-shrink: 0; font-size: .9rem; line-height: 1.6; }
/* Same mono treatment as .pj-role and .cv-tag, so the label reads as part of the
   existing vocabulary rather than as a new kind of thing. */
.pj-notice-label {
  font-family: var(--font-mono);
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .06em;
}
.pj-notice-label::after { content: " \00b7"; }

/* ---------- Filter bar ---------- */
/* Emitted with the `hidden` attribute; app.js removes it on boot. With JS off
   the control never appears and every card stays visible. */
.pj-filters[hidden] { display: none; }
.pj-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin-bottom: 1.75rem;
}
.pj-filter {
  background: var(--cv-elevated);
  border: 1px solid var(--cv-border);
  border-radius: 999px;
  padding: .35rem .85rem;
  font-size: .85rem;
  color: var(--cv-text);
  line-height: 1.4;
  transition: border-color .15s, color .15s;
}
.pj-filter:hover { border-color: var(--cv-accent); color: var(--cv-accent); }
.pj-filter[aria-pressed="true"] {
  border-color: var(--cv-accent);
  color: var(--cv-accent);
  font-weight: 600;
}
.pj-filter-count {
  font-family: var(--font-mono);
  font-size: .72rem;
  color: var(--cv-muted);
  margin-left: .35rem;
}
.pj-filter[aria-pressed="true"] .pj-filter-count { color: inherit; }

.pj-status { font-size: .85rem; color: var(--cv-muted); margin: 0 0 1.25rem !important; }

/* ---------- Card grid ---------- */
.pj-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
  gap: 1.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

.pj-card {
  display: flex;
  flex-direction: column;
  background: var(--cv-elevated);
  border: 1px solid var(--cv-border);
  border-radius: .5rem;
  padding: 1.25rem;
  transition: border-color .15s;
}
.pj-card:hover { border-color: var(--cv-accent); }
.pj-card[hidden] { display: none; }

.pj-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .75rem;
  margin-bottom: .35rem;
}
.pj-card h3 { font-size: 1.05rem; font-weight: 700; margin: 0; line-height: 1.4; }

/* Role marker. `work` is the one that carries information a visitor acts on —
   it explains why a card has no source link — so only it gets a visible label. */
.pj-role {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--cv-muted);
  border: 1px solid var(--cv-border);
  border-radius: .375rem;
  padding: 0 .4rem;
  line-height: 1.6;
}

.pj-card-meta {
  font-family: var(--font-mono);
  font-size: .78rem;
  color: var(--cv-muted);
  margin: 0 0 .75rem !important;
}

.pj-card-blurb { margin: 0 0 1rem !important; font-size: .95rem; }

/* Pushes the stack + links to the bottom so cards of unequal blurb length
   still line their footers up across a row. */
.pj-card-foot { margin-top: auto; }

.pj-stack {
  list-style: none;
  margin: 0 0 .85rem;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
}
.pj-stack li {
  font-family: var(--font-mono);
  font-size: .72rem;
  color: var(--cv-muted);
  border: 1px solid var(--cv-border);
  border-radius: .375rem;
  padding: .05rem .4rem;
  background: transparent;
}

.pj-card-links { display: flex; flex-wrap: wrap; gap: 1rem; }
.pj-card-links a { font-size: .85rem; font-weight: 500; }
.pj-card-links a::after { content: " \2192"; }

/* Stated where a repository is deliberately not linked, so the absence reads as
   a decision rather than an oversight. */
.pj-card-note { font-size: .8rem; color: var(--cv-muted); font-style: italic; }

/* ---------- Tail list ----------
   The list itself is `.cv-writing` (section 4) — same component as the CV
   homepage's writing list. Only the per-item pieces are new. */
.pj-more-title { color: var(--cv-text); font-weight: 500; }
a.pj-more-title:hover { color: var(--cv-accent); text-decoration: none; }
.pj-more-blurb { color: var(--cv-muted); font-size: .85rem; font-weight: 400; }

/* ---------- Responsive ---------- */
@media (max-width: 34rem) {
  .cv-name { font-size: 2.1rem; }
  .cv-writing li { flex-direction: column; gap: .25rem; }
  .pj-grid { grid-template-columns: 1fr; }
}

/* Respect a reduced-motion preference — the only transitions here are colour
   fades, but the smooth scroll is worth dropping. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition-duration: 0.01ms !important; }
}

@media print {
  .main-nav, .pj-filters, .skip-link, .pj-status { display: none !important; }
  body { max-width: none; }
  .pj-card { break-inside: avoid; }
}
