/* =====================================================================
   odhranroche.com — site styles
   One stylesheet for every page. Tokens first, then base, layout,
   components, the homepage illustration, and responsive rules.
   The style guide (styleguide.html) documents every token and component
   in this file. Change a value here and it changes everywhere.
   ===================================================================== */

/* ---------- 0. Fonts (self-hosted, SIL Open Font License) ---------- */
@font-face { font-family: "Lexend"; font-style: normal; font-weight: 400; font-display: swap; src: url("../fonts/lexend-latin-400-normal.woff2") format("woff2"); }
@font-face { font-family: "Lexend"; font-style: normal; font-weight: 500; font-display: swap; src: url("../fonts/lexend-latin-500-normal.woff2") format("woff2"); }
@font-face { font-family: "Lexend"; font-style: normal; font-weight: 600; font-display: swap; src: url("../fonts/lexend-latin-600-normal.woff2") format("woff2"); }
@font-face { font-family: "Atkinson Hyperlegible"; font-style: normal; font-weight: 400; font-display: swap; src: url("../fonts/atkinson-hyperlegible-latin-400-normal.woff2") format("woff2"); }
@font-face { font-family: "Atkinson Hyperlegible"; font-style: italic; font-weight: 400; font-display: swap; src: url("../fonts/atkinson-hyperlegible-latin-400-italic.woff2") format("woff2"); }
@font-face { font-family: "Atkinson Hyperlegible"; font-style: normal; font-weight: 700; font-display: swap; src: url("../fonts/atkinson-hyperlegible-latin-700-normal.woff2") format("woff2"); }
@font-face { font-family: "Kalam"; font-style: normal; font-weight: 400; font-display: swap; src: url("../fonts/kalam-latin-400-normal.woff2") format("woff2"); }

/* ---------- 1. Tokens ---------- */
:root {
  color-scheme: light;

  /* Colour. Each family has one meaning:
     soil (tan/brown) = documentation, sky (blue) = training,
     leaf (green) = growth, links and interaction, ink (navy) = text and primary actions. */
  --paper: #fbfcf8;        /* page background */
  --paper-deep: #f3f7ee;   /* alternate section background */
  --white: #ffffff;        /* tiles that hold logos */
  --ink: #1c2b3a;          /* text, primary buttons (14:1 on paper) */
  --ink-soft: #4b5967;     /* secondary text (7:1 on paper) */
  --rule: #dfe5dc;         /* hairlines and tile borders */

  --soil-tint: #ecdcc6;    /* documentation background */
  --soil-line: #b8875a;    /* documentation accents */
  --soil: #7a4a2b;         /* soil in illustrations */

  --sky-tint: #d3eaf8;     /* training background */
  --sky: #3586cf;          /* training accents (graphics only, 3.7:1) */
  --sky-deep: #2a6fb0;     /* blue text, handwritten notes (5.1:1) */

  --leaf-tint: #e5efdb;    /* hover background for quiet controls */
  --leaf-light: #8cc261;   /* young leaves */
  --leaf: #5e9e44;         /* lines, markers, underlines (graphics only, 3.2:1) */
  --leaf-deep: #3f7a2c;    /* green text, primary hover (5.1:1) */

  /* Type. Two faces chosen for legibility, plus a pen for margin notes. */
  --f-display: "Lexend", "Segoe UI", system-ui, sans-serif;
  --f-body: "Atkinson Hyperlegible", "Segoe UI", system-ui, sans-serif;
  --f-hand: "Kalam", "Segoe Print", "Bradley Hand", cursive;

  --t-xs: 0.8125rem;   /* 13px  footer, fine print */
  --t-sm: 0.9375rem;   /* 15px  nav, buttons, captions */
  --t-md: 1.0625rem;   /* 17px  body text */
  --t-lg: 1.25rem;     /* 20px  lead paragraphs, role line */
  --t-xl: clamp(1.6rem, 1.1rem + 1.6vw, 2.15rem);      /* section headings */
  --t-title: clamp(2.2rem, 1.5rem + 2.6vw, 3.2rem);    /* inner page titles */
  --t-display: clamp(2.7rem, 1.6rem + 4vw, 4.4rem);    /* homepage name only */
  --t-hand: 1.15rem;   /* handwritten notes */

  --lh-tight: 1.05;
  --lh-snug: 1.3;
  --lh-body: 1.6;

  /* Space. Use these steps for every gap, margin and padding. */
  --s-1: 0.25rem;   /*  4px */
  --s-2: 0.5rem;    /*  8px */
  --s-3: 0.75rem;   /* 12px */
  --s-4: 1rem;      /* 16px */
  --s-5: 1.5rem;    /* 24px */
  --s-6: 2rem;      /* 32px */
  --s-7: 3rem;      /* 48px */
  --s-8: 4.5rem;    /* 72px */
  --section-y: clamp(3rem, 6vw, 5rem);

  /* Layout */
  --wrap: 72rem;
  --measure: 36rem;                     /* max width of running text (~65 characters) */
  --gutter: clamp(1rem, 4vw, 2.5rem);

  /* Shape */
  --r-sm: 6px;     /* stickers, small controls */
  --r-md: 10px;    /* buttons, nav items, tiles */
  --tap: 2.75rem;  /* 44px minimum touch target */

  /* Motion */
  --d-fast: 150ms;
  --d-med: 300ms;
  --ease-out: cubic-bezier(.2, .8, .3, 1);
  --ease-spring: cubic-bezier(.3, 1.4, .5, 1);
}

/* ---------- 2. Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--f-body);
  font-size: var(--t-md);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
}
main { flex: 1 0 auto; }
img, svg { max-width: 100%; }
a { color: inherit; }
/* links in running text (links with a class style themselves) */
a:not([class]) { text-decoration-color: var(--leaf); text-decoration-thickness: 2px; text-underline-offset: 3px; }
a:not([class]):hover { text-decoration-color: var(--ink); }
p { margin: 0; }
h1, h2, h3 {
  font-family: var(--f-display);
  font-weight: 600;
  line-height: var(--lh-snug);
  letter-spacing: -0.02em;
  margin: 0;
  text-wrap: balance;
}
h2 { font-size: var(--t-xl); line-height: 1.15; letter-spacing: -0.025em; }
h3 { font-size: var(--t-lg); font-weight: 500; letter-spacing: -0.01em; }
:focus-visible { outline: 3px solid var(--sky); outline-offset: 3px; border-radius: 4px; }
::selection { background: var(--leaf-tint); }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.skip-link {
  position: absolute;
  left: var(--s-4);
  top: -4rem;
  z-index: 20;
  padding: var(--s-2) var(--s-4);
  background: var(--ink);
  color: var(--white);
  border-radius: var(--r-md);
  font-family: var(--f-display);
  font-size: var(--t-sm);
  text-decoration: none;
}
.skip-link:focus { top: var(--s-2); }

/* ---------- 3. Layout ---------- */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
  /* keep content clear of the notch on phones held sideways (the viewport uses viewport-fit=cover) */
  padding-left: max(var(--gutter), env(safe-area-inset-left, 0px));
  padding-right: max(var(--gutter), env(safe-area-inset-right, 0px));
}
.section { padding-block: var(--section-y); }
.section + .section { border-top: 1px solid var(--rule); }
.section-alt { background: linear-gradient(var(--paper), var(--paper-deep)); border-top: 1px solid var(--rule); }

/* Page head: the top of every inner page. One h1, one short lede. */
.page-head { display: grid; gap: var(--s-4); padding-block: var(--s-7) var(--s-6); }
.page-head h1 { font-size: var(--t-title); line-height: 1.08; letter-spacing: -0.03em; }
.page-head .lede { font-size: var(--t-lg); line-height: 1.55; color: var(--ink-soft); }

/* Section header: heading first, one short lede below. Used at the top of every section. */
.section-head { display: grid; gap: var(--s-3); }
.section-head .lede { color: var(--ink-soft); }

/* ---------- 4. Components ---------- */

/* Header */
.site-header {
  position: sticky;
  top: env(safe-area-inset-top, 0px);
  z-index: 10;
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--d-med);
}
.site-header.scrolled { border-bottom-color: var(--rule); }
.site-header .wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2) var(--s-5);
  padding-block: var(--s-3);
}
.nav { display: flex; flex-wrap: wrap; gap: var(--s-1); }
.nav a {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding-inline: var(--s-3);
  border-radius: var(--r-md);
  font-family: var(--f-display);
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--ink-soft);
  text-decoration: none;
  transition: background-color var(--d-fast), color var(--d-fast);
}
.nav a:hover { background: var(--leaf-tint); color: var(--ink); }
.nav a[aria-current="page"],
.nav-group:has([aria-current="page"]) .nav-trigger { color: var(--ink); }
/* current page: a hand-drawn green underline */
.nav a[aria-current="page"]::after,
.nav-group:has([aria-current="page"]) .nav-trigger::after {
  content: "";
  position: absolute;
  left: var(--s-3); right: var(--s-3); bottom: .45rem;
  height: 7px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 7' preserveAspectRatio='none'%3E%3Cpath d='M2 4.5 C14 1.5 26 6 38 3.5 S54 2.5 58 3.8' fill='none' stroke='%235e9e44' stroke-width='2.6' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat center / 100% 100%;
}
.nav-group { position: relative; }
.nav-trigger {
  position: relative;
  display: inline-flex; align-items: center; gap: .35rem; min-height: var(--tap); padding-inline: var(--s-3);
  border: 0; border-radius: var(--r-md); background: none; cursor: pointer;
  font-family: var(--f-display); font-size: var(--t-sm); font-weight: 500; color: var(--ink-soft);
  transition: background-color var(--d-fast), color var(--d-fast);
}
.nav-trigger svg { width: .75em; height: .75em; }
.nav-group.is-open .nav-trigger { background: var(--leaf-tint); color: var(--ink); }
/* The menu opens when the button is pressed (site.js), or on hover where there is a mouse. */
.nav-menu {
  display: none; position: absolute; top: 100%; left: 0; z-index: 20; min-width: 12rem; margin: 0; padding: var(--s-2);
  list-style: none; background: var(--paper); border: 1px solid var(--rule); border-radius: var(--r-md);
  box-shadow: 0 8px 24px rgba(20, 30, 50, .12);
}
.nav-group.is-open .nav-menu { display: block; }
@media (hover: hover) {
  .nav-group:hover .nav-trigger { background: var(--leaf-tint); color: var(--ink); }
  .nav-group:hover .nav-menu { display: block; }
}
.nav-menu a { display: flex; width: 100%; }
.header-actions { display: flex; align-items: center; gap: var(--s-2); }

/* Buttons. One primary (filled) button per screen; everything else is quiet. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: var(--tap);
  padding: 0 var(--s-5);
  border: 2px solid var(--ink);
  border-radius: var(--r-md);
  background: var(--ink);
  color: var(--white);
  font-family: var(--f-display);
  font-size: var(--t-sm);
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--d-fast), border-color var(--d-fast), transform var(--d-fast);
}
.btn:hover { background: var(--leaf-deep); border-color: var(--leaf-deep); }
.btn:active { transform: translateY(1px); }
.btn svg { width: 1em; height: 1em; flex: none; }
.btn-quiet { background: transparent; color: var(--ink); }
.btn-quiet:hover { background: var(--leaf-tint); border-color: var(--leaf-deep); color: var(--ink); }

/* Icon-only button: always give it an aria-label and a title */
.icon-btn {
  display: inline-grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  border-radius: var(--r-md);
  color: var(--ink);
  transition: background-color var(--d-fast);
}
.icon-btn:hover { background: var(--leaf-tint); }
.icon-btn img { width: 26px; height: 26px; display: block; }
.icon-btn .fallback-icon { display: none; width: 24px; height: 24px; }
.icon-btn.no-icon img { display: none; }
.icon-btn.no-icon .fallback-icon { display: block; }

/* Text link: for secondary actions next to a button, and links in running text */
.text-link {
  font-family: var(--f-display);
  font-size: var(--t-sm);
  font-weight: 500;
  text-decoration: underline;
  text-decoration-color: var(--leaf);
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
  transition: text-decoration-color var(--d-fast);
}
.text-link:hover { text-decoration-color: var(--ink); }
/* Text link with a leading icon, e.g. the download links on the CV page */
.text-link.has-icon { display: inline-flex; align-items: center; gap: 0.4em; }
.text-link.has-icon svg { width: 1em; height: 1em; flex: none; }

/* Topic marks: a highlighter stroke that ties a word to its colour family */
.mark-docs, .mark-training {
  font-weight: 700;
  font-style: normal;
  background-repeat: no-repeat;
  background-size: 100% 38%;
  background-position: 0 88%;
  transition: background-size var(--d-med) var(--ease-out);
}
.mark-docs { background-image: linear-gradient(var(--soil-tint), var(--soil-tint)); }
.mark-training { background-image: linear-gradient(var(--sky-tint), var(--sky-tint)); }
.mark-docs.is-on, .mark-training.is-on { background-size: 100% 100%; }

/* Handwritten note: max one per screen. Always points at something. */
.hand-note {
  font-family: var(--f-hand);
  font-size: var(--t-hand);
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: 0;
  color: var(--sky-deep);
  transform: rotate(-3deg);
}

/* Status line with a sprout */
.status { display: flex; align-items: center; gap: var(--s-2); font-size: var(--t-sm); color: var(--ink-soft); }
.status svg { width: 18px; height: 18px; flex: none; }

/* Logo tile: the only bordered box on the site, because logos need a neutral ground */
.logo-tile {
  display: grid;
  place-items: center;
  width: 100%;
  max-width: 11rem;
  height: 4.5rem;
  padding: var(--s-2) var(--s-4);
  background: var(--white);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  transition: border-color var(--d-med), transform var(--d-med) var(--ease-out);
}
.logo-tile img { max-width: 100%; max-height: 2.6rem; object-fit: contain; }
.logo-tile .logo-name {
  display: none;
  font-family: var(--f-display);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.15;
  letter-spacing: -0.01em;
  text-align: center;
}
.logo-tile.no-logo img { display: none; }
.logo-tile.no-logo .logo-name { display: block; }

/* Career vine (timeline). Oldest on the left, most recent on the right. */
.vine { position: relative; margin-top: var(--s-7); }
.vine-line { position: absolute; left: 0; right: 0; top: 30px; width: 100%; height: 40px; overflow: visible; }
.vine-line path { fill: none; stroke: var(--leaf); stroke-width: 3; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.vine ol { position: relative; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--s-4); list-style: none; margin: 0; padding: 0; }
.job { display: flex; flex-direction: column; align-items: center; min-width: 0; text-align: center; }
.job-text { display: flex; flex-direction: column; align-items: center; width: 100%; min-width: 0; }
.job .bud { width: 44px; height: 60px; overflow: visible; transform-origin: 50% 100%; transition: transform var(--d-med) var(--ease-spring); }
.job:nth-child(even) .bud { transform: scaleX(-1); }
.job:hover .bud { transform: rotate(-8deg) scale(1.12); }
.job:nth-child(even):hover .bud { transform: scaleX(-1) rotate(-8deg) scale(1.12); }
.job:hover .logo-tile { border-color: var(--leaf); transform: translateY(-2px); }
.bud .stalk { fill: none; stroke: var(--leaf); stroke-width: 3; stroke-linecap: round; }
.bud .lf { fill: var(--leaf-light); }
.bud .lf2 { fill: var(--leaf); }
.job .logo-tile { margin-top: var(--s-3); }
.job .title { margin-top: var(--s-3); font-size: var(--t-sm); line-height: var(--lh-snug); color: var(--ink-soft); text-wrap: balance; }
.job.latest .title { color: var(--ink); font-weight: 700; }
.job .hand-note { margin-top: var(--s-2); color: var(--leaf-deep); font-size: 1.05rem; }

/* Footer: one line, small */
.site-footer { border-top: 1px solid var(--rule); font-size: var(--t-xs); color: var(--ink-soft); }
.site-footer .wrap { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: var(--s-3) var(--s-5); padding-block: var(--s-3); }
.site-footer .sticker { justify-self: start; }
.site-footer .copyright { justify-self: center; text-align: center; }
.site-footer .copy-email { justify-self: end; }
.sticker {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: .35rem .65rem .3rem;
  background: var(--soil-tint);
  border-radius: var(--r-sm);
  box-shadow: 1px 2px 0 rgba(28, 43, 58, .15);
  font-family: var(--f-hand);
  font-size: .95rem;
  line-height: 1;
  color: var(--ink);
  transform: rotate(-3deg);
}
.sticker svg { width: 14px; height: 14px; }
.copy-email {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 2.25rem;
  padding: 0 var(--s-3);
  background: none;
  border: 1px dashed var(--rule);
  border-radius: var(--r-sm);
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  transition: border-color var(--d-fast);
}
.copy-email:hover { border-color: var(--leaf); }
.copy-email svg { width: 13px; height: 13px; }
.copy-email .done { color: var(--leaf-deep); font-weight: 700; }
.copy-email .done:empty { display: none; }
.copy-email.copied .ico { display: none; }

/* ---------- 5. Homepage ---------- */
.hero .wrap {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  align-items: center;
  gap: clamp(1.5rem, 4vw, 4rem);
  padding-block: clamp(2rem, 5vw, 4.5rem) clamp(1rem, 3vw, 2rem);
}
/* When the hero is the homepage's only section, centre it in the space between header and footer */
main:has(> .hero:only-child) { display: grid; align-content: center; }
main:has(> .hero:only-child) .hero .wrap { padding-block: clamp(2rem, 5vw, 4.5rem); }
.hero-text { min-width: 0; }
.name-row { padding-top: 2.6rem; }
.hero h1 { font-size: var(--t-display); line-height: 1.02; letter-spacing: -0.035em; }
.hero h1 .first { position: relative; display: inline-block; }
/* the pronunciation note sits above, and points at, the first name at every width */
.say-it {
  position: absolute;
  left: 30%;
  bottom: 100%;
  display: flex;
  align-items: flex-start;
  gap: .3rem;
  white-space: nowrap;
  transform-origin: left bottom;
  pointer-events: none;
}
.say-it svg { flex: none; width: 24px; height: 34px; margin-top: .45rem; }
.role { margin-top: var(--s-3); font-family: var(--f-display); font-size: var(--t-lg); color: var(--leaf-deep); }
.lead { margin-top: var(--s-5); font-size: var(--t-lg); line-height: 1.55; max-width: 34rem; }
.hero .status { margin-top: var(--s-5); }
.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3) var(--s-5); margin-top: var(--s-5); }

/* The garden: one scene. Soil (documentation) and water (training) feed a plant (reliable growth).
   site.js sets data-active="docs" or "training" on the figure while a part is hovered or focused. */
.garden-fig { position: relative; margin: 0; min-width: 0; }
.garden { display: block; width: 100%; max-width: 440px; height: auto; margin-inline: auto; overflow: visible; }
.garden text { font-family: var(--f-display); fill: var(--ink); }
.garden .label { font-size: 26px; font-weight: 500; letter-spacing: -0.01em; }
.garden .label-big { font-size: 30px; font-weight: 600; letter-spacing: -0.02em; }
.node { cursor: pointer; outline: none; transition: opacity var(--d-med); }
.node .hit { fill: transparent; stroke: transparent; stroke-width: 3; }
.node:focus-visible .hit { stroke: var(--ink); }
.garden-fig[data-active="docs"] .node-training,
.garden-fig[data-active="training"] .node-docs { opacity: .75; }
.tint { opacity: 0; transition: opacity var(--d-med); }
.tint-docs { fill: var(--soil-tint); }
.tint-training { fill: var(--sky-tint); }
.garden-fig[data-active="docs"] .tint-docs,
.garden-fig[data-active="training"] .tint-training { opacity: 1; }

/* Documentation: the written layers become legible, roots reach down, seeds sprout */
.lines { fill: none; stroke: #f0c27e; stroke-width: 3; stroke-linecap: round; opacity: .28; transition: opacity var(--d-med); }
.garden-fig[data-active="docs"] .lines { opacity: .7; }
.root { stroke-dasharray: 1 1; stroke-dashoffset: .38; transition: stroke-dashoffset 700ms var(--ease-out); animation: roots 1.2s var(--ease-out) .5s backwards; }
.garden-fig[data-active="docs"] .root { stroke-dashoffset: 0; }
@keyframes roots { from { stroke-dashoffset: 1; } }
.sprout-s { transform-box: fill-box; transform-origin: 50% 100%; transform: scale(0); transition: transform 350ms cubic-bezier(.3, 1.5, .5, 1); }
.garden-fig[data-active="docs"] .sprout-s { transform: scale(1); }

/* Training: the can tips further, water pours, the soil darkens where it lands */
.can-tilt { transform-box: view-box; transform-origin: 0 0; transition: transform 450ms cubic-bezier(.3, 1.3, .5, 1); }
.garden-fig[data-active="training"] .can-tilt { transform: rotate(-8deg); }
.drop { transform-box: fill-box; }
.garden-fig[data-active="training"] .drop { animation: fall .9s linear infinite; }
.garden-fig[data-active="training"] .drop:nth-of-type(2) { animation-delay: -.15s; }
.garden-fig[data-active="training"] .drop:nth-of-type(3) { animation-delay: -.3s; }
.garden-fig[data-active="training"] .drop:nth-of-type(4) { animation-delay: -.45s; }
.garden-fig[data-active="training"] .drop:nth-of-type(5) { animation-delay: -.6s; }
.garden-fig[data-active="training"] .drop:nth-of-type(6) { animation-delay: -.75s; }
@keyframes fall {
  0% { transform: translate(0, -12px); opacity: 0; }
  25%, 70% { opacity: 1; }
  100% { transform: translate(-3px, 14px); opacity: 0; }
}
.wet { opacity: 0; transition: opacity 600ms var(--ease-out); }
.garden-fig[data-active="training"] .wet { opacity: .55; }

/* Growth: the plant grows once on load (on the outer .plant-intro group), and stands a little taller when either
   part is active (on the inner .plant). Keeping the two on separate elements means hover never restarts the load
   animation, so the plant doesn't vanish and regrow when the cursor leaves. */
.plant-intro { transform-box: fill-box; transform-origin: 50% 100%; animation: grow 1.1s cubic-bezier(.25, 1.2, .45, 1) .15s both; }
@keyframes grow { from { transform: scale(.2, 0); } to { transform: scale(1); } }
.plant { transform-box: fill-box; transform-origin: 50% 100%; transition: transform 500ms var(--ease-spring); }
.garden-fig[data-active] .plant { transform: scale(1.03, 1.05); }

/* Ladybug easter egg: click her and she opens her wing cases and flies off the way she faces (site.js adds .is-flying) */
.ladybug { cursor: pointer; transform-box: fill-box; transform-origin: 50% 50%; }
.ladybug .bug-hit { fill: transparent; }
.ladybug .elytron, .ladybug .wing { transform-box: view-box; transform-origin: 0 0; transition: transform 220ms var(--ease-out, ease-out); }
.ladybug .bug-wings { opacity: 0; transition: opacity 150ms; }
.ladybug:hover .elytron-a { transform: rotate(8deg); }
.ladybug:hover .elytron-b { transform: rotate(-8deg); }
.ladybug.is-flying { pointer-events: none; animation: bug-fly 1.6s cubic-bezier(.5, 0, .75, .6) .25s forwards; }
.ladybug.is-flying .elytron-a { transform: rotate(32deg); }
.ladybug.is-flying .elytron-b { transform: rotate(-32deg); }
.ladybug.is-flying .bug-wings { opacity: .85; }
.ladybug.is-flying .wing-a { animation: wing-a 70ms linear infinite alternate; }
.ladybug.is-flying .wing-b { animation: wing-b 70ms linear infinite alternate; }
@keyframes wing-a { from { transform: rotate(8deg); } to { transform: rotate(40deg); } }
@keyframes wing-b { from { transform: rotate(-8deg); } to { transform: rotate(-40deg); } }
@keyframes bug-fly {
  /* straight ahead, in the direction she faces (up and to the left, about 34° above horizontal) */
  0%   { transform: translate(0, 0); opacity: 1; }
  60%  { opacity: 1; }
  100% { transform: translate(-290px, -196px) scale(.7); opacity: 0; }
}

/* the "Reliable growth" underline lengthens whenever soil or water is active */
.grow-line { stroke-dasharray: 1 1; stroke-dashoffset: .7; transition: stroke-dashoffset 700ms var(--ease-out); }
.garden-fig[data-active] .grow-line { stroke-dashoffset: 0; }

.garden-note {
  min-height: 3.2em;
  max-width: 30rem;
  margin: var(--s-2) auto 0;
  font-size: var(--t-sm);
  color: var(--ink-soft);
  text-align: center;
  text-wrap: balance;
}
.garden-note b { font-family: var(--f-display); font-weight: 500; color: var(--ink); }
/* touch screens can't hover, so the note would only ever be an empty gap */
@media (hover: none) { .garden-note { display: none; } }

/* ---------- 6. Inner pages ---------- */

/* Hand-drawn underline under a heading, coloured by topic */
.hand-u { display: inline-block; padding-bottom: .55rem; background: no-repeat left bottom / 4.5rem 8px; }
.hand-u.docs { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 8' preserveAspectRatio='none'%3E%3Cpath d='M2 5C20 2 44 6.5 60 4S74 3 78 4.2' fill='none' stroke='%23b8875a' stroke-width='3.2' stroke-linecap='round'/%3E%3C/svg%3E"); }
.hand-u.training { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 8' preserveAspectRatio='none'%3E%3Cpath d='M2 5C20 2 44 6.5 60 4S74 3 78 4.2' fill='none' stroke='%233586cf' stroke-width='3.2' stroke-linecap='round'/%3E%3C/svg%3E"); }
.hand-u.growth { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 8' preserveAspectRatio='none'%3E%3Cpath d='M2 5C20 2 44 6.5 60 4S74 3 78 4.2' fill='none' stroke='%235e9e44' stroke-width='3.2' stroke-linecap='round'/%3E%3C/svg%3E"); }

/* Quiet link row under a page head */
.link-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-5); }

/* Skill map: the skills page's one bold element. Three garden plots, one per topic. */
.skill-map { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3.2fr) minmax(0, 1.6fr); gap: var(--s-3); margin-bottom: var(--s-7); }
.plot { display: grid; align-content: start; gap: var(--s-3); padding: var(--s-5); border-radius: var(--r-md); }
.plot-docs { background: var(--soil-tint); }
.plot-training { background: var(--sky-tint); }
.plot-growth { background: var(--leaf-tint); }
.plot-head { display: flex; align-items: center; gap: var(--s-3); }
.plot-head svg { flex: none; width: 46px; height: 38px; }
.plot-title { font-family: var(--f-display); font-size: var(--t-lg); font-weight: 500; line-height: 1.2; }
.plot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px var(--s-4); }
.plot-training ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.plot a {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-2);
  min-height: var(--tap); margin-inline: calc(-1 * var(--s-2)); padding-inline: var(--s-2);
  border-radius: var(--r-sm);
  font-family: var(--f-display); font-weight: 500; text-decoration: none;
  transition: background-color var(--d-fast);
}
.plot a:hover { background: rgba(255, 255, 255, .65); }
.plot a svg { flex: none; width: 12px; height: 12px; opacity: .6; transition: transform var(--d-med) var(--ease-spring); }
.plot a:hover svg { transform: translateY(2px); }

/* Skill group and skill rows */
.skill-group { padding-block: var(--section-y) 0; border-top: 1px solid var(--rule); scroll-margin-top: 4rem; }
/* Skill row: the evidence (.skill-media, placed right after the h3) floats right with breathing room,
   and the text wraps around it, then runs the full width below it. */
.skill { display: flow-root; padding-block: var(--s-7); scroll-margin-top: 5rem; }
.skill + .skill { border-top: 1px solid var(--rule); }
.skill h3 { font-size: clamp(1.35rem, 1.1rem + .8vw, 1.6rem); font-weight: 600; letter-spacing: -0.02em; }
.skill .summary { margin-top: var(--s-3); font-size: var(--t-lg); line-height: 1.5; }
.did { margin: var(--s-4) 0 0; padding-left: 1.15rem; }
.did li + li { margin-top: var(--s-2); }
.did li::marker { color: var(--leaf); }
.meta { margin: var(--s-5) 0 0; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--s-1) var(--s-4); font-size: var(--t-sm); color: var(--ink-soft); }
.meta dt { font-family: var(--f-display); font-weight: 500; color: var(--ink); }
.meta dd { margin: 0; }
.skill-media { float: right; width: min(46%, 34rem); margin: var(--s-4) 0 var(--s-5) var(--s-7); display: grid; align-content: start; gap: var(--s-4); }

/* Screenshot: hairline frame so white UI doesn't melt into the page. Click to enlarge. */
.shot { margin: 0; display: grid; gap: var(--s-2); min-width: 0; }
.shot a { display: block; overflow: hidden; background: var(--white); border: 1px solid var(--rule); border-radius: var(--r-md); cursor: zoom-in; transition: border-color var(--d-fast); }
.shot a:hover { border-color: var(--leaf); }
.shot img { display: block; width: 100%; height: auto; }
.shot figcaption { font-size: var(--t-sm); color: var(--ink-soft); }
/* Tall screenshots (a newsletter, a long page): the frame shows the top part; clicking opens the whole image */
.shot-crop { max-width: 26rem; }
.skill-media:has(> .shot-crop:only-child) { width: min(46%, 26rem); }
.shot-crop img { aspect-ratio: 4 / 5; object-fit: cover; object-position: top; }
.media-note { font-size: var(--t-sm); color: var(--ink-soft); }
.shots-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
.frames { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
.frames .shot figcaption { font-family: var(--f-display); font-weight: 500; color: var(--ink); }

/* Image viewer (a native dialog) */
.viewer { width: min(96vw, 1400px); max-height: 94vh; padding: 0; border: 0; background: transparent; color: var(--white); overflow: visible; }
.viewer::backdrop { background: rgba(20, 31, 43, .95); backdrop-filter: blur(4px); }
.viewer-inner { display: grid; gap: var(--s-3); justify-items: center; }
.viewer img { display: block; max-width: 100%; max-height: 80vh; width: auto; height: auto; border-radius: var(--r-md); background: var(--white); }
.viewer p { max-width: 46rem; text-align: center; font-size: var(--t-sm); }
.viewer .btn { justify-self: end; background: var(--paper); color: var(--ink); border-color: var(--paper); }
.viewer .btn:hover { background: var(--leaf-tint); border-color: var(--leaf-tint); }

/* Plain list with sprout bullets */
.sprout-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-2); }
.sprout-list li { position: relative; padding-left: 28px; }
.sprout-list li::before { content: ""; position: absolute; left: 0; top: .2em; width: 18px; height: 18px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Cpath d='M9 17V9' stroke='%233f7a2c' stroke-width='2' stroke-linecap='round'/%3E%3Cpath d='M9 10C9 6 6 4 2.5 4.5 2.5 8 5 10 9 10Z' fill='%238cc261'/%3E%3Cpath d='M9 8c0-3.5 2.5-6 6.5-5.5C15.5 6 13 8.5 9 8Z' fill='%235e9e44'/%3E%3C/svg%3E") no-repeat center / contain; }

/* Panel: a tinted area for a short aside. Use sparingly. */
.panel { display: grid; gap: var(--s-3); padding: var(--s-5); border-radius: var(--r-md); background: var(--paper-deep); }
.panel-title { font-family: var(--f-display); font-weight: 500; }

/* CV: a vertical vine through the roles, dates in the margin */
.entries { --date-col: 10.5rem; position: relative; list-style: none; margin: var(--s-6) 0 0; padding: 0; display: grid; gap: var(--s-7); }
.entries::before { content: ""; position: absolute; left: calc(var(--date-col) + var(--s-5) - 1.5px); top: .5rem; bottom: .5rem; width: 3px; border-radius: 2px; background: var(--leaf); }
.entry { position: relative; display: grid; grid-template-columns: var(--date-col) minmax(0, 1fr); gap: var(--s-2) var(--s-7); }
.entry::before { content: ""; position: absolute; left: calc(var(--date-col) + var(--s-5) - 12px); top: .1rem; width: 24px; height: 24px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='11' fill='%23fbfcf8'/%3E%3Cpath d='M12 19v-6' stroke='%233f7a2c' stroke-width='2' stroke-linecap='round'/%3E%3Cpath d='M12 14c0-4-3-6-7-5.5 0 4 3 5.5 7 5.5Z' fill='%238cc261'/%3E%3Cpath d='M12 12c0-4 3-6.5 7-6 0 4-3 6-7 6Z' fill='%235e9e44'/%3E%3C/svg%3E") no-repeat center / contain; }
.entry .when { white-space: nowrap; padding-top: .2rem; font-family: var(--f-display); font-size: var(--t-sm); color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.entry h3 { font-size: var(--t-lg); font-weight: 600; }
.entry .org, .qual-row .org { font-family: var(--f-display); font-weight: 500; color: var(--leaf-deep); }
.entry .place { font-size: var(--t-sm); color: var(--ink-soft); }
.entry ul { margin: var(--s-3) 0 0; padding-left: 1.15rem; list-style: disc; display: grid; gap: var(--s-1); }
.entry li::marker { color: var(--leaf); }
.sprout-list.cols { grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr)); gap: var(--s-3) var(--s-7); margin-top: var(--s-5); }
.muted { color: var(--ink-soft); }
.section-first { padding-top: var(--s-6); }
.print-only { display: none; }

/* Projects: one row per project, name on the left, story on the right */
.project { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr); gap: var(--s-4) var(--s-7); padding-block: var(--s-7); border-top: 1px solid var(--rule); scroll-margin-top: 4rem; }
.project h2 { font-size: clamp(1.35rem, 1.1rem + .8vw, 1.6rem); }
.project h2 a { color: inherit; text-decoration: none; }
.project h2 a:hover { color: var(--leaf-deep); }
.project .status { margin-top: var(--s-2); }
.project-body { display: grid; gap: var(--s-4); max-width: var(--measure); }
.project-body .link-row { margin-top: var(--s-1); }
.project-body .did { margin-top: 0; }
.project-gallery { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-3); }
.archived { margin-top: var(--s-2); font-family: var(--f-display); font-size: var(--t-sm); color: var(--ink-soft); }

/* Qualifications: one row per group, like the CV. Name and a short fact on the left, details on the right,
   hairlines between rows. Long lists flow down two columns so they read top to bottom. */
.qual-rows { margin-top: var(--s-5); }
.qual-row { display: grid; grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); gap: var(--s-3) var(--s-7); padding-block: var(--s-5); border-top: 1px solid var(--rule); }
.qual-row:first-child { border-top: 0; padding-top: 0; }
.qual-head { display: grid; align-content: start; gap: var(--s-1); }
.qual-meta { font-size: var(--t-sm); color: var(--ink-soft); }
.qual-body { display: grid; gap: var(--s-5); min-width: 0; }
.qual-body > p { max-width: 42rem; }
.qual-topics { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr)); gap: var(--s-5) var(--s-7); }
.qual-topics h4 { margin: 0 0 var(--s-3); font-family: var(--f-display); font-size: var(--t-sm); font-weight: 500; color: var(--ink-soft); }
.qual-list { display: block; columns: 2 17rem; column-gap: var(--s-7); }
.qual-list li { break-inside: avoid; margin-bottom: var(--s-2); }

/* Contact: a photo beside a warm note, with the address as the page's bold element */
.page-end { padding-bottom: var(--s-8); }
.contact-layout { display: grid; grid-template-columns: minmax(0, 21rem) minmax(0, 1fr); gap: var(--s-6) var(--s-8); align-items: center; padding-top: var(--s-7); }
.contact-photo { position: relative; margin: 0; }
/* a soft tinted block sits behind the photo, offset down and to the right */
.contact-photo::before { content: ""; position: absolute; inset: var(--s-5) calc(-1 * var(--s-4)) calc(-1 * var(--s-4)) var(--s-5); border-radius: 18px; background: var(--soil-tint); }
.contact-photo img { position: relative; display: block; width: 100%; height: auto; border-radius: 18px; }
.contact-body { min-width: 0; }
@media (max-width: 1000px) { .contact-layout { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); gap: var(--s-6); } }
.contact-body .page-head { padding-block: 0 var(--s-6); }
.contact-card { display: grid; gap: var(--s-5); justify-items: start; }
.email-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-4); }
.contact-email { font-family: var(--f-display); font-weight: 600; font-size: clamp(1.3rem, 1rem + 1.2vw, 2.15rem); letter-spacing: -0.02em; overflow-wrap: anywhere; }
.copy-email.contact-email { gap: var(--s-3); max-width: 100%; min-height: 0; padding: var(--s-4) var(--s-5); border: 2px dashed var(--leaf); border-radius: var(--r-md); background: var(--white); line-height: 1.2; text-align: left; }
.copy-email.contact-email:hover { border-color: var(--leaf-deep); background: var(--leaf-tint); }
.copy-email.contact-email svg { width: 1.1rem; height: 1.1rem; flex: none; }
.copy-email.contact-email .done { font-family: var(--f-body); font-size: var(--t-sm); }
.contact-hint { margin-top: calc(-1 * var(--s-4)); font-size: var(--t-sm); color: var(--ink-soft); }
.social { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); margin: 0; padding: var(--s-5) 0 0; list-style: none; border-top: 1px solid var(--rule); justify-self: stretch; }
.social-link {
  display: inline-flex; align-items: center; gap: var(--s-3);
  min-height: var(--tap); padding-inline: var(--s-3); margin-left: calc(-1 * var(--s-3));
  border-radius: var(--r-md);
  font-family: var(--f-display); font-weight: 500; text-decoration: none;
  transition: background-color var(--d-fast);
}
.social-link:hover { background: var(--leaf-tint); }
.social-link img { width: 24px; height: 24px; display: block; }
.social-link .fallback-icon { display: none; width: 24px; height: 24px; }
.social-link.no-icon img { display: none; }
.social-link.no-icon .fallback-icon { display: block; }

/* References: word cloud. Colours follow the site families: green = growth, blue = people/training, soil = craft/documentation */
.wc-fig { margin: 0 0 var(--s-7); }
.wc { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: .4em 1.4em; padding: 0 var(--s-3) var(--s-5); line-height: 1.1; font-family: var(--f-display); font-size: min(1rem, 3.6vw); }
/* each word's size is set in em in the HTML, so the whole cloud scales down on small screens */
.wc span { white-space: nowrap; cursor: default; }
.wc-lead { color: var(--leaf-deep); }
.wc-char { color: var(--sky-deep); }
.wc-skill { color: var(--soil); }
.wc-legend { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-2) var(--s-5); padding-bottom: var(--s-2); font-size: var(--t-sm); color: var(--ink-soft); }
.wc-legend i { display: inline-block; width: 12px; height: 12px; border-radius: 3px; margin-right: 8px; vertical-align: -1px; }
.k-lead { background: var(--leaf); } .k-char { background: var(--sky); } .k-skill { background: var(--soil-line); }

/* Reference quotes */
.quotes { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr)); gap: var(--s-5); margin-top: var(--s-6); }
.quote { position: relative; display: flex; flex-direction: column; justify-content: space-between; gap: var(--s-4); margin: 0; padding: var(--s-5); background: var(--white); border: 1px solid var(--rule); border-left: 4px solid var(--leaf); border-radius: var(--r-md); }
.quote:nth-child(3n+2) { border-left-color: var(--sky); }
.quote:nth-child(3n) { border-left-color: var(--soil-line); }
.quote blockquote { margin: 0; }
.quote p { margin: 0; line-height: 1.6; }
.quote figcaption { display: grid; gap: 2px; font-size: var(--t-sm); color: var(--ink-soft); }
.quote figcaption b { font-family: var(--f-display); font-weight: 500; color: var(--ink); }

/* ---------- 7. Responsive ---------- */
@media (max-width: 860px) {
  .hero .wrap { grid-template-columns: minmax(0, 1fr); }
  .garden { max-width: 340px; }
  .garden .label { font-size: 29px; }
  .garden .label-big { font-size: 33px; }
  .vine-line { display: none; }
  .vine ol { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .vine ol::before { content: ""; position: absolute; left: 21px; top: 0; bottom: 0; width: 3px; background: var(--leaf); border-radius: 2px; }
  .job { flex-direction: row; align-items: center; gap: var(--s-4); padding-block: var(--s-3); text-align: left; }
  .job-text { align-items: flex-start; }
  .job .bud { flex: none; width: 44px; height: 44px; }
  .job .bud .stalk { display: none; }
  .job:nth-child(even) .bud { transform: none; }
  .job .logo-tile { margin-top: 0; width: 9rem; flex: none; height: 3.6rem; }
  .job .title, .job .hand-note { margin-top: 0; }
  .project { grid-template-columns: minmax(0, 1fr); }
  .skill-map { grid-template-columns: minmax(0, 1fr); }
  .skill-media { float: none; width: auto; margin: var(--s-4) 0 var(--s-5); }
}
@media (max-width: 700px) {
  .entries { padding-left: var(--s-6); }
  .entries::before { left: 10px; }
  .entry { grid-template-columns: minmax(0, 1fr); }
  .entry::before { left: calc(-1 * var(--s-6)); }
  .contact-layout { grid-template-columns: minmax(0, 1fr); padding-top: var(--s-6); }
  .contact-photo { width: min(16rem, 70%); margin-left: var(--s-4); }
  .qual-row { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 600px) {
  .copy-email.contact-email { font-size: 1.3rem; padding: var(--s-3) var(--s-4); }
  .plot-training ul { grid-template-columns: minmax(0, 1fr); }
  .frames, .shots-2 { gap: var(--s-2); }
  /* a two-row header shouldn't follow you down a phone screen; it still sits above the page so the menu isn't covered */
  .site-header { position: relative; top: auto; }
  .header-actions { width: 100%; justify-content: flex-end; gap: var(--s-3); }
  .job .logo-tile { width: 7.5rem; }
  .site-footer .wrap { grid-template-columns: minmax(0, 1fr); justify-items: center; }
  .site-footer .sticker, .site-footer .copy-email { justify-self: center; }
}
@media (max-width: 400px) {
  /* keeps all four menu items on one line on small phones */
  .nav { gap: 0; }
  .nav a, .nav-trigger { padding-inline: var(--s-2); }
  .nav a[aria-current="page"]::after, .nav-group:has([aria-current="page"]) .nav-trigger::after { left: var(--s-2); right: var(--s-2); }
}

/* Touch screens: give small text links and the copy-email button a full-size tap area without changing how they look */
@media (pointer: coarse) {
  .text-link { display: inline-flex; align-items: center; min-height: var(--tap); }
  .copy-email { min-height: var(--tap); }
}

/* Print: mostly for the CV. Content only, no chrome. */
@media print {
  .site-header, .site-footer, .skip-link, .link-row, .viewer { display: none !important; }
  .print-only { display: block; }
  body { background: #fff; font-size: 11pt; }
  .page-head { padding-block: 0 1rem; }
  .section, .skill-group { padding-block: 1rem; }
  .entries { gap: 1rem; }
  .entry, .skill, .quote { break-inside: avoid; }
  a { text-decoration: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
