/* ndibe components (31 Oct 2026).
   Built only from tokens.css; loaded after site.css. One block per component.
   Usage notes live in AGENTS.md and on /design-system. */

/* ---------- Hero ----------
   The top of a page: eyebrow, title and optional lede, on an optional warm wash.
   Markup via the `hero` macro in src/_includes/hero.njk. Two variants: page (default) and --case-study
   (client and years in the eyebrow, smaller balanced title, lede with the orange rule, butter wash). */
.hero{padding:var(--space-fluid-2xl) var(--gutter) var(--space-fluid-l)}
/* Only a hero with a wash is layered, so text sits above the wash; without one, content below can overlap it (the Contact portrait tucks behind the form). */
.hero--wash{position:relative}
.hero--wash :is(.hero-eyebrow,.hero-title,.hero-lede,.hero-meta){position:relative}
.hero--space-m{padding-bottom:var(--space-fluid-m)}
.hero-wash{position:absolute;inset:0;pointer-events:none;overflow:hidden}
.hero-eyebrow{margin-bottom:var(--space-fluid-m)}
.hero--gap-s .hero-eyebrow{margin-bottom:var(--space-fluid-s)}
.hero-title{font-size:var(--fs-hero);line-height:var(--lh-none);letter-spacing:var(--track-tighter)}
.hero-title--title{font-size:var(--fs-title)}
.hero-lede{margin-top:var(--space-fluid-s);padding-left:var(--space-fluid-s);border-left:3px solid var(--accent);font-family:'Fraunces',serif;font-variation-settings:'SOFT' 100,'opsz' 60;font-size:var(--fs-lede);line-height:var(--lh-snug);max-width:56ch}
.hero-row{max-width:1400px;margin:0 auto;display:flex;align-items:center;justify-content:space-between;gap:var(--space-32)}
/* Case study: the wash runs on past the hero, behind Role and impact. */
.hero--case-study{padding:var(--space-fluid-l) var(--gutter) var(--space-fluid-s)}
.hero--case-study .hero-wash{inset:0 0 -400px 0}
.hero-meta{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--space-16);margin-bottom:var(--space-fluid-s)}
.hero-client{display:inline-flex;align-items:baseline;gap:var(--space-8)}
.hero-dash{color:var(--accent-text)}
.hero-years{color:var(--ink-2)}
.hero--case-study .hero-title{font-size:var(--fs-title);text-wrap:balance}

/* ---------- Numbered section ----------
   A case-study chapter: orange numeral in the left column, heading and body on the right.
   Markup via the `section` macro in src/_includes/ui.njk. */
.cs-section{padding:var(--space-fluid-3xl) 0 0}
.cs-section-grid{display:grid;grid-template-columns:var(--grid-aside);gap:var(--space-fluid-l);align-items:start}
.cs-numeral{font-family:'Fraunces',serif;font-variation-settings:'SOFT' 100;font-size:var(--fs-numeral);line-height:var(--lh-none);color:var(--accent-text)}
.cs-section-body{max-width:66ch;display:grid;gap:var(--space-20)}
.cs-h2{font-size:var(--fs-section);line-height:var(--lh-display);letter-spacing:var(--track-tight);color:var(--leaf);text-wrap:balance}
.cs-h3{margin-top:var(--space-16);font-size:var(--fs-subhead);line-height:var(--lh-heading);color:var(--leaf)}
.cs-p{font-size:var(--fs-body-lg);line-height:var(--lh-body);color:var(--ink-2)}
/* A continuation block inside the same chapter (no numeral, tighter top space). */
.cs-section--continued{padding-top:var(--space-fluid-l)}
.cs-section--continued .cs-h3{margin-top:0}

/* ---------- Reframe ("From" → "To") ----------
   Two cards showing how the question changed: outlined "From", filled "To". */
.cs-reframe{display:grid;grid-template-columns:var(--grid-aside);gap:var(--space-fluid-l);align-items:start;margin-top:var(--space-fluid-l)}
.cs-reframe-pair{display:grid;grid-template-columns:var(--grid-cards);gap:var(--space-fluid-s);align-items:stretch;max-width:66ch}
.cs-reframe-card{margin:0;padding:var(--space-fluid-m);border-radius:var(--corner-xl)}
.cs-reframe-card--from{border:1.5px solid var(--field-blush)}
.cs-reframe-card--to{background:var(--field-blush);color:var(--ink)}
.cs-reframe-text{margin-top:var(--space-12);font-family:'Fraunces',serif;font-variation-settings:'SOFT' 100;font-size:var(--fs-body-lg);line-height:var(--lh-heading);max-width:28ch}
.cs-reframe-card--from .cs-reframe-text{color:var(--ink-2);max-width:22ch}

/* ---------- Role and impact ----------
   Sits between the intro and the hero image: "My role" as one line, then the
   four impact figures on a pink inset card with a cream gap before the image.
   Sizes follow the space each part has, so zoom and narrow windows reflow.
   src/_includes/cs-role-impact.njk. The fade is --cs-fade in tokens.css. */
.cs-ri{position:relative;padding:0 var(--gutter) var(--space-fluid-s)}
.cs-ri-role{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--space-4) var(--space-12);margin:0 0 var(--space-fluid-s);max-width:110ch}
.cs-ri-label{font-size:var(--fs-label);font-weight:var(--fw-semibold);letter-spacing:var(--track-caps);text-transform:uppercase;color:var(--accent-text)}
.cs-ri-role-text{font-size:var(--fs-ui);line-height:var(--lh-snug);color:var(--ink-2)}
.cs-ri-card{container-type:inline-size;container-name:cs-impact;background:var(--cs-fade);color:var(--on-blush);border-radius:var(--corner-md-alt);padding:var(--space-fluid-s) var(--space-fluid-s)}
.cs-ri-heading{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
/* Four figures: 1, 2 or 4 columns only, never 3 + 1. */
.cs-ri-stats{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--space-12) 0}
@container cs-impact (min-width:17rem){.cs-ri-stats{grid-template-columns:repeat(2,minmax(0,1fr))}}
@container cs-impact (min-width:48rem){.cs-ri-stats{grid-template-columns:repeat(4,minmax(0,1fr))}}
.cs-ri-stat{min-width:0;display:flex;flex-direction:column;gap:var(--space-4);padding:var(--space-4) var(--space-fluid-s);border-left:1px solid color-mix(in srgb,var(--on-blush) 24%,transparent)}
.cs-ri-stat:first-child{border-left:0;padding-left:0}
@container cs-impact (min-width:17rem) and (max-width:47.99rem){.cs-ri-stat:nth-child(3){border-left:0;padding-left:0}}
@container cs-impact (max-width:16.99rem){.cs-ri-stat{border-left:0;padding-left:0}}
.cs-ri-value{margin:0;font-family:'Fraunces',Georgia,serif;font-variation-settings:'SOFT' 100;font-size:var(--fs-body);line-height:var(--lh-heading);letter-spacing:var(--track-snug);overflow-wrap:break-word}
.cs-ri-caption{margin:0;font-size:var(--fs-label);line-height:var(--lh-snug)}

/* ---------- Recommendation ----------
   A colleague's words from LinkedIn, credited by role. src/_includes/cs-recommendation.njk.
   --band: slim strip between sections (About and the homepage). */
.cs-rec{margin:var(--space-12) 0 var(--space-8);padding:var(--space-fluid-m) var(--space-fluid-m);background:var(--quiet);border-left:3px solid var(--accent);border-radius:var(--corner-md-alt);position:relative}
.cs-rec-quote{margin:0}
.cs-rec-quote p{font-family:'Fraunces',Georgia,serif;font-variation-settings:'SOFT' 100,'opsz' 60;font-style:italic;font-weight:var(--fw-book);font-size:var(--fs-lede);line-height:var(--lh-snug);color:var(--ink)}
.cs-rec-quote p::before{content:"\201C";margin-left:-.42em;color:var(--accent-text)}
.cs-rec-quote p::after{content:"\201D";color:var(--accent-text)}
.cs-rec-by{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--space-4) var(--space-12);margin-top:var(--space-16)}
.cs-rec-role{font-size:var(--fs-ui-sm);font-weight:var(--fw-medium);letter-spacing:var(--track-caps);text-transform:uppercase;color:var(--leaf)}
.cs-rec-source{font-size:var(--fs-ui-sm);color:var(--ink-3)}
.cs-rec--band{margin:0;display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:var(--space-8) var(--space-fluid-l);padding:var(--space-fluid-s) var(--space-fluid-m)}
.cs-rec--band .cs-rec-quote{flex:1 1 52ch;max-width:78ch}
.cs-rec--band .cs-rec-quote p{font-size:var(--fs-ui-lg);line-height:var(--lh-body)}
.cs-rec--band .cs-rec-by{margin:0;flex:0 1 auto;flex-direction:column;gap:var(--space-2)}
.cs-rec--band .cs-rec-role,.cs-rec--band .cs-rec-source{font-size:var(--fs-label)}

/* ---------- Eyebrow ----------
   Small uppercase label above a heading or inside a card.
   Default: interface-small, accent colour. Modifiers change size or colour only. */
.eyebrow{font-size:var(--fs-ui-sm);font-weight:var(--fw-medium);letter-spacing:var(--track-caps);text-transform:uppercase;color:var(--accent-text)}
.eyebrow--sm{font-size:var(--fs-label)}
.eyebrow--lg{font-size:var(--fs-ui-lg)}
.eyebrow--ink{color:var(--ink)}
.eyebrow--quiet{color:var(--ink-3)}
.eyebrow--on-field{color:var(--on-blush)}

/* ---------- Button ----------
   One shape (the medium cut corner), three sizes, six looks, and the same states on every look.
   Sizes: default (large, 56px) for page actions · --md (44px) on cards and showreel promos · --sm (36px) for quiet, repeated actions.
   Medium and small labels are set in the medium weight so they hold up at the smaller size.
   --icon makes it square for an icon-only button; give it an aria-label.
   Looks: --primary filled leaf green, the main action on a cream page · --secondary outlined, beside a primary
   · --text no box, for a low-key action in running content · --accent orange, the form's send button
   · --on-band butter-filled, the main action on the green band; pair with --on-band-outline.
   States: hover · keyboard focus (ring) · pressed · disabled ([disabled] or aria-disabled="true", dimmed, no hover)
   · loading (aria-busy="true", spinner after the label; usually disabled at the same time). */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--space-8);min-height:var(--control-lg);padding:0 var(--space-24);border:1.5px solid transparent;border-radius:var(--corner-md);font:inherit;font-size:var(--fs-ui-lg);line-height:var(--lh-snug);text-align:center;text-decoration:none;cursor:pointer;transition:background-color var(--dur-quick) var(--ease),border-color var(--dur-quick) var(--ease),color var(--dur-quick) var(--ease)}
.btn--md{min-height:var(--control-md);padding:0 var(--space-20);font-size:var(--fs-ui);font-weight:var(--fw-medium)}
.btn--sm{min-height:var(--control-sm);padding:0 var(--space-16);font-size:var(--fs-ui-sm);font-weight:var(--fw-medium)}
.btn--icon{width:var(--control-lg);padding:0}
.btn--icon.btn--md{width:var(--control-md)}
.btn--icon.btn--sm{width:var(--control-sm)}
.btn--primary{background:var(--leaf);color:var(--bg)}
.btn--secondary{background:transparent;color:var(--leaf);border-color:var(--leaf)}
.btn--text{background:transparent;color:var(--leaf);padding-inline:0;text-decoration:underline;text-decoration-thickness:1.5px;text-underline-offset:.25em}
.btn--accent{background:var(--accent);color:var(--on-accent)}
.btn--on-band{background:var(--on-band);color:#3A4614}
.btn--on-band-outline{background:transparent;color:var(--on-band);border-color:var(--on-band-rule)}
.btn:is(.btn--primary,.btn--secondary):hover:not(:disabled,[aria-disabled="true"],[aria-busy="true"]){background:var(--leaf-mid);border-color:var(--leaf-mid);color:var(--bg)}
.btn--text:hover:not(:disabled,[aria-disabled="true"],[aria-busy="true"]){color:var(--accent-text)}
.btn--accent:hover:not(:disabled,[aria-disabled="true"],[aria-busy="true"]){background:var(--accent-deep);color:var(--bg)}
.btn:is(.btn--on-band,.btn--on-band-outline):hover:not(:disabled,[aria-disabled="true"],[aria-busy="true"]){background:var(--band-hover);border-color:var(--band-hover);color:var(--on-band)}
.btn:is(.btn--on-band,.btn--on-band-outline):focus-visible{outline-color:var(--on-band)}
.btn:active:not(:disabled,[aria-disabled="true"],[aria-busy="true"]){transform:translateY(1px)}
.btn:is(:disabled,[aria-disabled="true"]){opacity:.5;cursor:not-allowed}
.btn[aria-busy="true"],.btn[aria-busy="true"]:is(:disabled,[aria-disabled="true"]){cursor:progress;opacity:.85}
.btn[aria-busy="true"]::after{content:"";flex:0 0 auto;width:1em;height:1em;border:2px solid currentColor;border-right-color:transparent;border-radius:var(--round);animation:btn-spin var(--dur-slow) linear infinite}
@keyframes btn-spin{to{transform:rotate(1turn)}}
@media (prefers-reduced-motion:reduce){.btn[aria-busy="true"]::after{animation:none;border-right-color:currentColor;opacity:.6}}
.btn svg{flex:0 0 auto}

/* ---------- Showreel promo ----------
   A picture that opens a walkthrough reel in an overlay. Without JavaScript only the picture shows.
   Markup via src/_includes/cs-showreel.njk. */
.cs-wt{position:relative;max-width:var(--feature-max);width:var(--feature-w);height:var(--feature-h);overflow:hidden;border-radius:var(--corner-lg-alt);box-shadow:var(--shadow-soft);border:1.5px solid var(--rule)}
.cs-wt-media,.cs-wt-media img{display:block;width:100%;height:100%}
.cs-wt-media{overflow:hidden}
.cs-wt-media img{object-fit:cover;object-position:var(--wt-focus,68% 50%);transition:transform var(--dur-drift) var(--ease-drift)}
/* Drift: a zoom while the promo is pointed at or its button has focus, hinting that it plays (as on the homepage strip).
   Only when the reel can play; walkthrough.js adds .is-playable, and a click anywhere on the promo plays it. */
html.js .cs-wt:hover .cs-wt-media img,html.js .cs-wt:focus-within .cs-wt-media img{transform:scale(1.1)}
.cs-wt.is-playable{cursor:pointer}
@media (prefers-reduced-motion:reduce){.cs-wt-media img{transition:none;transform:none!important}}
.cs-wt-card{display:none}
html.js .cs-wt-card{position:absolute;left:clamp(16px,2.2vw,28px);bottom:clamp(16px,2.2vw,28px);width:min(400px,calc(100% - 32px));display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-8);padding:var(--space-24) var(--space-24) var(--space-24);background:var(--bg);border-radius:var(--corner-md-alt);box-shadow:var(--shadow-float)}
.cs-wt-title{font-family:'Fraunces',Georgia,serif;font-variation-settings:'SOFT' 100,'opsz' 60;font-size:var(--fs-subhead);line-height:var(--lh-heading);letter-spacing:var(--track-snug);color:var(--leaf)}
.cs-wt-play{margin-top:var(--space-8)}
.cs-wt-eyebrow .lc{text-transform:none}
.cs-wt-error{font-size:var(--fs-ui-sm);line-height:var(--lh-snug);color:var(--ink-2)}
@media (max-width:900px){.cs-wt{width:100%}}
@media (max-width:640px){
  .cs-wt{height:auto;border-radius:var(--corner-md-alt)}
  .cs-wt-media{height:auto;aspect-ratio:16/9}
  .cs-wt-media img{object-position:50% 50%}
  html.js .cs-wt-card{position:static;width:auto;border-radius:0;box-shadow:none;padding:var(--space-20) var(--space-20) var(--space-24)}
  .cs-wt-play{align-self:stretch;justify-content:center}
}

/* ---------- Illustration ----------
   A standalone illustration between chapters: the same frame as a showreel promo, so they line up,
   with a short caption underneath in the eyebrow colour. Markup via src/_includes/cs-illustration.njk.
   Not for pictures inside another panel (hero, reframe, showreel, diagrams with their own controls). */
.illustration{width:var(--feature-w);max-width:var(--feature-max);margin:var(--space-fluid-3xl) auto 0}
.illustration-frame{height:var(--feature-h);overflow:hidden;border-radius:var(--corner-lg-alt);box-shadow:var(--shadow-soft);border:1.5px solid var(--rule)}
.illustration-frame img{display:block;width:100%;height:100%;object-fit:cover;object-position:var(--illus-focus,50% 50%)}
.illustration figcaption,.media-caption{margin-top:var(--space-12);font-size:var(--fs-ui-sm);line-height:var(--lh-snug);color:var(--accent-text)}
/* The same caption under a visual that keeps its own size (an animation, a diagram): wrap the visual in
   <figure class="captioned"> and add <figcaption class="media-caption">. */
.captioned{margin:0}
@media (max-width:900px){.illustration{width:100%}}
@media (max-width:640px){.illustration-frame{height:auto;aspect-ratio:16/9;border-radius:var(--corner-md-alt)}}

/* ---------- Site footer (portrait) ----------
   Green band with portrait, closing line and two buttons. src/_includes/site-footer.njk. */
.site-footer{padding:var(--space-fluid-l) var(--gutter);background:var(--band);color:var(--on-band-text)}
.footer-grid{display:flex;flex-wrap:nowrap;gap:var(--space-fluid-xl);align-items:center}
.footer-left{display:flex;align-items:center;gap:var(--space-48);min-width:0;flex:1 1 auto}
.footer-avatar{height:225px;width:auto;flex:0 0 auto;object-fit:contain}
.footer-cta-text{font-family:'Fraunces',serif;font-variation-settings:'SOFT' 100;font-size:var(--fs-heading);line-height:var(--lh-heading);color:var(--on-band);min-width:0;max-width:48ch}
.footer-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--space-12);flex:0 0 auto}
@media (min-width:769px) and (max-width:1100px){
  .footer-grid{display:grid;grid-template-columns:auto 1fr;grid-template-rows:auto auto;column-gap:var(--space-48);row-gap:var(--space-24);align-items:start}
  .footer-left{display:contents}
  .footer-avatar{grid-column:1;grid-row:1/3;align-self:center}
  .footer-cta-text{grid-column:2;grid-row:1;align-self:end;max-width:none}
  .footer-actions{grid-column:2;grid-row:2;align-self:start;flex:none;justify-content:flex-start}
  .footer-btn{white-space:nowrap}
}
@media (max-width:768px){
  .footer-grid{flex-direction:column;align-items:stretch}
  .footer-left{gap:var(--space-20)}
  .footer-avatar{height:auto;width:clamp(90px,26vw,140px)}
  .footer-cta-text{font-size:clamp(1.3rem,5.5vw,1.6rem)}
  .footer-actions{flex-direction:row;align-items:stretch;justify-content:flex-start}
  .footer-btn{flex:1 1 0}
}

/* ---------- Statement footer ----------
   Green band with a closing statement, the email address and a sign-off line.
   Homepage and Contact. src/_includes/site-footer-statement.njk. */
.statement-footer{padding:var(--space-fluid-2xl) var(--gutter-wide);background:var(--band);color:var(--on-band-text)}
.statement-footer-grid{display:grid;grid-template-columns:var(--grid-cards);gap:var(--space-fluid-xl);align-items:end}
.statement-footer-line{font-size:var(--fs-section);line-height:var(--lh-display);letter-spacing:var(--track-tight);color:var(--on-band);max-width:22ch}
.statement-footer-contact{display:grid;gap:var(--space-16);justify-items:start}
.footer-email{font-size:var(--fs-subhead);color:var(--on-band);border-bottom:1.5px solid var(--on-band-rule);padding-bottom:var(--space-4)}
.footer-email:hover{color:var(--on-band-link-hover);border-color:var(--on-band-link-hover)}
.statement-footer-note{font-size:var(--fs-body);line-height:var(--lh-body);color:var(--on-band-muted);max-width:72ch}
.statement-footer-base{margin-top:var(--space-fluid-xl);padding-top:var(--space-24);border-top:1.5px solid var(--on-band-divider);display:flex;flex-wrap:wrap;gap:var(--space-16);justify-content:space-between;font-size:var(--fs-ui);letter-spacing:var(--track-caps);text-transform:uppercase;color:var(--on-band-faint)}

/* ---------- Case-study footer ----------
   The last band of a case study (inside cs-closing.njk). */
.cs-footer{padding:var(--space-fluid-2xl) var(--gutter);background:var(--band);color:var(--on-band-text)}
.cs-footer-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:var(--space-fluid-xl);align-items:end}
.cs-footer-line{font-family:'Fraunces',serif;font-variation-settings:'SOFT' 100;font-size:var(--fs-heading);line-height:var(--lh-heading);color:var(--on-band)}
.cs-footer-actions{display:flex;flex-wrap:wrap;gap:var(--space-12);justify-content:flex-end;justify-self:end}

/* ---------- Form field ----------
   Text inputs and text areas, with a label above. Contact form. */
.field-label{font-size:var(--fs-ui-sm);font-weight:var(--fw-medium);color:var(--ink-3)}
.field{width:100%;font:inherit;font-size:var(--fs-ui-lg);color:var(--ink);background:var(--bg);border:1.5px solid var(--rule-strong);border-radius:var(--corner-sm);padding:var(--space-12) var(--space-16)}
.field::placeholder{color:var(--ink-3)}
.field:focus{border-color:var(--accent);outline:2px solid var(--accent);outline-offset:1px}
textarea.field{resize:vertical}
/* Error state: set aria-invalid="true" on the field and show its .field-error (linked with aria-describedby).
   The red edge and the message (icon and words) carry it together, so it doesn't rely on colour. */
.field[aria-invalid="true"]{border-color:var(--status-error)}
.field[aria-invalid="true"]:focus{outline-color:var(--status-error)}
.field-error{display:flex;align-items:flex-start;gap:var(--space-8);font-size:var(--fs-ui);font-weight:var(--fw-medium);line-height:var(--lh-snug);color:var(--status-error)}
.field-error svg{flex:0 0 auto;width:1.1em;height:1.1em;margin-top:.15em}

/* ---------- Message ----------
   An inline message saying what happened: a message sent, or something that went wrong.
   Icon, then words, on a pale status background; --success or --error. Put it in an aria-live region
   (or move focus to it) so screen readers hear it. Not for decoration or general notes. */
.message{display:flex;align-items:flex-start;gap:var(--space-12);padding:var(--space-16) var(--space-20);border-radius:var(--corner-sm-alt);font-size:var(--fs-body);line-height:var(--lh-body);color:var(--ink)}
.message svg{flex:0 0 auto;width:1.25em;height:1.25em;margin-top:.2em}
.message a{color:inherit;text-decoration:underline}
.message:focus{outline:none}
.message:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
.message--success{background:var(--status-success-bg);border:1.5px solid var(--status-success)}
.message--success svg{color:var(--status-success)}
.message--error{background:var(--status-error-bg);border:1.5px solid var(--status-error)}
.message--error svg{color:var(--status-error)}

/* ---------- Links ----------
   Quiet links take the accent on hover; action links ("View CV →") take the leaf green.
   Inline links sit inside running text: orange text (--accent-text) with an underline, so they're clear by more than colour. */
.link-quiet:hover{color:var(--accent-text)}
.link-action:hover{color:var(--leaf)}
.link-inline{color:var(--accent-text);text-decoration:underline;text-decoration-thickness:1.5px;text-underline-offset:.25em;transition:color var(--dur-quick) var(--ease)}
.link-inline:hover{color:var(--ink);text-decoration-thickness:2.5px}

/* ---------- Case-study list row ----------
   One case study per row: title, client and outcome, arrow. Homepage list. */
.list-row{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(0,1fr) 28px;gap:var(--space-fluid-m);align-items:baseline;padding:var(--space-24) 0;border-bottom:1.5px solid var(--rule);color:var(--ink)}
.list-row:hover{background:var(--quiet);color:var(--ink)}
.list-row-title{font-family:'Fraunces',Georgia,serif;font-variation-settings:'SOFT' 100;font-size:var(--fs-subhead);line-height:var(--lh-heading)}
.list-row-label{font-size:var(--fs-ui);letter-spacing:var(--track-caps);text-transform:uppercase;color:var(--leaf-mid)}
.list-row-arrow{text-align:right}
/* Outcome (homepage): one line under the label; the title spans both lines. Stacks under the title on phones. */
.list-row:has(> .list-row-outcome){row-gap:var(--space-4)}
.list-row:has(> .list-row-outcome) > .list-row-title{grid-row:1 / span 2}
.list-row-outcome{grid-column:2;grid-row:2;font-size:var(--fs-ui);line-height:var(--lh-body);color:var(--ink);opacity:.72}
@media (max-width:640px){.list-row:has(> .list-row-outcome) > .list-row-title{grid-row:1}.list-row-outcome{grid-column:1 / 3}}
/* Stacked: a short description under the title, arrow at the end. For short lists where the description
   is a phrase rather than a client label (the Showpieces list on /design-system). Same three children. */
.list-row--stacked{grid-template-columns:minmax(0,1fr) auto;gap:var(--space-4) var(--space-16);padding:var(--space-16) 0}
.list-row--stacked > :nth-child(2){grid-column:1;grid-row:2}
.list-row--stacked > :nth-child(3){grid-column:2;grid-row:1}

/* ---------- Buttons on images and overlays ----------
   Round 44px icon buttons. Position stays with the page; these set colour and hover only.
   .lb-close: closes an expanded view (on the dark scrim). .glass-btn: expand, on a picture.
   .media-btn: play, pause or replay, on a picture or animation. */
.lb-close{border:1.5px solid var(--on-scrim-rule);background:transparent;color:var(--on-scrim)}
.lb-close:hover{background:var(--on-scrim);color:var(--on-scrim-hover-text);border-color:var(--on-scrim)}
.lb-close--solid{background:var(--scrim-button)}
.glass-btn{background:var(--glass)}
.glass-btn:hover{background:var(--glass-hover)}
.media-btn{background:var(--media-ctrl)}
.media-btn:hover{background:var(--media-ctrl-hover)}

/* ---------- Body text ----------
   Running text on ordinary pages (case studies use the larger Numbered section text).
   On a <p>, or on a <ul>/<ol> for a list in the same voice. */
.body-text{font-size:var(--fs-body);line-height:var(--lh-body);color:var(--ink-2)}
ul.body-text,ol.body-text{padding-left:1.2em;display:grid;gap:var(--space-4)}

/* ---------- Panel ----------
   A quiet box that groups related content: principles, examples, sample cards.
   --lg for larger content with fluid padding; --dashed for an example of what not to do. */
.panel{padding:var(--space-20);background:var(--surface);border:1.5px solid var(--rule);border-radius:var(--corner-md-alt)}
.panel--lg{padding:var(--space-fluid-m);border-radius:var(--corner-lg-alt)}
.panel--dashed{border-style:dashed}

/* ---------- Tag ----------
   A short label for a state, such as "Stable" or "New". Not a link or a button.
   (The CV's skill pills look similar but keep fixed paper colours, like the rest of the CV.) */
.tag{box-sizing:border-box;display:inline-flex;align-items:center;padding:var(--space-2) var(--space-12);border:1.5px solid var(--leaf);border-radius:var(--corner-sm);font-size:var(--fs-label);font-weight:var(--fw-medium);line-height:var(--lh-snug);color:var(--leaf)}

/* ---------- Disclosure ----------
   Detail kept out of the way until someone wants it: a <details> with a short <summary>.
   --boxed sits in its own panel, for a contents menu on phones. */
.disclosure > summary{width:fit-content;cursor:pointer;font-size:var(--fs-ui-sm);font-weight:var(--fw-medium);color:var(--leaf)}
.disclosure--boxed{padding:var(--space-12) var(--space-16);background:var(--surface);border:1.5px solid var(--rule);border-radius:var(--corner-md-alt)}
.disclosure--boxed > summary{font-size:var(--fs-ui)}

/* ---------- Code block ----------
   Code to copy, in a <pre> that scrolls sideways rather than wrapping. Give it tabindex="0" so it can be scrolled by keyboard. */
.code-block{margin:0;padding:var(--space-16);overflow-x:auto;background:color-mix(in srgb,var(--ink) 6%,transparent);border-radius:var(--corner-sm-alt);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:var(--fs-label);line-height:var(--lh-body);color:var(--ink);white-space:pre}

/* ---------- Contents list ----------
   Links to the sections of a long page, in named groups; the section in view is marked with aria-current="location". */
.contents ul{list-style:none;margin:var(--space-8) 0 0;padding:0;display:grid;gap:var(--space-2)}
.contents-group + .contents-group{margin-top:var(--space-20)}
.contents a{display:block;padding:var(--space-4) var(--space-12);border-left:2px solid transparent;font-size:var(--fs-ui-sm);color:var(--ink-2)}
.contents a:hover{color:var(--accent-text)}
.contents a[aria-current]{border-left-color:var(--accent);color:var(--ink);font-weight:var(--fw-medium)}

/* ---------- Key–value list ----------
   Short facts as name and value pairs, in a <dl>. --ruled puts each pair on its own ruled row, for keyboard keys and the like. */
.kv{display:grid;grid-template-columns:var(--grid-aside);gap:var(--space-8) var(--space-16);margin:0;font-size:var(--fs-ui);line-height:var(--lh-body);color:var(--ink-2)}
.kv dt{font-weight:var(--fw-medium);color:var(--ink)}
.kv dd{margin:0}
.kv kbd{font:inherit;font-weight:var(--fw-medium);color:var(--ink)}
.kv--ruled{grid-template-columns:minmax(0,10rem) minmax(0,1fr);gap:0;border-top:1px solid var(--rule)}
.kv--ruled > dt,.kv--ruled > dd{padding:var(--space-8) 0;border-bottom:1px solid var(--rule)}
.kv--ruled > dt{padding-right:var(--space-16)}
@media (max-width:640px){
  .kv:not(.kv--ruled){grid-template-columns:minmax(0,1fr)}
  .kv:not(.kv--ruled) dd{margin-bottom:var(--space-8)}
  .kv--ruled{grid-template-columns:minmax(0,5.5rem) minmax(0,1fr)}
}
