/* Shared site chrome — blue/cream/Rubik direction from the Figma home page,
   now applied to every page (not just Home). This is the single source of
   truth for the header/nav, footer, and colour variables. cv.css @imports
   this file for the chrome and adds only the resume-specific rules on top;
   every other page (index/about/work/blog) loads this file directly and
   adds its own content rules below the import line in this same file, so
   there's one place to change the header/nav/footer instead of four.

   Colours pulled directly from the Home page in Figma (2026-08 pass):
     blue  #2667fe (background — bulb.js repoints this between the dark-mode
           and light-mode background colour on click; see js/bulb.js. The
           name is a holdover from when dark mode was blue — light mode is
           now a very light grey, not blue)
     cream #fff3b7 (text/links/headings — the site's one text colour.
           bulb.js also repoints this, between cream for dark mode and
           --ink for light mode, so text stays legible against whichever
           background is active. --muted/--border below are derived from
           --cream via color-mix() so they follow it automatically)
     yellow #f7da50 (bulb — sparing highlight only, unchanged from earlier pass)
     ink   #232323 (light-mode text colour, via bulb.js; also used directly
           for print — see the print block at the bottom) */

:root {
  --blue: #2667fe;
  --cream: #fff3b7;
  --yellow: #f7da50;
  --ink: #232323;
  --muted: color-mix(in srgb, var(--cream) 65%, transparent); /* de-emphasised
    text — derived from --cream rather than a fixed colour, so it tracks
    whichever text colour bulb.js has set (cream in dark mode, ink in light
    mode) instead of going stale/washed-out when the theme switches */
  --paper: #ffffff;
  --border: color-mix(in srgb, var(--cream) 25%, transparent); /* borders/
    dividers — same reasoning as --muted: derived from --cream so it stays
    visible against whichever background colour is active */
  --max-width: 44rem;
  --font-body: "Rubik", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

html { color-scheme: light; }

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--cream);
  background: var(--blue);
  line-height: 1.6;
}

/* Body text and links are both cream now, so links need their own visual
   marker (underline) rather than relying on a colour difference — colour
   alone stopped working once every page's text became one colour. */
a { color: var(--cream); text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--cream) 50%, transparent); }
a:hover { text-decoration-color: currentColor; }

/* Top nav — solid blue bar, cream links, centred. Spacing (72px gaps) and
   the home-lottie icon match the Figma "home-light" frame's "top-nav"
   node exactly (js/home-nav.js + js/home-data.js render the lottie). */

/* Cross-document view transitions: smooths the visual cut between full
   page loads on this plain multi-page site (no fetch/router involved —
   still genuine full navigations, just bridged with a native browser
   crossfade instead of a hard cut). Naming .site-header/.bulb-toggle the
   same on every page tells the browser to treat them as one continuous
   element across the navigation rather than an old one vanishing and a
   new one popping in. Chromium-only for now; unsupported browsers just
   ignore this block and navigate exactly as before — and file://'s
   same-origin rules for this feature haven't been verified on this site
   specifically, so treat it as a bonus layer on top of the real fixes
   (self-hosted lottie.min.js, the <head> preload hint, and no longer
   blocking navigation on the click clip), not the fix itself. */
@view-transition {
  navigation: auto;
}

.site-header {
  view-transition-name: site-header;
  background: var(--blue);
  padding: 1.25rem 1.5rem;
  position: relative; /* anchors .nav-menu/.nav-toggle's absolute
    positioning (right: 1.5rem) to the header's own true edges — the full
    page width, since .site-header has no side margin of its own, just
    this padding — rather than to .site-header-inner's 64rem-capped,
    centred box below it. That distinction only shows up once the
    viewport's wider than ~1072px (64rem + this padding): below that,
    site-header-inner always stretches to fill the same width anyway, so
    moving this here doesn't change anything at mobile sizes, but it's
    what makes .nav-menu's right: 1.5rem actually match the bulb's own
    left: 1.5rem (position: absolute with no positioned ancestor, so its
    containing block is still viewport-width, same as when it was fixed)
    at every width instead of drifting apart on a wide screen. */
  z-index: 15; /* without this, position:relative alone doesn't create a
    stacking context (z-index stays auto), so the mobile dropdown menu
    inside it (.nav-menu, z-index: 10) was only being compared against
    page content back at the root level — where .hero-copy's waving emoji
    (animated via transform, which creates its own implicit stacking
    context) could paint above it. Explicitly promoting the whole header
    fixes that for anything on the page, while staying below .bulb-toggle
    (z-index: 20), which is meant to sit on top of the header. */
}
.site-header-inner {
  max-width: 64rem;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 1rem;
}
/* nav is a 3-column grid — 1fr / auto / 1fr — so Home (.nav-primary)
   sits in the centre column, genuinely centred on the nav's own full
   width rather than just centred relative to whatever's next to it.
   width: 100% is what gives the two 1fr spacer columns something to
   actually distribute — without it, nav would only be as wide as its own
   content needs and the "spacers" would collapse to nothing.
   .nav-menu (CV/Contact — Animation/Illustration are hidden out of it
   further down; their pages still exist, still linked from Home's own
   showcase sections, see css/home.css) isn't a grid column at all though:
   it's pulled out to position: absolute (see .site-header/.nav-menu
   below) so it can sit flush against the header's true right edge,
   matching the bulb's left edge exactly, instead of the right edge of
   this grid — which, once .site-header-inner hits its own 64rem cap on a
   wide screen, stops being the same place. */
.site-header nav {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  width: 100%;
}
.nav-primary {
  grid-column: 2;
  justify-self: center;
}
.nav-menu {
  position: absolute;
  right: 5.5rem; /* was 4rem — pulled in further still */
  top: 50%;
  transform: translateY(-50%);
}
/* Animation and Illustration hidden from the top nav (still real, linked
   pages — see the comment above — just not in this menu right now). Always
   the first two <li>s in .nav-menu across every page, so one rule here
   covers the whole site instead of editing all 17 pages' markup. */
.nav-menu li:nth-child(1),
.nav-menu li:nth-child(2) {
  display: none;
}
.site-header nav ul {
  display: flex;
  align-items: center;
  gap: 32px; /* was 72px — decreased for CV/Contact, the only two links
    left visible in .nav-menu now that Animation/Illustration are hidden;
    .nav-primary only ever has the one item so this value doesn't show up
    there either way */
  list-style: none;
  margin: 0;
  padding: 0;
}
.site-header nav a {
  display: inline-block;
  color: var(--cream);
  font-weight: 600;
  text-decoration: none;
  opacity: 0.85;
  /* Springy "pop" on hover (overshoot easing) and a quick squash while
     held down — every nav link gets both, home's icon included. Home's
     icon also plays its own squash-and-back Lottie clip on click
     (js/home-nav.js) as a bonus flourish, but doesn't wait for it to
     finish before following the link — this CSS squash is what gives
     every link (home included) its instant, un-delayed press feedback. */
  transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.site-header nav a:hover { opacity: 1; text-decoration: none; transform: scale(1.08); }
.site-header nav a[aria-current="page"] { opacity: 1; border-bottom: 2px solid var(--cream); padding-bottom: 2px; }
.site-header nav a:active {
  transform: scale(0.92);
  transition: transform 0.1s ease;
}
.site-header nav .nav-menu a {
  padding: 16px 20px;
}

/* Home button — the "head" node in Figma's top-nav (60.883 x 54.176px).
   Its own link is meant to skip the aria-current underline treatment
   above, since being "current" doesn't apply to a single icon the same
   way — but .site-header nav a[aria-current="page"] and this rule are
   equally specific, so without explicitly cancelling border-bottom/
   padding-bottom here too, the underline was still showing up under the
   icon on the Home page itself. */
.site-header nav .nav-home a {
  display: block;
  opacity: 1;
  border-bottom: 0;
  padding-bottom: 0;
}
.nav-home-lottie {
  display: block;
  width: 152px; /* was 183px (3x) — pulled back slightly, ~2.5x the
    original 61px */
  height: 135px; /* was 162px (3x) — ~2.5x the original 54px */
}
.nav-home-lottie svg { display: block; }

/* Hamburger button for the collapsed link menu below — hidden by default;
   the 768px breakpoint further down switches it on and positions it. Home
   never moves into this menu, so the button only ever needs to reveal
   Animation/Illustration/CV/Contact (.nav-menu). */
.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 5px;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.nav-toggle-bar {
  display: block;
  width: 22px;
  height: 2px;
  border-radius: 2px;
  background: var(--cream);
  transition: transform 0.2s ease, opacity 0.2s ease;
}
/* js/nav-toggle.js adds/removes this class on <nav> when the button's
   clicked (and on Escape / outside click / resizing back past 768px) — the
   bars morph into a close "X" to match. */
nav.nav-open .nav-toggle-bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
nav.nav-open .nav-toggle-bar:nth-child(2) { opacity: 0; }
nav.nav-open .nav-toggle-bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* Below this, CV/Contact (.nav-menu, right-hand grid column) collapse
   into a dropdown behind a hamburger pinned to the right instead of
   crowding the now much larger, centred Home icon (183x162px) as the
   viewport narrows. Home stays put either way: it's still the only item
   in .nav-primary, still centred via nav's own 1fr/auto/1fr grid columns
   regardless of what .nav-menu is doing, so it never shifts. The bulb
   toggle is unaffected too — it's fixed-positioned outside this grid
   entirely, top-left of the viewport. */
@media (max-width: 768px) {
  .nav-toggle {
    display: flex;
    position: absolute;
    right: 1.5rem;
    top: 50%;
    transform: translateY(-50%);
  }
  /* .site-header nav .nav-menu (not just .nav-menu) — the base
     ".site-header nav ul" rule up above (gap: 72px, align-items: center)
     is more specific than a bare class selector would be, so a bare
     ".nav-menu { gap: 0 }" here loses that fight and the dropdown silently
     keeps its wide desktop gap and centred (rather than stretched) links —
     that's the "way too much space between each line" bug. Matching its
     specificity here is what actually makes the override stick. */
  .site-header nav .nav-menu {
    display: none;
    position: absolute;
    top: 100%;
    right: 1.5rem;
    transform: none; /* cancels the desktop rule's translateY(-50%) — that
      one's needed to vertically centre .nav-menu against the nav bar at
      desktop widths, but here .nav-menu is a dropdown hanging below the
      header (top: 100%) rather than sitting inside it, so the same
      transform would shift it upward by half its own height instead */
    margin-top: 0.75rem;
    min-width: 200px;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--blue);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 0.5rem;
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.25);
    z-index: 10;
  }
  nav.nav-open .nav-menu {
    display: flex;
  }
  .nav-menu li { width: 100%; }
  .nav-menu a {
    display: block;
    padding: 0.75rem 1rem;
  }
  .nav-menu a[aria-current="page"] {
    border-bottom: 0;
    padding-bottom: 0.75rem;
    background: color-mix(in srgb, var(--cream) 12%, transparent);
    border-radius: 8px;
  }
}

.site-footer {
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-weight: 700; /* same bold body font as .illustration-hero-intro/
    -meta and Home's .hero-copy */
  font-size: 0.85rem;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 1.5rem;
  text-align: center;
}

/* Clickable bulb (js/bulb.js) — present on every page. Anchored to the
   top-left corner of the PAGE (not the viewport) so it reads as hanging
   down from the top edge of the header and scrolls away together with it,
   the same as the home icon and CV/Email Me nav links do — it used to be
   position: fixed, which pinned it to the viewport and kept it floating
   on screen by itself once you'd scrolled past the header, decoupled from
   everything else up there. position: absolute with no positioned
   ancestor in between is positioned against the page itself (the initial
   containing block), which is exactly what makes it scroll normally
   instead of staying fixed — same top/left coordinates, so it sits in the
   same spot on first paint, it just isn't pinned to the viewport as you
   scroll. Sized down a lot since the source 1080x1080 frame has a lot of
   empty space around the actual bulb/cord artwork. z-index keeps it above
   the header bar it overlaps. */
.bulb-toggle {
  position: absolute;
  top: 0;
  left: 2.5rem; /* was 1.5rem — pulled further in */
  width: 140px;
  height: 140px;
  z-index: 20;
  cursor: pointer;
  view-transition-name: bulb-toggle;
  /* Same springy hover "pop" as the header's home lottie/link (.site-header
     nav a below) — identical transform, identical overshoot easing, and
     the same quick squash on click. It was using the default centre
     transform-origin (50% 50%) at first, which looked flat rather than
     springy: this element sits pinned at top: 0, so scaling from its
     centre pushes roughly half the growth above y: 0 — off the top edge
     of the viewport — where it's simply not visible, cutting the pop off
     mid-motion. Anchoring the origin to the top instead (matching "hangs
     down from the top edge" above) means all of the growth happens
     downward into visible space, so the full bounce actually shows.
     will-change hints the browser to give this its own compositing layer,
     so the hover transition stays smooth independent of the bulb's own
     continuously-animating idle Lottie loop repainting underneath it. */
  transform-origin: 50% 0;
  will-change: transform;
  transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.bulb-toggle:hover { transform: scale(1.08); }
.bulb-toggle:active { transform: scale(0.92); transition: transform 0.1s ease; }
.bulb-toggle svg { display: block; }

@media (max-width: 640px) {
  .bulb-toggle {
    left: 1.75rem; /* was 1rem — pulled further in, same direction as desktop */
    width: 100px;
    height: 100px;
  }
}

/* bulb.js repoints --blue between the light/dark theme colours on click (and
   on load, from localStorage or system preference). This class is added by
   bulb.js right after the very first paint, so the initial colour is always
   set instantly — only changes after that point animate. Every page's body
   background and header now point at --blue (all pages match Home's full
   blue/cream look), so this transition applies sitewide. */
body.bg-transitions-ready,
body.bg-transitions-ready .site-header {
  transition: background-color 0.4s ease;
}

/* ---- Generic content pages (about / work / blog) ---- */

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

.page-header { margin-bottom: 2rem; }
.page-title {
  margin: 0 0 0.5rem;
  font-size: 1.75rem;
  font-weight: 700;
  color: var(--cream);
}
.page-intro { color: var(--muted); margin: 0; }

main > p { margin: 0 0 1rem; }

.post-meta {
  color: var(--muted);
  font-size: 0.9rem;
  margin: 0 0 1.5rem;
}
.post-meta .p-category { text-transform: capitalize; }

.e-content > p { margin: 0 0 1rem; }
.e-content > p:last-child { margin-bottom: 0; }

.post-footer {
  margin-top: 2rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.9rem;
}

/* Work / blog index listings */
.post-list, .work-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.post-list li, .work-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.25rem 1rem;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--border);
}
.post-list li:first-child, .work-list li:first-child { padding-top: 0; }
.post-list a, .work-list a { font-weight: 600; color: var(--cream); }
.post-list a:hover, .work-list a:hover { opacity: 0.75; }
.post-list time, .work-role {
  color: var(--muted);
  font-size: 0.9rem;
  white-space: nowrap;
}

/* Individual work item */
.work-hero {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 6px;
  margin: 0 0 1.5rem;
  border: 1px solid var(--border);
}
.work-video {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 6px;
  margin: 0 0 1.5rem;
  background: #000;
}
.video-pending {
  color: var(--muted);
  font-style: italic;
  margin: -0.75rem 0 1.5rem;
}

/* Landing page hero + link cards (index.html) */
.hero { text-align: center; margin-bottom: 2.5rem; }
.hero h1 {
  margin: 0 0 0.35rem;
  font-size: 2rem;
  font-weight: 700;
  color: var(--cream);
}
.hero-title { margin: 0 0 1rem; color: var(--muted); font-weight: 500; }
.hero-intro { max-width: 36rem; margin: 0 auto; }

.link-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1rem;
  list-style: none;
  margin: 2rem 0 0;
  padding: 0;
}
.link-cards a {
  display: block;
  padding: 1.1rem 1rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--cream);
  font-weight: 600;
  text-align: center;
  text-decoration: none;
}
.link-cards a:hover {
  border-color: var(--cream);
  opacity: 0.85;
}
.link-cards .link-card-glyph {
  display: block;
  font-size: 1.4rem;
  margin-bottom: 0.4rem;
}

/* Illustration detail page (illustration/<collection>.html) — the page's
   own page-header (h1 + intro line, styled generically above) covers the
   title/copy for the whole connected series. Two non-hero pieces sit side
   by side per row; a hero image (add class illustration-piece--hero to its
   <li>, when a collection has one) spans the full row on its own, always
   first. Reuses the same 44rem reading width (doubled by illustration.css)
   as every other content page rather than going full-bleed, so it lines up
   with the page-header above it. */
.illustration-list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.illustration-piece--hero {
  grid-column: 1 / -1;
}
.illustration-piece {
  position: relative;
  cursor: pointer; /* clickable — js/illustration-lightbox.js opens it centred
    over a dimmed backdrop, trialled on pinnacle-valley.html first */
  will-change: transform; /* js/illustration-magnetic.js drives this
    element's transform continuously via requestAnimationFrame while
    hovered, same as .illustration-card-link above — see that file's own
    comment for why there's no CSS transition here to race against it */
}
.illustration-piece img:not(.illustration-badge) {
  display: block;
  width: 100%;
  height: auto;
  /* A flat, fixed radius - same 24px on every card regardless of its size
     (hero or regular piece, any viewport). These images used to ship with
     their corners already cut into the artwork's own alpha channel; that
     baked-in masking has been flattened out of every illustration piece and
     hero image site-wide, so this rule is the only thing rounding any of
     them now. */
  border-radius: 24px;
}
/* Photoshop badge — the SVG already carries its own dark rounded-square
   background, so it just needs positioning: top-left corner, inset from
   the edge rather than flush against it. :not() above stops the generic
   width:100% image rule from stretching this to fill the container (it
   otherwise wins on specificity since it's also scoped under
   .illustration-piece), which is what made it render oversized. */
.illustration-badge {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  width: 34px;
  height: 34px;
  display: block;
}

@media (max-width: 640px) {
  .illustration-list { grid-template-columns: 1fr; }
}

/* Previous/next project links at the bottom of each detail page
   (work/illustration/<collection>.html) — cycles through the same order
   the cards appear in on the Illustration index, wrapping around at each
   end (the last project's "next" is the first, and vice versa). A plain
   hairline top border and generous top spacing echo .site-footer just
   above it, rather than looking like another card. */
.project-nav {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 2rem;
  margin-top: 6rem;
  padding-top: 3rem;
}
.project-nav a {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  color: var(--cream);
  text-decoration: none;
  /* Same springy hover pop as the top nav links, so these read as part of
     the same interactive language rather than a one-off. */
  transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.project-nav a:hover { transform: scale(1.03); }
.project-nav a:active {
  transform: scale(0.97);
  transition: transform 0.1s ease;
}
.project-nav-next {
  text-align: right;
  align-items: flex-end;
}
.project-nav-label {
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.project-nav-title {
  font-size: 1.15rem;
  font-weight: 700;
}

@media (max-width: 640px) {
  .project-nav { gap: 1rem; }
  .project-nav-title { font-size: 1rem; }
}

/* Illustration page header — a two-column row: title on the left,
   intro on the right, both starting flush with the top of the row.
   Sits above the piece grid or card grid; shared by Animation, the
   Illustration index, and every detail page
   (work/illustration/<collection>.html), so all of them use identical
   header styling. Title/intro copy is edited directly in each page's
   HTML — .illustration-hero-intro is deliberately plain (regular weight,
   sentence case, same line-height as body text elsewhere on the site),
   not a styled label, so whatever's typed there reads as normal body
   copy.

   Back to each box's original, unconstrained width (title capped at
   40rem same as before either of the last two changes; intro at 100%
   again) — the earlier three-quarters-width, centred version is gone.
   The left/right positioning here isn't a text-align trick: the title
   sits at the row's start because it's a plain flex item (default
   flex: 0 1 auto — it doesn't grow), and the intro is flex: 1 1 20rem,
   so it grows to fill whatever's left in the row, its own right edge
   landing flush with the page's right edge without ever centring or
   right-aligning the paragraph text itself inside it — that stays
   left-aligned, ragged-right, same as any other body copy on the site.
   align-items: flex-start is what keeps the two top-aligned with each
   other rather than one drifting down to vertically centre against the
   other's height. flex-wrap: wrap is the narrow-viewport fallback: once
   there's no longer room for both side by side, intro drops to its own
   line below the title instead of squeezing unreadably thin. */
.illustration-hero {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 2rem;
  margin-bottom: 6rem; /* doubled from 3rem — felt cramped against the
    piece/card grid below it */
}
/* Detail pages wrap the title and the Role/Copyright line together in
   .illustration-hero-left, so meta sits directly under the title — in the
   same left column — rather than spanning the full width below both the
   title and the (often taller, wrapping) intro on the right. Animation
   and the Illustration index have no meta line, so their .illustration-
   hero-title renders unwrapped as a direct flex child instead — its own
   max-width below still bounds it the same way either way. */
.illustration-hero-left {
  max-width: 40rem;
}
.illustration-hero-title {
  margin: 0;
  max-width: 40rem;
  font-size: clamp(2rem, 5vw, 2.73rem); /* max nudged to match
    slimjimstudios.com/work/pat's own H2 (measured ~43.65px/2.73rem at a
    1280px viewport) almost exactly — it was already close at 2.75rem, this
    just tightens it */
  line-height: 1.2; /* their H2's own line-height/font-size ratio measures
    ~1.206 — 1.2 is the same, cleanly */
  font-weight: 700;
  color: var(--cream);
  text-align: left;
}
.illustration-hero-intro {
  flex: 1 1 20rem;
  margin: 0 0 0 auto; /* the auto left margin is what actually pushes the
    box itself to sit flush against the row's right edge — any leftover
    row space once the box has grown to its 50% cap collapses into this
    margin rather than justify-content, so the box is right-aligned while
    the text inside it (text-align: left, below) stays ragged-right same
    as always */
  max-width: 50%;
  font-weight: 700; /* matches slimjimstudios.com/work/pat's own body
    paragraph, which is bold rather than the regular weight used
    everywhere else on this site */
  font-size: 17.5px; /* matches their body paragraph (measured ~17.5px at
    a 1280px viewport) — superseding the earlier match to Home's
    .hero-copy (20px/20px) */
  line-height: 1.7; /* their paragraph's own line-height/font-size ratio
    measures ~1.7 almost exactly, so this is their real authored value,
    not just a close approximation */
  color: var(--cream); /* matches .illustration-hero-title's own colour
    exactly (rather than the softer --muted derived from it), so this text
    is never a separate shade from the heading above it in either theme -
    bulb.js repoints --cream itself between dark-mode cream and light-mode
    ink, so this still reads as near-black in light mode without needing
    a fixed colour of its own. Shared by Animation, the Illustration
    index, and every detail page (see the comment above .illustration-
    hero), so the change already applies everywhere it's used. */
  text-align: left;
}
/* Sits inside .illustration-hero-left, directly under the title — a
   plain block under a block, not a flex item, so it just needs its own
   top margin and an explicit left alignment (the row above it can put
   the title flush left while this stays independently anchored left
   too, regardless of whatever alignment .illustration-hero-intro next
   to it is doing). */
.illustration-hero-meta {
  margin: 1rem 0 0;
  text-align: left;
  color: var(--muted);
  font-weight: 700; /* matches .illustration-hero-intro's bold body font */
  font-size: 17.5px;
  line-height: 1.7;
}
.illustration-hero-meta strong {
  color: var(--cream);
  font-weight: 700;
}
/* Copyright stacks directly under Role now, rather than sitting beside it
   on a bullet-separated line — same block-per-span treatment at every
   width, so the old sub-640px-only override (and its bullet, no longer
   shown anywhere) is gone too. */
.illustration-hero-meta span {
  display: block;
}

@media (max-width: 640px) {
  .illustration-hero-title { font-size: 1.75rem; }
  .illustration-hero-intro {
    font-size: 14px; /* same 80% mobile scale-down home.css's own 640px
      breakpoint used to give .hero-copy (20->16), just applied to the new
      17.5px base instead */
    /* Desktop's flex:1 1 20rem + max-width:50% + margin-left:auto is what
       sits this beside .illustration-hero-left and flush against the
       row's right edge on a wide screen. Once the row wraps here (title
       no longer fits next to it), those same rules kept it capped at half
       width and pushed right on its own line too — squeezed into the
       right half of the screen with the left half sitting empty, instead
       of reading as body copy under the title. flex-basis/max-width:100%
       plus a plain top margin (replacing the auto side margin, which had
       nothing left to center/push against at full width) makes it a
       normal full-width block stacked directly under the header. */
    flex-basis: 100%;
    max-width: 100%;
    margin: 1.5rem 0 0;
  }
}

/* Printed pages (mainly the CV) should stay legible on paper regardless of
   the on-screen blue/cream theme — override the custom properties themselves
   rather than patching every individual rule, so print always renders dark
   text on white no matter what --blue/--cream currently point at. */
@media print {
  :root {
    /* !important is load-bearing here: index.html's inline flash-prevention
       script (and js/bulb.js) set --blue/--cream directly on <html>'s own
       style attribute, and an inline style always beats a plain stylesheet
       rule for the same property — that's exactly why dark mode's --cream
       (#fff3b7, a pale/dark yellow) was still winning and showing up as
       yellow-tinted text in printed/saved PDFs despite this whole block.
       An !important stylesheet rule is the one thing that outranks an
       inline style, so these force it back to plain dark-on-white. */
    --blue: #1a1a1a !important;
    --cream: #1a1a1a !important;
    --muted: #555 !important;
    --border: #ddd !important;
    --paper: #ffffff !important;
  }
  /* Everything on the CV is sized in rem, so scaling the root font-size
     down scales the whole page proportionally — text, gaps and all — to
     roughly resume-standard sizing on paper (this page's 1rem body text
     is 16px/~12pt on screen; 14px here lands it around ~10.5pt printed). */
  html { font-size: 14px; }
  .site-header, .site-footer, .no-print, .bulb-toggle { display: none; }
  main { padding: 0; max-width: none; }
  /* 1.2 rather than the on-screen 1.6 — resume convention runs close to
     single spacing (~1.0-1.15); 1.2 stays a touch more breathable than
     that while being clearly tighter than reading-comfort spacing. */
  body { background: #fff; color: #1a1a1a; line-height: 1.2; }
  a { color: inherit; text-decoration: none; }
}

/* More generous top/side page margins than the browser default; bottom
   stays tighter since that's where the CV already has spare room. */
@page { margin: 2.5cm 2.5cm 1.5cm; }
