@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/IBMPlexSans-400.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+FB01-FB02}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url('/fonts/IBMPlexSans-500.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+FB01-FB02}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url('/fonts/IBMPlexSans-600.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+FB01-FB02}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/IBMPlexMono-400.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+FB01-FB02}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url('/fonts/IBMPlexMono-500.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+FB01-FB02}

/* ===========================================================================
   Palette: paper and ink, one vermilion accent.
   Radius: 3px, used only where something is genuinely boxed.
   Motion: hover, focus, and disclosure only. Nothing animates on its own.
   =========================================================================== */

:root {
  --bg:     #fafaf9;
  --bg-2:   #f2f2f0;
  --card:   #ffffff;
  --ink:    #17171a;
  --ink-2:  #52525a;
  --ink-3:  #6e6e77;
  --line:   #e3e3e0;
  --line-2: #ededea;
  --accent: #b23c17;
  --accent-soft: rgba(178, 60, 23, .09);
  --accent-ink: #ffffff;
  --shadow: 0 1px 2px rgba(23,23,26,.04), 0 10px 28px -14px rgba(23,23,26,.18);

  --r: 3px;
  --sans: 'IBM Plex Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --rail: 8.5rem;
  --gap:  3rem;
  --maxw: 64rem;
  --pad:  clamp(1.25rem, 5vw, 3rem);
}

:root[data-theme="dark"] {
  --bg: #101012; --bg-2: #17181b; --card: #17181b;
  --ink: #ededf0; --ink-2: #9d9da7; --ink-3: #86868f;
  --line: #26262a; --line-2: #1e1e22;
  --accent: #ff7a4d; --accent-soft: rgba(255,122,77,.12); --accent-ink: #1a0d06;
  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 14px 34px -16px rgba(0,0,0,.7);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #101012; --bg-2: #17181b; --card: #17181b;
    --ink: #ededf0; --ink-2: #9d9da7; --ink-3: #86868f;
    --line: #26262a; --line-2: #1e1e22;
    --accent: #ff7a4d; --accent-soft: rgba(255,122,77,.12); --accent-ink: #1a0d06;
    --shadow: 0 1px 2px rgba(0,0,0,.4), 0 14px 34px -16px rgba(0,0,0,.7);
  }
}

/* =========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-padding-top: 5rem; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font-family: var(--sans); font-size: 16px; line-height: 1.6;
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
}
h1, h2, h3 { margin: 0; font-weight: 600; line-height: 1.22; letter-spacing: -.012em; }
p, ul, dl, dd { margin: 0; }
ul { padding: 0; list-style: none; }
a { color: var(--accent); text-underline-offset: 2px; }
img { max-width: 100%; display: block; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r); }

.wrap { max-width: var(--maxw); margin-inline: auto; padding-inline: var(--pad); }

.skip { position: absolute; left: -9999px; top: 0; z-index: 100;
        background: var(--accent); color: var(--accent-ink); padding: .625rem 1rem; border-radius: var(--r); }
.skip:focus { left: .75rem; top: .75rem; }

/* --- Top bar -------------------------------------------------------------- */

.bar { position: sticky; top: 0; z-index: 40; background: var(--bg); border-bottom: 1px solid var(--line); }
.bar-in { height: 54px; display: flex; align-items: center; justify-content: space-between; gap: 1.25rem; }
.bar-name { font-family: var(--mono); font-size: .8125rem; font-weight: 500; color: var(--ink);
            text-decoration: none; white-space: nowrap; }
.bar-name:hover { color: var(--accent); }

.bar-links { display: flex; align-items: center; gap: 1.125rem; min-width: 0; }
.bar-links a { font-family: var(--mono); font-size: .78125rem; color: var(--ink-3); text-decoration: none; }
.bar-links a:hover { color: var(--ink); }
.bar-links a[aria-current="page"] { color: var(--accent); }

.bar-tools { display: flex; align-items: center; gap: .5rem; flex: none; }

.toggle, .kbd-btn {
  appearance: none; border: 1px solid var(--line); background: transparent; color: var(--ink-3);
  font: inherit; font-family: var(--mono); font-size: .6875rem; letter-spacing: .02em;
  padding: .3125rem .5rem; border-radius: var(--r); cursor: pointer; white-space: nowrap;
}
.toggle:hover, .kbd-btn:hover { color: var(--ink); border-color: var(--ink-3); }
.toggle:active, .kbd-btn:active { transform: translateY(1px); }
.kbd-btn { display: inline-flex; align-items: center; gap: .4375rem; }
.kbd-btn kbd { font-family: var(--mono); font-size: .625rem; border: 1px solid var(--line);
               border-radius: 2px; padding: 0 .25rem; color: var(--ink-3); }

/* Below this the five links cannot share a row with the name and the two
   buttons, so the bar becomes two rows and the links scroll sideways. Leaving
   the palette as the only way through would strand a phone with no visible
   route to the rest of the site. */
@media (max-width: 860px) {
  .kbd-btn span { display: none; }
  .bar-in { flex-wrap: wrap; height: auto; padding-block: .5rem 0; }
  .bar-name { order: 1; }
  .bar-tools { order: 2; margin-left: auto; }
  .bar-links {
    order: 3; width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch;
    padding-block: .625rem; margin-top: .5rem;
    border-top: 1px solid var(--line-2); scrollbar-width: none;
  }
  .bar-links::-webkit-scrollbar { display: none; }
  .bar-links a { white-space: nowrap; }
}

/* --- Page heads ----------------------------------------------------------- */

.hero { padding-block: clamp(3rem, 7vw, 5rem) clamp(2rem, 4vw, 3rem); }
.hero-kicker { font-family: var(--mono); font-size: .8125rem; color: var(--ink-2); margin-bottom: 1.25rem; }
.hero-kicker span { color: var(--ink-3); }
.hero h1 { font-size: clamp(1.875rem, 4.6vw, 2.875rem); letter-spacing: -.03em; max-width: 26ch; }
.hero-sub { margin-top: 1.375rem; max-width: 60ch; color: var(--ink-2); font-size: 1.0625rem; }

.hero-do { display: flex; flex-wrap: wrap; gap: .625rem; margin-top: 1.75rem; }
.btn { display: inline-flex; align-items: center; gap: .5rem; padding: .5625rem 1rem;
       border: 1px solid var(--line); border-radius: var(--r); text-decoration: none;
       font-size: .9375rem; font-weight: 500; color: var(--ink); background: transparent; }
.btn:hover { border-color: var(--ink-3); background: var(--bg-2); }
.btn:active { transform: translateY(1px); }
.btn-solid { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn-solid:hover { background: var(--accent); border-color: var(--accent); filter: brightness(1.08); }

.hero-facts { display: grid; gap: 0; margin-top: 2.25rem; border-top: 1px solid var(--line); }
@media (min-width: 620px) { .hero-facts { grid-template-columns: repeat(3, 1fr); } }
.hero-facts > div { padding-block: .875rem; border-bottom: 1px solid var(--line-2); }
@media (min-width: 620px) { .hero-facts > div { border-bottom: none; padding-right: 1.5rem; } }
.hero-facts dt { font-family: var(--mono); font-size: .6875rem; color: var(--ink-3);
                 text-transform: uppercase; letter-spacing: .05em; margin-bottom: .25rem; }
.hero-facts dd { font-size: .9375rem; font-weight: 500; }

.page-head { padding-block: clamp(2.5rem, 6vw, 4rem) clamp(1.5rem, 3vw, 2.25rem); }
.page-head h1 { font-size: clamp(1.75rem, 4.5vw, 2.5rem); letter-spacing: -.028em; }
.page-head > p { margin-top: .875rem; color: var(--ink-2); max-width: 62ch; }
.page-sum { font-size: 1.0625rem; }
.crumb { font-family: var(--mono); font-size: .75rem; color: var(--ink-3); margin-bottom: .875rem; }
/* Underlined always: colour alone is not enough to mark a link sitting
   inside a run of text. */
.crumb a { text-decoration: underline; text-decoration-thickness: 1px; }
.crumb a:hover { text-decoration-thickness: 2px; }

/* --- Section rail --------------------------------------------------------- */

.sec { padding-block: clamp(2.25rem, 4.5vw, 3.25rem); border-top: 1px solid var(--line); }
.sec-grid { display: grid; gap: 1.25rem; }
@media (min-width: 860px) { .sec-grid { grid-template-columns: var(--rail) minmax(0,1fr); gap: var(--gap); } }
.rail { font-family: var(--mono); font-size: .75rem; font-weight: 500; color: var(--ink-3);
        letter-spacing: .04em; text-transform: uppercase; padding-top: .25rem; }
@media (min-width: 860px) { .rail { position: sticky; top: 4.75rem; align-self: start; } }
.body { min-width: 0; }

.prose { color: var(--ink-2); max-width: 68ch; }
.prose + .prose { margin-top: 1rem; }
.lead-sm { color: var(--ink-2); max-width: 62ch; font-size: .9375rem; }
.more { margin-top: 1.5rem; font-family: var(--mono); font-size: .8125rem; }
.more a { text-decoration: none; border-bottom: 1px solid currentColor; }

/* --- Entries -------------------------------------------------------------- */

.entry { padding-block: 1.5rem; scroll-margin-top: 5rem; }
.entry-id { display: flex; gap: .9375rem; align-items: flex-start; }
.entry-hgroup { min-width: 0; }
/* One mark per employer, drawn in the site's own style: a real logo when the
   file exists, the org's initials otherwise, so the column stays one system. */
.org-mark { flex: none; width: 2.75rem; height: 2.75rem; margin-top: .125rem;
            display: grid; place-items: center; overflow: hidden;
            border: 1px solid var(--line); border-radius: var(--r); background: var(--card);
            font-family: var(--mono); font-size: .75rem; font-weight: 500;
            letter-spacing: .04em; color: var(--ink-2); user-select: none; }
.org-mark.is-live { color: var(--accent); border-color: var(--accent); }
.org-mark.has-img { padding: .3125rem; }
.org-mark.has-img img { width: 100%; height: 100%; object-fit: contain; }
.entry:first-child { padding-top: 0; }
.entry + .entry { border-top: 1px solid var(--line-2); }
.when { font-family: var(--mono); font-size: .75rem; color: var(--ink-3); margin-bottom: .4375rem; }
.live { color: var(--accent); }
.entry h3 { font-size: 1.0625rem; }
.at { color: var(--accent); font-size: .9375rem; margin-top: .125rem; }
.at .kind { color: var(--ink-3); }
.where { font-family: var(--mono); font-size: .75rem; color: var(--ink-3); margin-top: .3125rem; }
.what { color: var(--ink); font-size: .9375rem; margin-top: .75rem; max-width: 66ch; }
.points { margin-top: .875rem; }
.points li { position: relative; padding-left: 1.0625rem; color: var(--ink-2);
             font-size: .9375rem; line-height: 1.62; max-width: 68ch; }
.points li + li { margin-top: .4375rem; }
.points li::before { content: ""; position: absolute; left: 0; top: .66em; width: 5px; height: 1px; background: var(--ink-3); }

/* --- Row links (compact list that stands in for a page) ------------------- */

.stack-list { display: grid; }
.row-link { display: grid; grid-template-columns: 1fr auto; gap: .25rem 1rem; align-items: baseline;
            padding-block: .9375rem; border-bottom: 1px solid var(--line-2);
            text-decoration: none; color: inherit; }
@media (min-width: 620px) { .row-link { grid-template-columns: 9rem 1fr auto; } }
.row-link:hover { background: var(--accent-soft); }
.row-when { font-family: var(--mono); font-size: .75rem; color: var(--ink-3); }
.row-main { display: flex; flex-wrap: wrap; gap: .0625rem .625rem; align-items: baseline; }
.row-main strong { font-weight: 600; font-size: .9875rem; }
.row-org { color: var(--accent); font-size: .875rem; }
.row-go { color: var(--ink-3); font-family: var(--mono); }
.row-link:hover .row-go { color: var(--accent); }

/* --- Preview cards -------------------------------------------------------- */

.cards { display: grid; gap: 1rem; }
@media (min-width: 720px) { .cards { grid-template-columns: repeat(2, 1fr); } }
.cards-all { gap: 1rem; }

.card { position: relative; background: var(--card); border: 1px solid var(--line);
        border-radius: var(--r); padding: 1.25rem;
        display: flex; flex-direction: column; gap: .5rem; min-width: 0; }
.card:hover { border-color: var(--ink-3); box-shadow: var(--shadow); }
.card:focus-within { border-color: var(--accent); }
/* One hit area over the whole card so the title is not the only target. */
.card-hit { position: absolute; inset: 0; border-radius: inherit; z-index: 1; }
.card-hit:focus-visible { outline-offset: -3px; }
.card-when { font-family: var(--mono); font-size: .6875rem; color: var(--ink-3); }
.card-title { font-size: 1.0625rem; }
.card-org { color: var(--accent); font-size: .8125rem; }
.card-sum { color: var(--ink-2); font-size: .9125rem; line-height: 1.55; }
.card-go { margin-top: auto; padding-top: .5rem; font-family: var(--mono);
           font-size: .75rem; color: var(--ink-3); }
.card:hover .card-go { color: var(--accent); }

/* --- Chips ---------------------------------------------------------------- */

.chips { display: flex; flex-wrap: wrap; gap: .3125rem; }
.chip { display: inline-block; font-family: var(--mono); font-size: .6875rem; line-height: 1.5;
        padding: .1875rem .4375rem; border: 1px solid var(--line-2); border-radius: var(--r);
        background: var(--bg-2); color: var(--ink-2); text-decoration: none; position: relative; z-index: 2; }
a.chip:hover { color: var(--accent); border-color: var(--accent); }
.chip-btn { cursor: pointer; font: inherit; font-family: var(--mono); font-size: .6875rem;
            padding: .25rem .5rem; }
.chip-btn.is-on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

.filter { display: flex; flex-wrap: wrap; gap: .375rem; align-items: center; margin-bottom: 1.5rem; }
.filter-label { font-family: var(--mono); font-size: .6875rem; text-transform: uppercase;
                letter-spacing: .05em; color: var(--ink-3); margin-right: .25rem; }
.filter-empty { font-family: var(--mono); font-size: .8125rem; color: var(--ink-3); padding-block: 2rem; }
.filter-n { font-family: var(--mono); font-size: .6875rem; color: var(--ink-3); margin-left: .25rem; font-variant-numeric: tabular-nums; }
/* The slot is what gets hidden by the filter, so it has to be the grid item.
   Cards take their natural height rather than stretching to match the row:
   once some projects carry a photo and some do not, stretching opens a void
   inside the shorter card, which reads worse than an uneven bottom edge. */
.card-slot { display: block; align-self: start; }
.card-slot[hidden] { display: none; }

/* --- Skills --------------------------------------------------------------- */

.skill { border-bottom: 1px solid var(--line-2); scroll-margin-top: 5rem; }
.skill > summary {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding-block: .8125rem; cursor: pointer; list-style: none;
}
.skill > summary::-webkit-details-marker { display: none; }
.skill > summary::after { content: "+"; font-family: var(--mono); color: var(--ink-3); }
.skill[open] > summary::after { content: "\2212"; }
.skill > summary:hover .skill-name { color: var(--accent); }
.skill-name { font-size: .9375rem; font-weight: 500; }
.skill-count { font-family: var(--mono); font-size: .6875rem; color: var(--ink-3);
               margin-left: auto; margin-right: .75rem; white-space: nowrap; }
.skill:target { background: var(--accent-soft); }

.skill-uses { padding-bottom: .875rem; display: grid; gap: 1px; }
.skill-uses a { display: grid; grid-template-columns: 4.5rem 1fr auto; gap: .75rem;
                align-items: baseline; padding: .4375rem .5rem; text-decoration: none;
                color: var(--ink-2); border-radius: var(--r); }
.skill-uses a:hover { background: var(--bg-2); color: var(--ink); }
.use-kind { font-family: var(--mono); font-size: .625rem; text-transform: uppercase;
            letter-spacing: .06em; color: var(--accent); }
.use-label { font-size: .875rem; }
.use-when { font-family: var(--mono); font-size: .6875rem; color: var(--ink-3); white-space: nowrap; }
@media (max-width: 560px) {
  .skill-uses a { grid-template-columns: 1fr; gap: .125rem; }
  .use-when { grid-column: 1; }
}

.skill-teaser { display: grid; gap: 1.125rem; margin-top: 1.5rem; }
.teaser-row h3 { font-size: .8125rem; font-family: var(--mono); font-weight: 500;
                 color: var(--ink-3); text-transform: uppercase; letter-spacing: .05em;
                 margin-bottom: .5rem; }

/* --- Contact -------------------------------------------------------------- */

.contact-grid { display: grid; gap: .75rem; }
@media (min-width: 620px) { .contact-grid { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); } }
.contact-card { display: flex; flex-direction: column; gap: .25rem; padding: 1rem;
                border: 1px solid var(--line); border-radius: var(--r);
                text-decoration: none; color: inherit; background: var(--card); }
.contact-card:hover { border-color: var(--accent); }
.contact-card span { font-family: var(--mono); font-size: .6875rem; text-transform: uppercase;
                     letter-spacing: .05em; color: var(--ink-3); }
.contact-card strong { font-size: .9375rem; font-weight: 500; word-break: break-word; }
.contact-big .contact-card { padding: 1.25rem; }

.mini { display: grid; }
@media (min-width: 620px) { .mini { grid-template-columns: 1fr 1fr; column-gap: var(--gap); } }
.mini-item { padding-block: .75rem; border-bottom: 1px solid var(--line-2); }
.mini-item .k { font-size: .9375rem; font-weight: 500; }
.mini-item .v { font-family: var(--mono); font-size: .6875rem; color: var(--ink-3); margin-top: .1875rem; }

/* --- Images ---------------------------------------------------------------
   Every <img> ships its intrinsic width and height, so the browser reserves
   the right box before the bytes land and the page never jumps. These rules
   scale that box down responsively without losing the ratio.
   -------------------------------------------------------------------------- */

img { height: auto; }

.shot { margin: 1.125rem 0 0; border: 1px solid var(--line); border-radius: var(--r);
        overflow: hidden; background: var(--bg-2); max-width: 42rem; }
.shot img { width: 100%; }
.shot figcaption { padding: .625rem .875rem; border-top: 1px solid var(--line);
                   font-family: var(--mono); font-size: .6875rem; color: var(--ink-3);
                   line-height: 1.5; }

/* The portrait sits beside the bio on a wide screen and above it on a narrow
   one, which is what float gives without a second grid. */
.portrait { margin: 0 0 1rem; max-width: 11rem; }
.portrait img { width: 100%; border-radius: var(--r); border: 1px solid var(--line); }
@media (min-width: 620px) {
  .portrait { float: right; margin: .25rem 0 1rem 1.75rem; max-width: 13rem; }
}

/* A thumbnail bleeds to the card edges, so it cancels the card padding and
   restores it on the text below. Cards without one are unchanged. */
.card-shot { margin: -1.25rem -1.25rem .25rem; border-bottom: 1px solid var(--line);
             background: var(--bg-2); overflow: hidden;
             border-radius: var(--r) var(--r) 0 0; }
.card-shot img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; display: block; }
@supports not (aspect-ratio: 1) { .card-shot img { max-height: 12rem; object-fit: cover; } }

.out { display: flex; flex-wrap: wrap; gap: 1rem; font-family: var(--mono); font-size: .8125rem; }

/* --- Command palette ------------------------------------------------------ */

.palette { position: fixed; inset: 0; z-index: 90; background: rgba(0,0,0,.4);
           display: grid; place-items: start center; padding-top: 12vh; }
.palette[hidden] { display: none; }
.palette-box { width: min(34rem, calc(100vw - 2rem)); background: var(--bg);
               border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow);
               overflow: hidden; }
#palette-input { width: 100%; border: 0; border-bottom: 1px solid var(--line);
                 background: transparent; color: var(--ink); font: inherit; font-size: 1rem;
                 padding: .875rem 1rem; }
#palette-input::placeholder { color: var(--ink-3); }
#palette-input:focus { outline: none; }
#palette-list { max-height: 22rem; overflow-y: auto; }
#palette-list li a { display: flex; align-items: baseline; gap: .75rem; padding: .5625rem 1rem;
                     text-decoration: none; color: var(--ink-2); }
#palette-list li[aria-selected="true"] a, #palette-list li a:hover { background: var(--accent-soft); color: var(--ink); }
#palette-list .pk { font-family: var(--mono); font-size: .625rem; text-transform: uppercase;
                    letter-spacing: .06em; color: var(--accent); min-width: 3.75rem; }
#palette-list .pt { font-size: .875rem; }
.palette-none { padding: 1rem; font-family: var(--mono); font-size: .8125rem; color: var(--ink-3); }

/* --- Footer --------------------------------------------------------------- */

.foot-wrap { border-top: 1px solid var(--line); margin-top: 1rem; }
.foot { padding-block: 2rem clamp(2rem, 5vw, 3rem);
        display: flex; flex-wrap: wrap; gap: 1.25rem; justify-content: space-between; align-items: flex-start; }
.foot-name { font-size: .9375rem; font-weight: 600; }
.foot-meta { font-family: var(--mono); font-size: .75rem; color: var(--ink-3); margin-top: .1875rem; }
.foot-links { display: flex; flex-wrap: wrap; gap: 1.125rem; font-family: var(--mono); font-size: .78125rem; }
.foot-links a { text-decoration: none; color: var(--ink-3); }
.foot-links a:hover { color: var(--accent); }

/* --- Motion ----------------------------------------------------------------
   Every entrance runs once and then the page is still. Nothing loops, nothing
   waits for the cursor, and all of it is gated twice: on .js, so a page
   without scripts is simply complete, and on prefers-reduced-motion.
   --------------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
  a, .btn, .chip, .card, .toggle, .kbd-btn, .row-link, .contact-card, .skill-uses a {
    transition: color .15s ease, background-color .15s ease, border-color .15s ease, box-shadow .15s ease;
  }

  /* The hero settles in reading order, so the eye lands where it should. */
  .js .hero > * { animation: rise .55s cubic-bezier(.16, 1, .3, 1) both; }
  .js .hero > *:nth-child(2) { animation-delay: .07s; }
  .js .hero > *:nth-child(3) { animation-delay: .14s; }
  .js .hero > *:nth-child(4) { animation-delay: .21s; }
  .js .hero > *:nth-child(5) { animation-delay: .28s; }
  @keyframes rise {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
  }

  /* Cards and work rows surface as they enter the viewport, once. */
  .js .reveal { opacity: 0; transform: translateY(10px);
                transition: opacity .5s cubic-bezier(.16, 1, .3, 1),
                            transform .5s cubic-bezier(.16, 1, .3, 1); }
  .js .reveal.is-in { opacity: 1; transform: none; }

  /* The bars draw to their measured width the first time they are seen,
     which is the one place motion carries information: these are quantities. */
  .js .gantt-bar, .js .bar-fill {
    transform: scaleX(0); transform-origin: left center;
    transition: transform .8s cubic-bezier(.16, 1, .3, 1);
  }
  .js .chart.is-in .gantt-bar, .js .chart.is-in .bar-fill { transform: scaleX(1); }

  /* A thumbnail leans in with its card. */
  .card-shot img { transition: transform .45s cubic-bezier(.16, 1, .3, 1); }
  .card:hover .card-shot img { transform: scale(1.03); }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition-duration: .001ms !important; animation-duration: .001ms !important; }
}

@media print {
  .bar, .palette, .kbd-btn, .toggle, .filter, .card-go, .card-shot { display: none; }
  .portrait { float: none; max-width: 9rem; }
  body { background: #fff; color: #000; font-size: 11pt; }
  a { color: #000; }
  .sec-grid { grid-template-columns: var(--rail) 1fr; }
}

/* --- Dashboard -------------------------------------------------------------
   One hue with two states: accent for ongoing, neutral for ended. No second
   palette, and no bar ever carries meaning that its text label does not also
   carry, so none of this depends on seeing colour.
   -------------------------------------------------------------------------- */

.dash { border-top: 1px solid var(--line); }
.dash-head { margin-bottom: 2rem; }
.dash-head h2 { font-size: clamp(1.25rem, 2.6vw, 1.625rem); }
.dash-head p { margin-top: .625rem; color: var(--ink-2); font-size: .9375rem; max-width: 60ch; }

.stats { display: grid; gap: 0; border-top: 1px solid var(--line); margin-bottom: 2.75rem; }
@media (min-width: 640px) { .stats { grid-template-columns: repeat(4, 1fr); } }
.stat { padding: 1rem 1.25rem 1.125rem 0; border-bottom: 1px solid var(--line-2); }
@media (min-width: 640px) { .stat { border-bottom: none; } }
.stat dt { font-family: var(--mono); font-size: .6875rem; text-transform: uppercase;
           letter-spacing: .06em; color: var(--ink-3); }
/* Proportional figures: tabular digits make a standalone number look loose. */
.stat-v { font-size: clamp(1.5rem, 3.4vw, 1.9rem); font-weight: 600;
          letter-spacing: -.02em; margin-top: .375rem; line-height: 1.1; }
.stat-n { font-size: .78125rem; color: var(--ink-3); margin-top: .3125rem; line-height: 1.45; }

.chart { margin: 0 0 2.75rem; }
.chart:last-child { margin-bottom: 0; }
.chart figcaption { margin-bottom: 1.125rem; }
.chart figcaption h3 { font-size: 1.0625rem; }
.chart figcaption p { margin-top: .375rem; color: var(--ink-3); font-size: .84375rem;
                      max-width: 62ch; line-height: 1.55; }

/* --- Timeline ------------------------------------------------------------- */

.gantt { border-top: 1px solid var(--line); }

/* The axis shares the row grid exactly, so a tick sits over the month it marks
   rather than near it. */
.gantt-axis { display: grid; grid-template-columns: 1fr; padding-right: .5rem; }
@media (min-width: 720px) {
  .gantt-axis { grid-template-columns: 13rem minmax(0, 1fr) 8.5rem; gap: 1rem; }
}
.tick-track { position: relative; display: block; height: 1.5rem; }
.tick {
  position: absolute; top: .25rem; transform: translateX(-50%);
  font-family: var(--mono); font-size: .625rem; font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}
/* The end ticks would otherwise hang off the ends of the track. */
.tick:first-child { transform: none; }
.tick:last-child  { transform: translateX(-100%); }
.tick::after {
  content: ""; position: absolute; left: 50%; top: 1.05rem; width: 1px; height: .25rem;
  background: var(--line);
}
.tick:first-child::after { left: 0; }
.tick:last-child::after  { left: auto; right: 0; }

.gantt-rows { display: grid; list-style: none; margin: 0; padding: 0; }
.gantt-row > a {
  display: grid; grid-template-columns: 1fr; gap: .25rem;
  padding: .625rem .5rem .625rem 0; text-decoration: none; color: inherit;
  border-top: 1px solid var(--line-2); border-radius: var(--r);
  min-height: 2.75rem; align-items: center;
}
@media (min-width: 720px) {
  .gantt-row > a { grid-template-columns: 13rem minmax(0, 1fr) 8.5rem; gap: 1rem; }
}
.gantt-row > a:hover { background: var(--accent-soft); }

.gantt-label { display: flex; flex-direction: column; min-width: 0; }
.gantt-role { font-size: .875rem; font-weight: 500; }
.gantt-org { font-size: .78125rem; color: var(--ink-3); }
.gantt-row.is-live .gantt-org { color: var(--accent); }

.gantt-track { position: relative; height: 8px; background: var(--bg-2); border-radius: 999px; }
.gantt-bar {
  position: absolute; top: 0; height: 8px; border-radius: 999px;
  background: var(--ink-3); min-width: 8px;
}
.gantt-row.is-live .gantt-bar { background: var(--accent); }
.gantt-row > a:hover .gantt-bar { background: var(--accent); }

.gantt-when { font-family: var(--mono); font-size: .6875rem; font-variant-numeric: tabular-nums;
              color: var(--ink-3); white-space: nowrap; }
@media (min-width: 720px) { .gantt-when { text-align: right; } }

/* --- Domain coverage ------------------------------------------------------ */

.bars { display: grid; border-top: 1px solid var(--line); }
.bar-row {
  display: grid; grid-template-columns: 1fr; gap: .25rem;
  padding-block: .6875rem; border-bottom: 1px solid var(--line-2); align-items: center;
}
@media (min-width: 640px) {
  .bar-row { grid-template-columns: 8rem minmax(0, 1fr) 10rem; gap: 1rem; }
}
.bar-label { font-size: .875rem; font-weight: 500; }
.bar-track { height: 8px; background: var(--bg-2); border-radius: 999px; overflow: hidden; }
.bar-fill { display: block; height: 8px; background: var(--accent); border-radius: 999px; }
.bar-val { font-family: var(--mono); font-size: .6875rem; color: var(--ink-3);
           font-variant-numeric: tabular-nums; }
.bar-val strong { color: var(--ink); font-size: .8125rem; font-weight: 600; margin-right: .375rem; }
@media (min-width: 640px) { .bar-val { text-align: right; } }
