/* shell.css — the site header and footer, for the React app AND every static
   page under /blog and /notes.

   Why its own file: the app's styles are compiled by Vite into a hashed bundle
   that plain HTML pages cannot reference by a stable path, and the blog and
   notes pages are plain HTML on purpose, because Google reads them directly.
   This small, unhashed file is the one place the header and footer are styled.

   The markup comes from src/site/links.json: the app renders it in App.tsx and
   Footer.tsx, and scripts/stamp-shell.mjs writes the same markup into every
   static page on each build.

   Literal values, not var(): the static pages define their own custom
   properties (their --ink is #1e293b, the app's is #0f172a), so reading a
   variable here would give the footer a different navy on the blog than in
   the app — the exact drift this file exists to end. Served no-cache by
   server.ts, so an edit reaches visitors on their next load. */

@font-face {
  font-family: 'Caroni';
  src: url('/Caroni-Regular.woff2') format('woff2');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

/* ── Header ─────────────────────────────────────────────────────────────── */

.site-header {
  position: sticky;
  top: 24px;
  z-index: 100;
  box-sizing: border-box;
  width: fit-content;
  max-width: calc(100% - 40px);
  margin: 24px auto 0;
  /* 0.97, not 0.85: at 0.85 scrolled content showed through the pill. */
  background: rgba(241, 245, 249, 0.97);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border: 1px solid rgba(0, 0, 0, 0.08);
  border-radius: 999px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.02);
  font-family: 'Raleway', 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  line-height: 1;
  text-align: left;
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.4s cubic-bezier(0.16, 1, 0.3, 1), margin 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.site-header *, .site-header *::before, .site-header *::after { box-sizing: border-box; }

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
  padding: 6px 16px;
}
.site-header__logo { display: block; line-height: 0; flex-shrink: 0; }
/* No width/height attributes on this img: an explicit height here plus
   width:auto is what keeps the logo's proportions. */
.site-header__logo img { display: block; height: 36px; width: auto; }

.site-header__nav { display: flex; align-items: center; gap: 6px; }

/* Text links carry the pressed-chip look the app's buttons use. */
.site-header__link {
  display: flex;
  align-items: center;
  height: 28px;
  margin: 0;
  padding: 0 12px;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  color: #0f172a;
  text-decoration: none;
  background: linear-gradient(180deg, #ffffff 0%, #f1f5f9 100%);
  border-radius: 8px;
  box-shadow: inset 0 1px 1px #ffffff, 0 3px 5px rgba(0, 0, 0, 0.05), 0 0 0 1px rgba(0, 0, 0, 0.1), 0 4px 0 #cbd5e1;
  transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.15s, color 0.15s;
}
.site-header__link:hover { transform: translateY(-1px); }
.site-header__link:active {
  transform: translateY(3px);
  box-shadow: inset 0 3px 6px rgba(0, 0, 0, 0.05), 0 0 0 1px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.5);
  color: #047857;
}
/* The section you are in. #047857 on the chip face is 5.5:1. */
.site-header__link[aria-current="page"] {
  color: #047857;
  box-shadow: inset 0 1px 1px #ffffff, 0 3px 5px rgba(0, 0, 0, 0.05), 0 0 0 1px #10b981, 0 4px 0 #cbd5e1;
}

/* Primary action. Solid #047857: white on the brighter #10b981 is 2.5:1 and
   fails contrast; on #047857 it is 5.5:1. Hover lifts rather than lightens. */
.site-header__cta {
  display: flex;
  align-items: center;
  height: 28px;
  margin: 0;
  padding: 0 14px;
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  color: #ffffff;
  text-decoration: none;
  background: #047857;
  border-radius: 999px;
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.4), 0 3px 5px rgba(5, 150, 105, 0.25), 0 0 0 1px rgba(5, 150, 105, 0.6), 0 4px 0 #065f46;
  transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.15s, background 0.15s;
}
.site-header__cta:hover {
  transform: translateY(-1px);
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.4), 0 5px 8px rgba(5, 150, 105, 0.3), 0 0 0 1px rgba(5, 150, 105, 0.6), 0 5px 0 #065f46;
}
.site-header__cta:active { transform: translateY(3px); background: #065f46; }

.site-header a:focus-visible { outline: 3px solid #059669; outline-offset: 2px; }

/* Phones: a full-width bar pinned to the top instead of a floating pill. */
@media (max-width: 640px) {
  .site-header {
    top: 0;
    width: 100%;
    max-width: 100%;
    margin: 0;
    border-radius: 0 0 14px 14px;
    background: rgba(241, 245, 249, 0.98);
  }
  .site-header__inner { gap: 10px; padding: 6px 12px; }
  .site-header__logo img { height: 28px; }
  .site-header__nav { gap: 4px; }
  .site-header__link { padding: 0 8px; }
  .site-header__cta { padding: 0 11px; }
}

/* ── Footer ─────────────────────────────────────────────────────────────── */

.aipen-footer-band {
  box-sizing: border-box;
  width: 100%;
  flex-shrink: 0;
  margin-top: 40px;
  background: #0f172a;
  color: #94a3b8;
  font-family: 'Caroni', cursive;
  font-size: 0.95rem;
  line-height: 1.5;
  text-align: left;
}
.aipen-footer-band *, .aipen-footer-band *::before, .aipen-footer-band *::after { box-sizing: border-box; }

.aipen-footer { max-width: 1100px; margin: 0 auto; padding: 52px 20px 36px; }

/* Brand column is wider so its blurb reads as three tidy lines; Blog is widest
   because its links are full article titles. */
.aipen-footer-grid {
  display: grid;
  grid-template-columns: 1.5fr 0.85fr 0.95fr 1fr 0.85fr 1.6fr;
  gap: 36px 28px;
  align-items: start;
}
@media (max-width: 900px) {
  .aipen-footer-grid { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
}
@media (max-width: 560px) {
  .aipen-footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 20px; }
}

.aipen-footer__brand { min-width: 0; }
/* 34px logo + 8px margin = 42px, which is exactly heading (26px) + heading
   margin (4px) + column gap (12px), so the blurb starts on the same line as
   the first link in every other column. Change one and change the other. */
.aipen-footer__logo { display: block; height: 34px; width: auto; margin: 0 0 8px; }

/* Selectors carry the band class on purpose: several static pages style bare
   p {} and h4 {}, and these must win over them. */
.aipen-footer-band .aipen-footer__blurb {
  margin: 0 0 16px;
  max-width: 250px;
  font-size: inherit;
  line-height: 1.55;
  color: inherit;
}
.aipen-footer-band .aipen-footer__copy { margin: 0; font-size: 0.85rem; line-height: 1.5; color: inherit; opacity: 0.8; }

.aipen-footer__col { display: flex; flex-direction: column; gap: 12px; min-width: 0; }

/* Weight 400: Caroni ships one weight, so anything heavier is faux bold. */
.aipen-footer-band .aipen-footer__heading {
  margin: 0 0 4px;
  font-family: 'Caroni', cursive;
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.625;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #f9f9f9;
}

.aipen-footer-band .aipen-footer-link {
  font-family: 'Caroni', cursive;
  font-size: 1.02rem;
  font-weight: 400;
  line-height: 1.3;
  color: #94a3b8;
  text-decoration: none;
  transition: color 0.15s;
}
.aipen-footer-band .aipen-footer-link:hover { color: #34d399; }

.aipen-footer__social { display: flex; gap: 12px; }
.aipen-social-icon {
  display: inline-flex;
  align-items: center;
  color: #94a3b8;
  transition: color 0.15s, transform 0.15s;
}
.aipen-social-icon:hover { color: #34d399; transform: translateY(-2px); }
.aipen-social-icon svg, .aipen-social-icon img { display: block; width: 22px; height: 22px; }

.aipen-footer-band a:focus-visible { outline: 3px solid #6ee7b7; outline-offset: 2px; border-radius: 4px; }

/* ── Short pages (static pages only) ────────────────────────────────────── */

/* On a page shorter than the window, the footer used to stop where the content
   ended and leave a strip of page background beneath it — /notes/ and /blog/ on
   a tall or zoomed-out screen. Now <body> is a column at least as tall as the
   window, and the empty .shell-push that stamp-shell.mjs writes just before the
   footer takes the leftover height. flex-grow only hands out FREE space, so on
   a long page the spacer is 0px tall and nothing moves.

   Scoped with :has(> .aipen-footer-band): only a page whose footer band is a
   direct child of <body> — the static pages — is affected. In the app the band
   sits deep inside .main-area, which has its own spacer in App.tsx. A browser
   without :has() simply keeps the old layout. */
body:has(> .aipen-footer-band) {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}
body:has(> .aipen-footer-band) > .shell-push { flex: 1 0 0; }

/* In a flex column, margin: 0 auto stops an element stretching and shrinks it
   to its content, so a centred main/article column would narrow on a page
   whose content is short. width: 100% restores ordinary block sizing; each
   page's own max-width and auto margins still centre it exactly as before. */
body:has(> .aipen-footer-band) > main,
body:has(> .aipen-footer-band) > article { width: 100%; }

@media print {
  .site-header, .aipen-footer-band, .shell-push { display: none !important; }
  /* No window-height body in print, or a short page would print a blank tail. */
  body:has(> .aipen-footer-band) { min-height: 0 !important; }
}

@media (prefers-reduced-motion: reduce) {
  .site-header, .site-header__link, .site-header__cta, .aipen-footer-link, .aipen-social-icon { transition: none; }
}
