/* ============================================================
   Andrew Worgan PORTFOLIO - DESIGN SYSTEM (flat / playful)
   ============================================================
   Flat colour palette - NO gradients:
     --blush:      #FEF6FE   (page background)
     --ink:        #161A2E   (text, borders, dark footer)
     --periwinkle: #AE9DF3
     --yellow:     #FEDA74
     --blue:       #65A1FB
   ------------------------------------------------------------
   You almost never need to touch this file. To change CONTENT
   (images, certificates, projects, bio) edit  content.js  only.
   ============================================================ */

/* ---------- FONTS ---------- */
@font-face {
  font-family: 'Arial Rounded MT Bold';
  src: url('fonts/ArialRoundedMTBold.woff2') format('woff2'),
       url('fonts/ArialRoundedMTBold.woff') format('woff');
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}

/* Body text: Inter, self-hosted (one variable file covers weights 300-700,
   Latin only) so pages don't wait on Google Fonts. Both fonts are also
   preloaded in each page's <head>. */
@font-face {
  font-family: 'Inter';
  src: url('fonts/Inter-latin-var.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
                 U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- RESET ---------- */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  scroll-behavior: smooth;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  font-family: var(--font-body);
  background-color: var(--blush);
  color: var(--ink);
  line-height: 1.7;
  overflow-x: hidden;
  /* The "6 4" is the hotspot - the actual click point inside the 48px image. */
  cursor: url('assets/ui/Pet Wizard Cursor OwO.png') 6 4, auto;
}

a { text-decoration: none; color: inherit; }
a:hover { cursor: url('assets/ui/Pet Wizard Cursor default Hover OwO.png') 6 4, pointer; }
img { max-width: 100%; height: auto; display: block; }
ul, ol { list-style: none; }
button {
  cursor: url('assets/ui/Pet Wizard Cursor default Hover OwO.png') 6 4, pointer;
  border: none; background: none; font: inherit; color: inherit;
}

/* Prose keeps the normal caret/arrow so text still feels precise to select.
   Links inside prose still get the wizard pointer (a:hover above wins on the <a>). */
p, h1, h2, h3, h4, li, blockquote, figcaption { cursor: auto; }
/* ...except inside something clickable (a polaroid's caption, a card link),
   where the text keeps that thing's wizard pointer. */
:is(a, button, [role="button"]) :is(p, h1, h2, h3, h4, li, blockquote, figcaption) { cursor: inherit; }

/* ---------- CUSTOM PROPERTIES ---------- */
:root {
  /* Flat brand colours */
  --blush:      #FEF6FE;
  --ink:        #161A2E;
  --periwinkle: #AE9DF3;
  --yellow:     #FEDA74;
  --blue:       #65A1FB;
  --teal:       #5AC8B6;   /* 4th flat accent - gives the Writing page its own colour */
  --pink:       #FB9DC4;   /* 5th flat accent - Certificates page chip/badge */
  --white:      #FFFFFF;

  /* Derived */
  --ink-soft:   #4A4E63;   /* secondary text */
  --ink-muted:  #5E6175;   /* tertiary text - ≥4.5:1 on white (WCAG AA) */
  --overlay:    rgba(22, 26, 46, 0.78);

  /* Soft accent tints (still flat) */
  --periwinkle-tint: #F0ECFC;
  --yellow-tint:     #FEF4DC;
  --blue-tint:       #E4EDFE;
  --teal-tint:       #E0F5F1;
  --pink-tint:       #FEEAF3;

  /* Deep accent inks - accent-coloured text on white (stamps, icons) */
  --periwinkle-ink:  #5E46B8;
  --yellow-ink:      #8A6400;
  --blue-ink:        #1F5FC0;
  --teal-ink:        #1F7D6E;
  --pink-ink:        #B03A70;

  /* Typography */
  --font-display: 'Arial Rounded MT Bold', 'Trebuchet MS', system-ui, sans-serif;
  --font-body:    'Inter', 'Arial Rounded MT Bold', sans-serif;

  --fs-hero:    clamp(2.6rem, 6.5vw, 5.5rem);
  --fs-h1:      clamp(2.2rem, 5vw, 3.6rem);
  --fs-h2:      clamp(1.6rem, 3.2vw, 2.4rem);
  --fs-h3:      clamp(1.15rem, 2vw, 1.5rem);
  --fs-body:    1.0625rem;
  --fs-small:   0.9rem;
  --fs-tiny:    0.75rem;

  /* Spacing */
  --space-xs:  0.5rem;
  --space-sm:  1rem;
  --space-md:  1.5rem;
  --space-lg:  2.5rem;
  --space-xl:  4rem;
  --space-2xl: 6rem;

  /* Layout */
  --max-width:  1180px;
  --header-h:   78px;

  /* Radii - chunky/rounded */
  --radius-sm:  10px;
  --radius-md:  16px;
  --radius-lg:  22px;
  --radius-xl:  30px;
  --radius-full: 9999px;

  /* Flat hard-offset shadows (no blur => stays flat) */
  --pop:        4px 4px 0 var(--ink);
  --pop-lg:     7px 7px 0 var(--ink);

  --transition: 0.22s cubic-bezier(0.4, 0, 0.2, 1);
  --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);   /* card hovers overshoot a touch */

  --border: 2.5px solid var(--ink);
}

/* Accent classes expose their colour trio to the cards (folders, index
   cards, tickets), which read --acc / --acc-tint / --acc-ink. */
.lavender { --acc: var(--periwinkle); --acc-tint: var(--periwinkle-tint); --acc-ink: var(--periwinkle-ink); }
.blue     { --acc: var(--blue);       --acc-tint: var(--blue-tint);       --acc-ink: var(--blue-ink); }
.teal     { --acc: var(--teal);       --acc-tint: var(--teal-tint);       --acc-ink: var(--teal-ink); }
.yellow   { --acc: var(--yellow);     --acc-tint: var(--yellow-tint);     --acc-ink: var(--yellow-ink); }
.pink     { --acc: var(--pink);       --acc-tint: var(--pink-tint);       --acc-ink: var(--pink-ink); }

/* ============================================================
   HEADER / NAVIGATION
   ============================================================ */
.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-sm) var(--space-lg);
  background: var(--blush);
  position: sticky;
  top: 0;
  z-index: 1000;
  border-bottom: 2.5px solid var(--ink);
}

.brand {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.5rem;
  color: var(--ink);
  letter-spacing: -0.01em;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}
/* Kasai flame beside the name - flickers gently, burns faster on hover. */
.brand .brand-flame {
  height: 26px;
  width: auto;
  transform-origin: bottom center;
}
.brand:hover { transform: rotate(-2deg); }
@media (prefers-reduced-motion: no-preference) {
  .brand .brand-flame { animation: flame-flicker 2.4s ease-in-out infinite; }
  .brand:hover .brand-flame { animation-duration: 0.7s; }
}
@keyframes flame-flicker {
  0%, 100% { transform: scaleY(1) rotate(-2deg); }
  30%      { transform: scaleY(1.08) scaleX(0.95) rotate(2.5deg); }
  60%      { transform: scaleY(0.94) scaleX(1.05) rotate(-1deg); }
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 2px;
}

.nav-links a {
  font-family: var(--font-display);
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--ink);
  padding: 8px 16px;
  border-radius: var(--radius-full);
  border: 2px solid transparent;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}

.nav-links a:hover {
  background: var(--periwinkle-tint);
  border-color: var(--ink);
}
/* Current page = that page's chip colour, so the icons keep their navy outlines. */
.page-about  { --page-acc: var(--yellow); }
.page-coding { --page-acc: var(--blue); }
.page-art    { --page-acc: var(--periwinkle); }
.page-writing{ --page-acc: var(--teal); }
.page-certs  { --page-acc: var(--pink); }
.nav-links a.active {
  background: var(--page-acc, var(--yellow));
  border-color: var(--ink);
}

/* Doodle icons beside each nav label (one file each in assets/ui/nav-icons/).
   Outlines use the text colour (navy). */
.nav-links a,
.mobile-nav a {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
}
.nav-icon {
  width: 1.45em;
  height: 1.45em;
  flex-shrink: 0;
  transition: transform var(--transition);
}
@media (prefers-reduced-motion: no-preference) {
  .nav-links a:hover .nav-icon,
  .mobile-nav a:hover .nav-icon { transform: rotate(-10deg) scale(1.12); }
}

/* Hamburger */
.hamburger {
  display: none;
  flex-direction: column;
  gap: 5px;
  padding: 8px;
  z-index: 1001;
}
.hamburger span {
  display: block;
  width: 26px;
  height: 3px;
  background: var(--ink);
  border-radius: 2px;
  transition: transform var(--transition), opacity var(--transition);
}
.hamburger.open span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.hamburger.open span:nth-child(2) { opacity: 0; }
.hamburger.open span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }

/* Mobile nav overlay */
.mobile-nav {
  display: none;
  position: fixed;
  inset: 0;
  background: var(--blush);
  z-index: 999;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
}
.mobile-nav.open { display: flex; }
.mobile-nav a {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: 600;
  color: var(--ink);
  padding: 8px 28px;
  border-radius: var(--radius-full);
  transition: background var(--transition), color var(--transition);
}
.mobile-nav a:hover  { background: var(--periwinkle-tint); box-shadow: inset 0 0 0 2.5px var(--ink); }
.mobile-nav a.active { background: var(--page-acc, var(--yellow)); box-shadow: inset 0 0 0 2.5px var(--ink); }

@media (max-width: 820px) {
  .nav-links { display: none; }
  .hamburger { display: flex; }
  .site-header { padding: var(--space-sm) var(--space-md); }
}

/* ============================================================
   MARQUEE (rolling banner)
   ============================================================ */
.marquee-container {
  width: 100%;
  overflow: hidden;
  background: var(--yellow);
  color: var(--ink);
  padding: 0.6rem 0;
  display: flex;
  align-items: center;
  border-bottom: 2.5px solid var(--ink);
}
/* The track that scrolls. JS clones the group inside it to fill any width,
   so translateX(-50%) always loops seamlessly. Duration is set by JS too. */
.marquee-content {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  animation: scroll-marquee 30s linear infinite;
  will-change: transform;
}
/* One authored group of phrases (a <ul>). Each <li> gets a single wave after
   it with equal spacing, so every seam looks identical - no double-wave gap. */
.marquee-group {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  margin: 0;
  padding: 0;
}
.marquee-group li {
  flex-shrink: 0;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: 0.06em;
}
/* The wave is an SVG mask filled with currentColor, so it always matches the text. */
.marquee-group li::after {
  content: '';
  width: 30px;
  height: 12px;
  margin: 0 1.5rem;
  background: currentColor;
  opacity: 0.85;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 12'%3E%3Cpath d='M2 6 Q 6.5 1 11 6 T 20 6 T 29 6' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 12'%3E%3Cpath d='M2 6 Q 6.5 1 11 6 T 20 6 T 29 6' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
}
@keyframes scroll-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* ============================================================
   LAYOUT
   ============================================================ */
.page-content { min-height: 100vh; }

.container {
  width: 100%;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 var(--space-lg);
}

.section { padding: var(--space-2xl) 0; }
.section--tight { padding-top: var(--space-lg); }

/* Anything jumped to via #anchor clears the sticky header. */
:target, section[id] { scroll-margin-top: calc(var(--header-h) + 12px); }

/* ---------- WAVY DIVIDER (Niv-style) ---------- */
.wave-divider {
  height: 22px;
  width: 100%;
  background-repeat: repeat-x;
  background-position: center;
  background-size: 44px 22px;
  /* one wave crest, ink stroke */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='44' height='22' viewBox='0 0 44 22'%3E%3Cpath d='M0 11 Q 11 -1 22 11 T 44 11' fill='none' stroke='%23161A2E' stroke-width='2.5' stroke-linecap='round'/%3E%3C/svg%3E");
  margin: var(--space-lg) 0;
  opacity: 0.9;
}
.wave-divider.peri {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='44' height='22' viewBox='0 0 44 22'%3E%3Cpath d='M0 11 Q 11 -1 22 11 T 44 11' fill='none' stroke='%23AE9DF3' stroke-width='3' stroke-linecap='round'/%3E%3C/svg%3E");
}
.wave-divider.blue {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='44' height='22' viewBox='0 0 44 22'%3E%3Cpath d='M0 11 Q 11 -1 22 11 T 44 11' fill='none' stroke='%2365A1FB' stroke-width='3' stroke-linecap='round'/%3E%3C/svg%3E");
}
.wave-divider.teal {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='44' height='22' viewBox='0 0 44 22'%3E%3Cpath d='M0 11 Q 11 -1 22 11 T 44 11' fill='none' stroke='%235AC8B6' stroke-width='3' stroke-linecap='round'/%3E%3C/svg%3E");
}
.wave-divider.yellow {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='44' height='22' viewBox='0 0 44 22'%3E%3Cpath d='M0 11 Q 11 -1 22 11 T 44 11' fill='none' stroke='%23FEDA74' stroke-width='3.5' stroke-linecap='round'/%3E%3C/svg%3E");
}
.wave-divider.pink {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='44' height='22' viewBox='0 0 44 22'%3E%3Cpath d='M0 11 Q 11 -1 22 11 T 44 11' fill='none' stroke='%23FB9DC4' stroke-width='3' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* ============================================================
   PAGE BANNER (top of each section page)
   ============================================================ */
.page-banner {
  padding: var(--space-lg) 0;
  text-align: center;
  position: relative;
}
/* Accent-tinted banner blocks carry the homepage's boldness onto sub-pages. */
.page-banner.lavender { background: var(--periwinkle-tint); }
.page-banner.blue     { background: var(--blue-tint); }
.page-banner.teal     { background: var(--teal-tint); }
.page-banner.yellow   { background: var(--yellow-tint); }
.page-banner.pink     { background: var(--pink-tint); }
.page-banner h1 {
  font-family: var(--font-display);
  font-size: var(--fs-hero);
  font-weight: 700;
  color: var(--ink);
  line-height: 1.02;
  margin-bottom: var(--space-sm);
  letter-spacing: -0.015em;
}
.page-banner p {
  font-size: var(--fs-body);
  color: var(--ink-soft);
  max-width: 560px;
  margin: 0 auto;
}
/* little tilted highlight chip at the top of each page */
.page-banner .banner-chip {
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-small);
  padding: 5px 16px;
  border: var(--border);
  border-radius: var(--radius-full);
  background: var(--white);
  box-shadow: var(--pop);
  margin-bottom: var(--space-md);
  transform: rotate(-2deg);
  transition: transform var(--transition), box-shadow var(--transition);
}
/* Playful lift on hover so the chip doesn't read as a dead, static label. */
.page-banner .banner-chip:hover {
  transform: rotate(2deg) translateY(-3px) scale(1.05);
  box-shadow: var(--pop-lg);
}
.page-banner.lavender .banner-chip { background: var(--periwinkle); }
.page-banner.blue     .banner-chip { background: var(--blue); }  /* ink text - white fails contrast on this blue */
.page-banner.teal     .banner-chip { background: var(--teal); }
.page-banner.yellow   .banner-chip { background: var(--yellow); }
.page-banner.pink     .banner-chip { background: var(--pink); }

/* ============================================================
   PROJECT CARDS (Coding) - file folders
   ============================================================
   One fill (the accent tint) for tab + folder. The tab is a normal
   CSS-bordered box (both top corners rounded the same way); only the
   concave curve where it meets the folder top is an inline SVG (.tab-cap),
   which also paints over the straight border lines that would otherwise
   run through that curve.
   The screenshot is a sheet of paper hidden behind the folder, to the
   right of the tab; it rises out of the folder on hover. */
.project-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
  gap: var(--space-2xl) var(--space-lg);   /* headroom for the rising paper */
}

.project-card {
  --tab-h: 38px;
  --fillet: 14px;
  container-type: inline-size;
  position: relative;
  display: flex;
  flex-direction: column;
}
.project-card:hover,
.project-card:focus-within { z-index: 2; translate: 0 -4px; }

/* Tab row: the tab, then a slot for the paper. No z-index here, so the
   tab can sit above the folder while the paper sits below it. */
.project-card-top {
  position: relative;
  display: flex;
  height: var(--tab-h);
  margin-bottom: -2.5px;        /* tab covers the folder's top border */
}

.project-card-tab {
  position: relative;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 8rem;              /* every tab the same size (longer labels still fit) */
  padding: 0 16px 2px 14px;
  margin-right: var(--fillet);
  font-family: var(--font-display);
  font-size: var(--fs-small);
  white-space: nowrap;
  background: var(--acc-tint);
  border: var(--border);
  border-bottom: 0;
  border-radius: 14px 14px 0 0;
}
/* Seals any sub-pixel gap between the tab and the folder, between its borders. */
.project-card-tab::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: var(--acc-tint);
}
.project-card-tab > svg:not(.tab-cap) { width: 18px; height: 18px; flex-shrink: 0; }
.tab-cap {
  position: absolute;
  left: 100%;                   /* = start of the tab's right border */
  bottom: 0;
  width: calc(var(--fillet) + 3px);
  height: var(--fillet);
  overflow: visible;
}
.tab-cap .fill   { fill: var(--acc-tint); }
.tab-cap .stroke { fill: none; stroke: var(--ink); stroke-width: 2.5; }

.project-card-slot {
  position: relative;
  flex: 1;
  margin-left: 10px;
}
/* Same size on every card (54% of the card width, right-aligned), hidden
   12px inside the folder at rest; rises out on hover or keyboard focus. */
.project-card-paper {
  position: absolute;
  top: calc(100% + 12px);
  right: 8px;
  width: min(54cqw, 100% - 8px);
  z-index: 0;
  rotate: -1.5deg;
  transition: rotate 0.4s var(--ease-bounce), translate 0.4s var(--ease-bounce);
}
.project-card:hover .project-card-paper,
.project-card:focus-within .project-card-paper { rotate: 2deg; translate: 0 -85%; }
/* No hover on touch screens - show the preview peeking out instead. */
@media (hover: none) {
  .project-card-paper { translate: 0 -60%; }
}
.project-card-image {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  background: var(--white);
  border: 2px solid var(--ink);
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--acc-ink);
}
.project-card-image svg { width: 44px; height: 44px; }

.project-card-body {
  position: relative;
  z-index: 1;
  flex: 1;
  display: flex;
  flex-direction: column;
  /* Tall enough to hide the paper at rest (54cqw wide at 16:10). */
  min-height: calc(54cqw * 0.625 + 28px);
  padding: var(--space-md);
  background: var(--acc-tint);
  border: var(--border);
  border-radius: 0 var(--radius-lg) var(--radius-lg) var(--radius-lg);
}

.project-card-title {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: var(--space-xs);
}
.project-card-fork {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: -2px 0 var(--space-xs);
  font-size: var(--fs-small);
  color: var(--ink-soft);
}
.project-card-fork svg { width: 1.1em; height: 1.1em; flex-shrink: 0; color: var(--ink); }
.project-card-fork a {
  font-weight: 600;
  color: var(--ink);
  border-bottom: 2px solid var(--acc);
}
.project-card-desc {
  font-size: var(--fs-small);
  color: var(--ink-soft);
  margin-bottom: var(--space-sm);
  line-height: 1.6;
  flex: 1;
}
.project-card-tags {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-bottom: var(--space-sm);
}
.tag {
  display: inline-block;
  font-size: var(--fs-tiny);
  font-weight: 600;
  padding: 3px 11px;
  border-radius: var(--radius-full);
  background: var(--white);
  border: 1.5px solid var(--ink);
  color: var(--ink);
}
.project-card-links { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.project-card-links a {
  font-family: var(--font-display);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--ink);
  border-bottom: 2.5px solid var(--acc);
}

/* Shared link arrow on cards - nudges right on hover. */
.card-arrow {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  transition: translate var(--transition);
}
.project-card-links a:hover .card-arrow,
.writing-card:hover .card-arrow,
.cert-link:hover .card-arrow { translate: 4px 0; }

/* ============================================================
   GALLERY GRID (Illustrations) - polaroids
   ============================================================
   Colour-pop frames: each frame is painted with its artwork's most
   visible colour and the tag chip with the second (set per card by
   script.js as --frame / --chip). Chunky ink outline, a slight tilt that
   varies card to card; on hover the frame straightens and lifts, and the
   artwork jumps a little way out of it. Art keeps its natural ratio. */
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-xl) var(--space-lg);
  align-items: start;   /* cards keep their natural (uneven) heights */
}

.gallery-item {
  --frame: var(--white);
  --frame-ink: var(--ink);
  --chip: var(--periwinkle-tint);
  --chip-ink: var(--ink);
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 12px 12px 0;
  background: var(--frame);
  border: var(--border);
  border-radius: 6px;
  box-shadow: var(--pop);
  rotate: -1.5deg;   /* hover bounce comes from .animate-on-scroll's transition */
}
.gallery-item:nth-child(3n+2) { rotate: 1.8deg; }
.gallery-item:nth-child(3n)   { rotate: -0.6deg; }
.gallery-item:hover {
  z-index: 1;
  rotate: 0deg;
  translate: -3px -6px;
  box-shadow: var(--pop-lg);
}
/* No forced aspect ratio - artwork keeps its own proportions, never cropped. */
.gallery-item-img {
  width: 100%;
  overflow: hidden;
  background: var(--periwinkle-tint);
  border: 2px solid var(--ink);
  border-radius: 3px;
}
.gallery-item-img--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 4 / 3;
  color: var(--periwinkle);
}
.gallery-item-img--empty svg { width: 52px; height: 52px; }
.gallery-item-img img { width: 100%; height: auto; }

.gallery-item-cap {
  padding: 14px 4px 16px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px var(--space-sm);
}
.gallery-item-cap h3 {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 600;
  color: var(--frame-ink);
  line-height: 1.25;
}
.gallery-item-cap p {
  font-size: var(--fs-tiny);
  font-weight: 600;
  color: var(--chip-ink);
  background: var(--chip);
  border: 2px solid var(--ink);
  border-radius: var(--radius-full);
  padding: 2px 10px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  white-space: nowrap;
}

/* ============================================================
   LIGHTBOX  (native <dialog> - focus trap, Esc and aria-modal for free)
   ============================================================ */
.lightbox {
  margin: auto;          /* restores <dialog> centring (the * reset zeroes it) */
  border: none;
  background: transparent;
  padding: 0;
  max-width: 92vw;
  overflow: visible;
}
.lightbox::backdrop { background: var(--overlay); }
.lightbox img {
  max-width: 90vw;
  max-height: 80vh;
  margin: 0 auto;
  border-radius: var(--radius-md);
  border: 3px solid var(--white);
  box-shadow: var(--pop-lg);
}
.lightbox-cap {
  margin-top: 0.7rem;
  text-align: center;
  font-family: var(--font-display);
  font-size: var(--fs-body);
  color: var(--white);
}
.lightbox-cap:empty { display: none; }
.lightbox-close {
  position: absolute;
  top: -16px;
  right: -16px;
  width: 52px; height: 52px;
  font-size: 1.7rem;
  color: var(--ink);
  background: var(--white);
  border: var(--border);
  border-radius: 50%;
  box-shadow: var(--pop);
  display: flex; align-items: center; justify-content: center;
  transition: transform var(--transition);
}
.lightbox-close:hover { transform: rotate(90deg); }

/* ============================================================
   WRITING - library index cards
   ============================================================
   Every line of text sits on a 28px ruled grid (--rule), so keep
   margins inside the card at 0 or a multiple of it. */
.writing-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 400px), 1fr));
  gap: var(--space-lg);
  align-items: start;
}

.writing-card {
  --rule: 28px;
  position: relative;
  display: block;
  padding: var(--rule) var(--space-lg) 22px 3.4rem;
  line-height: var(--rule);
  background-color: #FFFDF8;
  /* ruled lines as a flat SVG tile, not a gradient */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='28'%3E%3Crect y='22' width='10' height='1' fill='%23DDE3F7'/%3E%3C/svg%3E");
  border: 1.5px solid rgba(22, 26, 46, 0.2);
  border-radius: 6px;
}
.writing-card:hover { rotate: -0.8deg; translate: 0 -3px; }

/* Margin rule in the card's accent colour */
.writing-card::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 2.3rem;
  width: 2px;
  background: var(--acc);
}
.writing-card-hole {
  position: absolute;
  left: 0.8rem;
  top: 50%;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--blush);
  border: 1.5px solid rgba(22, 26, 46, 0.25);
  translate: 0 -50%;
}
.writing-card-stamp {
  position: absolute;
  top: 18px;
  right: 18px;
  rotate: 8deg;
  font-family: var(--font-display);
  font-size: 0.7rem;
  line-height: 1.9;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--acc-ink);
  background: var(--white);
  border: 2px solid currentColor;
  border-radius: 8px;
  padding: 0 8px;
}

.writing-card-date {
  font-family: var(--font-display);
  font-size: var(--fs-tiny);
  color: var(--ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding-right: 6rem;            /* clear of the stamp */
}
.writing-card-title {
  font-family: var(--font-display);
  font-size: 1.35rem;
  font-weight: 600;
  color: var(--ink);
}
.writing-card-excerpt {
  font-size: var(--fs-small);
  color: var(--ink-soft);
}
.read-more {
  font-family: var(--font-display);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--ink);
  border-bottom: 2.5px solid var(--acc);
}
.read-more svg { width: 1.05em; height: 1.05em; vertical-align: -0.15em; }

/* ============================================================
   CERTIFICATES - ticket stubs
   ============================================================
   Coloured stub (scan or icon) | dashed perforation with notches | details. */
.cert-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
  gap: var(--space-lg);
}

.cert-card {
  --stub: 104px;
  position: relative;
  display: grid;
  grid-template-columns: var(--stub) 1fr;
  min-height: 124px;
  background: var(--white);
  border: var(--border);
  border-radius: var(--radius-md);
}
.cert-card:hover { rotate: -1.5deg; scale: 1.02; }

.cert-stub {
  display: grid;
  place-items: center;
  overflow: hidden;
  color: var(--ink);
  background: var(--acc);
  border-right: 2.5px dashed var(--ink);
  border-radius: calc(var(--radius-md) - 2.5px) 0 0 calc(var(--radius-md) - 2.5px);
}
.cert-stub svg { width: 44px; height: 44px; }
.cert-stub--img img { width: 100%; height: 100%; object-fit: cover; }

/* Notches: half-circles in the page colour sitting on the perforation. */
.cert-card::before,
.cert-card::after {
  content: '';
  position: absolute;
  left: calc(var(--stub) - 12.25px);
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--blush);
  border: var(--border);
}
.cert-card::before { top: -12.25px;    clip-path: inset(50% 0 0 0); }
.cert-card::after  { bottom: -12.25px; clip-path: inset(0 0 50% 0); }

.cert-info {
  padding: var(--space-sm) var(--space-md);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
}
.cert-meta {
  font-size: var(--fs-tiny);
  font-weight: 700;
  color: var(--ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.cert-info h3 {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 600;
  line-height: 1.25;
  color: var(--ink);
}
.cert-link {
  font-family: var(--font-display);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--ink);
  border-bottom: 2.5px solid var(--acc);
  align-self: flex-start;
  margin-top: var(--space-xs);
}

/* ============================================================
   ABOUT PAGE
   ============================================================ */
.about-hero {
  display: grid;
  grid-template-columns: 1.2fr 0.9fr;
  gap: var(--space-lg) var(--space-2xl);
  align-items: start;
  padding: 0 0 var(--space-lg);
}

/* The About page opens straight after the marquee - keep the gap tight,
   and the Current Goals notes follow close behind the bio. */
.page-about .section:first-of-type { padding: var(--space-md) 0; }

/* Full-width hero header: eyebrow + one-line greeting + subheading. */
.about-head { grid-column: 1 / -1; }

.about-eyebrow {
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-small);
  padding: 5px 16px;
  border: var(--border);
  border-radius: var(--radius-full);
  background: var(--yellow);
  box-shadow: var(--pop);
  margin-bottom: var(--space-md);
  transform: rotate(-2deg);
}

.about-greeting {
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 6vw, 4.6rem);
  font-weight: 700;
  color: var(--ink);
  line-height: 1.05;
  letter-spacing: -0.02em;
  white-space: nowrap;            /* keep the greeting on one line (desktop) */
  margin-bottom: var(--space-md);
}
.about-subheading {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: 500;
  color: var(--ink-soft);
  line-height: 1.25;
  max-width: 760px;
}

/* Yellow highlight for *asterisked* words (greeting, subheading, etc.) */
.hl {
  background: var(--yellow);
  padding: 0 0.15em;
  border-radius: 6px;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}
.about-text p {
  font-size: var(--fs-body);
  color: var(--ink-soft);
  margin-bottom: var(--space-sm);
  line-height: 1.8;
}
.about-email {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--ink);
  border-bottom: 2.5px solid var(--blue);
}

.about-photo-wrapper {
  display: flex;
  align-items: center;
  justify-content: center;
}
.about-photo {
  width: 100%;
  max-width: 380px;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: var(--radius-xl);
  border: 3px solid var(--ink);
  box-shadow: var(--pop-lg);
  transform: rotate(2.5deg);
  transition: transform var(--transition);
}
.about-photo:hover { transform: rotate(0deg); }

.about-photo-placeholder {
  width: 100%;
  max-width: 380px;
  aspect-ratio: 3 / 4;
  border-radius: var(--radius-xl);
  background: var(--periwinkle);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink);
  border: 3px solid var(--ink);
  box-shadow: var(--pop-lg);
  transform: rotate(2.5deg);
}

/* Skills / "Other Pages" pills (centred row of links to the other pages) */
.skills-section { padding: var(--space-md) 0 0; }
.skills-heading {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: var(--space-md);
  text-align: center;
}
.skills-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.skill-tag {
  font-family: var(--font-display);
  font-size: var(--fs-small);
  font-weight: 500;
  padding: 8px 18px;
  border-radius: var(--radius-full);
  background: var(--white);
  border: var(--border);
  box-shadow: var(--pop);
  color: var(--ink);
  transition: transform var(--transition), box-shadow var(--transition),
              background var(--transition), color var(--transition);
}
/* Accent hover - each "Other Pages" chip previews its page's own colour. */
.skill-tag.lavender:hover { background: var(--periwinkle); color: var(--ink); }
.skill-tag.blue:hover     { background: var(--blue);       color: var(--ink); }  /* ink - white fails contrast */
.skill-tag.teal:hover     { background: var(--teal);       color: var(--ink); }
.skill-tag.yellow:hover   { background: var(--yellow);     color: var(--ink); }
.skill-tag.pink:hover     { background: var(--pink);       color: var(--ink); }
.skill-tag:hover { transform: translate(-2px, -2px); box-shadow: var(--pop-lg); }

/* Casual sign-off (Niv-style "Thanks for looking ;)") */
.signoff {
  text-align: center;
  padding: var(--space-lg) 0 0;
}
/* The About page runs Current Goals -> Other Pages -> sign-off -> footer
   as one short stack, so its gaps are tighter than the other pages'. */
.page-about .wave-divider { margin: var(--space-md) 0; }
.page-about .site-footer { margin-top: var(--space-xl); }
.signoff p {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: 600;
  color: var(--ink);
}

@media (max-width: 820px) {
  /* minmax(0, 1fr), not 1fr: a plain 1fr column grows to fit its widest
     child, and Firefox sizes the photo at its 380px max, which pushed the
     column past the screen edge and everything centred in it off to the right. */
  .about-hero { grid-template-columns: minmax(0, 1fr); gap: var(--space-lg); text-align: center; }
  .about-email { overflow-wrap: anywhere; }   /* last resort if even half the address won't fit */
  .about-head { order: 1; }
  .about-photo-wrapper { order: 2; }
  .about-text { order: 3; }
  .about-greeting { white-space: normal; font-size: var(--fs-h1); }
  .about-subheading { font-size: var(--fs-h3); }
  .about-eyebrow, .about-photo, .about-photo-placeholder { transform: rotate(0deg); }
}

/* ============================================================
   FOOTER (dark, grounding)
   ============================================================ */
.site-footer {
  background: var(--ink);
  border-top: 2.5px solid var(--periwinkle);   /* visible grounding line (ink-on-ink was invisible) */
  padding: var(--space-xl) 0;
  margin-top: var(--space-2xl);
}
.footer-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-md);
}
.footer-text {
  font-size: var(--fs-small);
  color: var(--periwinkle);          /* same colour as the social icons */
}
.footer-socials { display: flex; align-items: center; gap: var(--space-sm); }
.social-link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px; height: 46px;
  border-radius: var(--radius-full);
  color: var(--periwinkle);                  /* icon colour, via currentColor */
  background: rgba(174, 157, 243, 0.16);     /* faint periwinkle disc */
  transition: background var(--transition), transform var(--transition), color var(--transition);
}
.social-link:hover {
  color: var(--ink);                 /* icon flips to navy for contrast */
  background: var(--periwinkle);     /* solid periwinkle disc */
  transform: translateY(-3px);
}
/* JS recolours each icon into a mask filled with currentColor, so the icons
   always match the palette (and the copyright text beside them). */
.social-ico {
  width: 22px; height: 22px;
  background: currentColor;
  -webkit-mask: var(--ico) center / contain no-repeat;
          mask: var(--ico) center / contain no-repeat;
}
/* Fallback shown before JS upgrades the icons (or if JS is disabled). */
.social-link img { width: 22px; height: 22px; object-fit: contain; }

/* On-brand keyboard focus ring for links, buttons and gallery tiles. */
:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; }
[data-full]:focus-visible { outline-offset: 4px; border-radius: var(--radius-lg); }

/* ============================================================
   EMPTY STATE (auto-shown when a section has no items yet)
   ============================================================ */
.empty-state {
  text-align: center;
  padding: var(--space-2xl) var(--space-lg);
  background: var(--white);
  border: 2.5px dashed var(--ink);
  border-radius: var(--radius-lg);
}
.about-photo-placeholder svg { width: 72px; height: 72px; }
.empty-state-icon { display: flex; justify-content: center; margin-bottom: var(--space-sm); color: var(--ink); }
.empty-state-icon svg { width: 56px; height: 56px; }
.empty-state h3 {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  color: var(--ink);
  margin-bottom: var(--space-xs);
}
.empty-state p { color: var(--ink-muted); font-size: var(--fs-small); }
.empty-state code {
  background: var(--yellow-tint);
  border: 1.5px solid var(--ink);
  border-radius: 6px;
  padding: 1px 7px;
  font-size: 0.85em;
}

/* ============================================================
   SCROLL ANIMATIONS
   ============================================================ */
.animate-on-scroll {
  opacity: 0;
  transform: translateY(28px);
  /* Card hovers use the individual translate/rotate/scale properties so they
     never fight this entrance transform. */
  transition: opacity 0.55s ease-out, transform 0.55s ease-out,
              translate 0.35s var(--ease-bounce), rotate 0.35s var(--ease-bounce),
              scale 0.35s var(--ease-bounce);
}
.animate-on-scroll.visible { opacity: 1; transform: translateY(0); }
/* Above-the-fold cards: no entrance of their own (the page fade covers
   them), but hovers still bounce. */
.animate-on-scroll.no-enter {
  transition: translate 0.35s var(--ease-bounce), rotate 0.35s var(--ease-bounce),
              scale 0.35s var(--ease-bounce);
}

.stagger-children .animate-on-scroll:nth-child(1) { transition-delay: 0.04s; }
.stagger-children .animate-on-scroll:nth-child(2) { transition-delay: 0.08s; }
.stagger-children .animate-on-scroll:nth-child(3) { transition-delay: 0.12s; }
.stagger-children .animate-on-scroll:nth-child(4) { transition-delay: 0.16s; }
.stagger-children .animate-on-scroll:nth-child(5) { transition-delay: 0.20s; }
.stagger-children .animate-on-scroll:nth-child(6) { transition-delay: 0.24s; }
.stagger-children .animate-on-scroll:nth-child(7) { transition-delay: 0.28s; }
.stagger-children .animate-on-scroll:nth-child(8) { transition-delay: 0.32s; }
.stagger-children .animate-on-scroll.no-enter { transition-delay: 0s; }

@media (prefers-reduced-motion: reduce) {
  .animate-on-scroll { opacity: 1; transform: none; transition: none; }
  .marquee-content { animation: none; }
  * { scroll-behavior: auto !important; }
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 768px) {
  .container { padding: 0 var(--space-md); }
  .section { padding: var(--space-xl) 0; }
  .project-grid { grid-template-columns: 1fr; }
  .gallery-grid { grid-template-columns: 1fr 1fr; gap: var(--space-md); }
  .cert-grid { grid-template-columns: 1fr; }
  .footer-inner { flex-direction: column; text-align: center; }
}

@media (max-width: 480px) {
  .gallery-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   PERSONALITY LAYER
   ============================================================ */

/* Text selection matches each page's accent colour (ink text on every
   flat accent passes AA - same combos as the chips/buttons). */
::selection { background: var(--yellow); color: var(--ink); }
.page-coding ::selection { background: var(--blue); color: var(--ink); }
.page-art ::selection { background: var(--periwinkle); color: var(--ink); }
.page-writing ::selection { background: var(--teal); color: var(--ink); }
.page-certs ::selection { background: var(--pink); color: var(--ink); }

/* Art page leans periwinkle, not blue - its focus rings follow. */
.page-art :focus-visible { outline-color: var(--periwinkle); }

/* Visually-hidden utility (screen-reader announcements). */
.vh {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* "About me" chip lifts on hover - same playful swing as the banner chips. */
.about-eyebrow { transition: transform var(--transition), box-shadow var(--transition); }
.about-eyebrow:hover {
  transform: rotate(2deg) translateY(-3px) scale(1.05);
  box-shadow: var(--pop-lg);
}

/* ---------- "CURRENT GOALS" STICKY NOTES (About page) ----------
   One pinned note per goal in its page's colour, each at its own slight
   tilt. Notes that link somewhere straighten and lift on hover. */
.currently-section { padding: 0 0 var(--space-md); }
.goals { text-align: center; }
.goals-heading {
  display: inline-block;
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 600;
  color: var(--ink);
  background: var(--yellow);
  padding: 0 0.3em;
  border-radius: 6px;
  transform: rotate(-1.5deg);
  margin-bottom: var(--space-md);
}
.goals-board {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-md);
  max-width: 980px;
  margin: 0 auto;
  padding-top: 10px;              /* room for the pins */
  text-align: left;
}
.goal-note {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
  height: 100%;
  min-height: 190px;
  padding: 26px 18px 18px;
  background: var(--periwinkle);
  border: var(--border);
  border-radius: 4px;
  box-shadow: var(--pop);
  color: var(--ink);
  transition: rotate var(--transition), translate var(--transition), box-shadow var(--transition);
}
.goal-note.blue { background: var(--blue); }
.goal-note.teal { background: var(--teal); }
.goal-note.yellow { background: var(--yellow); }
.goal-note.pink { background: var(--pink); }
.goals-board li:nth-child(4n+1) .goal-note { rotate: -2.5deg; }
.goals-board li:nth-child(4n+2) .goal-note { rotate: 1.5deg; translate: 0 8px; }
.goals-board li:nth-child(4n+3) .goal-note { rotate: -1deg; }
.goals-board li:nth-child(4n)   .goal-note { rotate: 2.5deg; translate: 0 6px; }
.goals-board li a.goal-note:hover { rotate: 0deg; translate: -2px -4px; box-shadow: var(--pop-lg); }
.goal-pin {
  position: absolute;
  top: -10px;
  left: 50%;
  margin-left: -9px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--ink);
  border: 2.5px solid var(--ink);
  box-shadow: inset 4px 4px 0 -1px var(--white);
}
.goal-icon { display: inline-flex; }
.goal-icon svg { width: 22px; height: 22px; }
.goal-label {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 600;
  margin-top: 6px;
}
.goal-value { font-size: 0.92rem; line-height: 1.5; }
.goal-link {
  margin-top: auto;
  padding-top: var(--space-xs);
  font-family: var(--font-display);
  font-size: var(--fs-small);
}
.goal-note:hover .card-arrow { translate: 4px 0; }

@media (max-width: 820px) {
  .goals-board { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-md) var(--space-sm); }
  .goal-note { min-height: 170px; padding: 24px 14px 14px; }
  .goal-link { font-size: 0.8rem; }
}

/* ---------- GALLERY FILTER CHIPS + SHUFFLE ---------- */
.gallery-filters {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-bottom: var(--space-lg);
}
.filter-chip svg { width: 1.1em; height: 1.1em; vertical-align: -0.2em; margin-right: 6px; }
.filter-chip[aria-pressed="true"] {
  background: var(--ink);
  color: var(--blush);
}
.gallery-item.filtered-out { display: none; }

/* ---------- THE PET WIZARD (mascot, bottom-right) ---------- */
.wizard-buddy {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 900;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
}
.wizard-sprite {
  position: relative;
  width: 120px;
  height: 120px;
  padding: 0;
  transition: transform var(--transition);
}
.wizard-sprite:hover { transform: translateY(-3px); }
.wizard-sprite img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  transform-origin: bottom center;
  /* hard offset, zero blur - stays flat */
  filter: drop-shadow(3px 3px 0 rgba(22, 26, 46, 0.22));
}
.wizard-sprite.asleep img {
  transform: rotate(9deg);
  opacity: 0.85;
  animation: none;
}
.wizard-zzz {
  display: none;
  position: absolute;
  top: -12px;
  right: -8px;
  font-family: var(--font-display);
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--ink);
  background: var(--white);
  border: 2px solid var(--ink);
  border-radius: var(--radius-full);
  padding: 1px 9px;
  box-shadow: var(--pop);
}
.wizard-sprite.asleep .wizard-zzz { display: block; }

.wizard-bubble {
  position: relative;
  max-width: 230px;
  padding: 8px 14px;
  background: var(--white);
  border: var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--pop);
  font-family: var(--font-display);
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--ink);
  text-align: center;
}
.wizard-bubble::after {
  content: '';
  position: absolute;
  bottom: -9px;
  right: 28px;
  width: 13px;
  height: 13px;
  background: var(--white);
  border-right: 2.5px solid var(--ink);
  border-bottom: 2.5px solid var(--ink);
  transform: rotate(45deg);
}
.wizard-bubble[hidden] { display: none; }

/* He politely steps out while the lightbox is open, and on phones and
   tablets (narrow screens, or any touch-first device such as a large iPad).
   Keep this query in sync with WIZARD_HIDDEN_MQ in script.js. */
body:has(dialog[open]) .wizard-buddy { display: none; }
@media (max-width: 1024px), (hover: none) and (pointer: coarse) {
  .wizard-buddy { display: none; }
}

/* Doodle rain - the 10-pet reward. Flat glyphs in brand colours. */
.doodle-rain {
  position: fixed;
  inset: 0;
  z-index: 1200;
  pointer-events: none;
  overflow: hidden;
}
.doodle-rain span {
  position: absolute;
  top: -48px;
  width: 28px;
  height: 28px;
  color: var(--periwinkle);
  animation: doodle-fall 2.5s linear forwards;
}
.doodle-rain span svg { display: block; width: 100%; height: 100%; }
.doodle-rain span:nth-child(3n)   { color: var(--pink); }
.doodle-rain span:nth-child(4n)   { color: var(--teal); }
.doodle-rain span:nth-child(5n)   { color: var(--yellow); }
@keyframes doodle-fall {
  to { transform: translateY(112vh) rotate(310deg); }
}

/* Wizard motion (idle breathing + pet squish) - only when motion is welcome. */
@media (prefers-reduced-motion: no-preference) {
  .wizard-sprite img { animation: wizard-breathe 3.6s ease-in-out infinite; }
  .wizard-sprite.petted img { animation: wizard-squish 0.45s ease; }
}
@keyframes wizard-breathe {
  0%, 100% { transform: scaleY(1); }
  50%      { transform: scaleY(0.96); }
}
@keyframes wizard-squish {
  30% { transform: scaleY(0.74) scaleX(1.18); }
  70% { transform: scaleY(1.08) scaleX(0.94); }
}
/* ---------- 404 PAGE ---------- */
.notfound-box { text-align: center; }
.notfound-wizard {
  width: 140px;
  margin: 0 auto var(--space-md);
  transform: rotate(-6deg);
}
.notfound-text {
  color: var(--ink-soft);
  margin-bottom: var(--space-md);
}

/* ---------- FOOTER TAGLINE ---------- */
.footer-tagline {
  margin-top: var(--space-sm);
  font-size: var(--fs-tiny);
  color: var(--periwinkle);
  opacity: 0.85;
  text-align: center;
  width: 100%;
}

/* ============================================================
   VIEW TRANSITIONS (cross-page morphs - progressive enhancement;
   browsers without support simply navigate as normal)
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }

  /* The header persists untouched. The old page is dropped at once (fading
     it out would leave its pieces floating over the new page), and the new
     page's own page-enter fade (below) is the only fade - everything arrives
     together. */
  .site-header { view-transition-name: site-header; }
  ::view-transition-old(root) { display: none; }
  ::view-transition-new(root) { animation: none; }

  /* Everything except the header fades in as one unit on every page load. */
  .marquee-container,
  main.page-content,
  .site-footer { animation: page-enter 0.16s ease-out backwards; }
}
@keyframes page-enter {
  /* Starts part-visible so the body lands with the header, not after it. */
  from { opacity: 0.4; transform: translateY(4px); }
}

/* ============================================================
   MOTION EXTRAS (marker highlights, press feedback, lightbox morph,
   doodle trail - the gallery glide lives in script.js)
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  /* Yellow highlights are drawn in like a marker pen, left to right. */
  .hl {
    background: linear-gradient(var(--yellow), var(--yellow)) no-repeat 0 0 / 0% 100%;
    animation: hl-draw 0.55s 0.2s cubic-bezier(0.6, 0, 0.3, 1) forwards;
  }

  /* Chips and buttons sink into their flat shadow while pressed. */
  .skill-tag:active {
    transform: translate(3px, 3px);
    box-shadow: 1px 1px 0 var(--ink);
    transition-duration: 0.06s;
  }
  .lightbox-close:active { scale: 0.88; transition-duration: 0.06s; }
  .goals-board li a.goal-note:active {
    translate: 2px 2px;
    box-shadow: 1px 1px 0 var(--ink);
    transition-duration: 0.06s;
  }

  /* Lightbox morph (same-page view transition, started in script.js).
     The page itself just dims; only the picture moves. */
  html.lb-morph .site-header { view-transition-name: none; } /* dims with the page */
  html.lb-morph::view-transition-group(lb-art) {
    animation-duration: 0.38s;
    animation-timing-function: cubic-bezier(0.3, 0.9, 0.3, 1.05);
  }
  html.lb-morph::view-transition-old(lb-art),
  html.lb-morph::view-transition-new(lb-art) {
    animation-duration: 0.38s;
    height: 100%;
  }
  /* Closing: the dimmed page fades away on top while the picture flies home. */
  html.lb-morph.lb-closing::view-transition-old(root) {
    display: block;
    z-index: 1;
    mix-blend-mode: normal;
    animation: lb-undim 0.3s ease-in forwards;
  }
  .lightbox[open]::backdrop { animation: lb-dim 0.3s ease-out; }
}
@keyframes hl-draw { to { background-size: 100% 100%; } }
@keyframes lb-dim { from { opacity: 0; } }
@keyframes lb-undim { to { opacity: 0; } }

/* Doodle trail - unlocked by the wizard's doodle rain. */
.doodle-trail {
  position: fixed;
  left: 0; top: 0;
  z-index: 1300;
  pointer-events: none;
  color: var(--periwinkle);
  animation: trail-fade 0.75s ease-out forwards;
}
.doodle-trail svg { display: block; width: 100%; height: 100%; }
@keyframes trail-fade {
  from { opacity: 1; }
  to   { opacity: 0; transform: translate(var(--dx), var(--dy)) rotate(var(--rot)) scale(0.3); }
}
