/* About hero, the stardust take (about-hero-stardust.js, the default). Its canvas runs on below the hero, so the storm
   can spill past its foot, and the stat's caption is a small tracked label centred under the figure that rises in
   word by word as the figure resolves. On phones the figure stacks under the copy, with room kept for it. */
.ab-hero-field.is-stardust .ab-sd { position: absolute; left: 0; right: 0; top: 0; bottom: calc(var(--sd-ext, 0px) * -1); }
.ab-hero-field.is-stardust .ab-sd canvas { display: block; width: 100%; height: 100%; }
.ab-sd-cap { position: absolute; margin: 0; transform: translateX(-50%); white-space: nowrap; font-family: var(--font-site); font-size: .82rem; font-weight: 700; line-height: 1.2; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
.ab-sd-cap .w { display: inline-block; overflow: hidden; vertical-align: top; padding: .04em .02em .12em; margin: -.04em -.02em -.12em; }
.ab-sd-cap .w > i { display: inline-block; font-style: normal; transform: translateY(112%) rotate(5deg); transform-origin: 0 100%; opacity: 0; filter: blur(5px);
  transition: transform 1.05s cubic-bezier(.16, 1, .3, 1), opacity .7s ease, filter .8s ease; transition-delay: calc(var(--i) * 75ms + 60ms); }
.ab-sd-cap.is-in .w > i { transform: none; opacity: 1; filter: blur(0); }
.ab-hero.is-sd-stack { padding-bottom: var(--sd-pad, calc(56vw + 120px)); }
@media (prefers-reduced-motion: reduce) { .ab-sd-cap .w > i { transition: none; } }

/* About hero, the infographic take (about-hero-info.js, ?hero=info): a grid of soft glass cards right of the copy, the
   20-year timeline a tall card on the left, four cards beside it. Every card has the same parts in the same places: a
   picture set from the card's top padding in a band --abi-vis tall, the figure (every figure one size), a small accent name and
   one muted line. Cards rise in turn (--t), then their pictures build (--c). */
.ab-hero.is-info { gap: clamp(32px, 4vw, 64px); }
.ab-hero.is-info .ab-hero-copy { flex: 1 1 0; }
/* the copy wipes in left to right behind the board as it sweeps across from the left, the way the Work page's copy
   comes in behind the phone (hero-wipe and hero-slide in styles.css); html.hero-info is set in the page head, so the
   wipe is in place from the first paint */
.hero-info .ab-hero-copy > :is(.about-kicker, .about-lead, .about-actions), .hero-info .ab-hero .ab-line > * {
  mask-image: linear-gradient(90deg, #000 29%, rgb(0 0 0 / .94) 38%, rgb(0 0 0 / .5) 50%, rgb(0 0 0 / .06) 62%, transparent 71%);
  mask-size: 350% 100%; mask-repeat: no-repeat;
  animation: hero-wipe 1300ms cubic-bezier(.2, .65, .22, 1) both, hero-slide 1300ms cubic-bezier(.2, .65, .22, 1) both; }
.hero-info .ab-hero .ab-line { overflow: visible; } /* the line clips only for its rise-in; left on, it cut the wipe's slide off with a hard edge */
.hero-info .ab-hero-copy > .about-kicker { animation-delay: 80ms; }
.hero-info .ab-hero .ab-line:first-child > * { animation-delay: 150ms; }
.hero-info .ab-hero .ab-line + .ab-line > * { animation-delay: 220ms; }
.hero-info .ab-hero-copy > .about-lead { animation-delay: 310ms; }
.hero-info .ab-hero-copy > .about-actions { animation-delay: 390ms; }
/* flown in (from Results or Experience): the copy rises in over the flight's second half as the camera swings round the
   peak, landing with it; the board's cards rise in turn alongside (about-hero-info.js) */
html.flown.hero-info .ab-hero-copy > :is(.about-kicker, .about-lead, .about-actions), html.flown.hero-info .ab-hero .ab-line > * { mask-image: none; animation: summit-soft .7s cubic-bezier(.2,.7,.2,1) both; } /* each piece moves in whole: a short rise and fade, no wipe */
html.flown.hero-info .ab-hero-copy > .about-kicker { animation-delay: 280ms; }
html.flown.hero-info .ab-hero .ab-line:first-child > * { animation-delay: 330ms; }
html.flown.hero-info .ab-hero .ab-line + .ab-line > * { animation-delay: 390ms; }
html.flown.hero-info .ab-hero-copy > .about-lead { animation-delay: 460ms; }
html.flown.hero-info .ab-hero-copy > .about-actions { animation-delay: 520ms; }
/* ...and the board's cards come up out of the scene in turn, each face fading in as it rises (faces fade on their own:
   opacity on the 3D card would flatten it), so no blank card waits on screen */
html.flown .abi-stat { --t: calc(var(--d) * 64ms + 40ms); transform: translateY(54px) translateZ(-90px); transition-duration: .8s; }
html.flown .ab-info .abi-face, html.flown .ab-info .abi-glare { opacity: 0; transition: opacity .45s ease var(--t); }
html.flown .ab-info.is-in .abi-face, html.flown .ab-info.is-in .abi-glare { opacity: 1; }
html.flown .ab-info.is-in .abi-stat { transform: none; }
@media (prefers-reduced-motion: reduce) { .hero-info .ab-hero-copy > :is(.about-kicker, .about-lead, .about-actions), .hero-info .ab-hero .ab-line > * { animation: none; mask-image: none; } }
.ab-hero.is-info .ab-hero-field { bottom: -160px; } /* the stardust canvas runs on below the hero, fading out, so no cloud is cut off */
.ab-info { --e: cubic-bezier(.16, 1, .3, 1); --abi-vis: 116px; flex: 0 1 680px; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
/* 3D: the panel is one preserve-3d scene (its transform set by the script); each card is a glass face at z 0 with its
   picture and words lifted off it, so they shift against the card as it turns. Nothing in the scene fades as a whole
   (opacity on a 3D parent flattens it): the face, glare and each lifted layer fade on their own. */
.ab-info { --rx: 8deg; --ry: -14deg; position: relative; z-index: 3; transform-style: preserve-3d; will-change: transform; /* over the copy as it sweeps across it */
  transform: translateX(var(--tx, 0px)) perspective(1600px) rotateX(var(--rx)) rotateY(var(--ry)); }
.abi-stat { --t: calc(var(--d) * 126ms + 175ms); --c: calc(var(--t) + 40ms); position: relative; display: flex; flex-direction: column; min-width: 0; padding: 18px 18px 17px; border-radius: 18px;
  transform-style: preserve-3d; transform: translateY(18px); transition: transform .8s var(--e) var(--t); }
.abi-face, .abi-glare { position: absolute; inset: 0; border-radius: inherit; pointer-events: none; } /* solid from the first frame, so the copy stays hidden under the board as it sweeps across */
.abi-face { background: linear-gradient(180deg, rgb(255 255 255 / .95), rgb(255 255 255 / .86));
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .85), 0 0 0 1px color-mix(in srgb, var(--ink) 7%, transparent), 0 26px 50px -30px color-mix(in srgb, var(--ink) 50%, transparent); }
.abi-glare { overflow: hidden; }
.abi-glare > i { position: absolute; left: -70%; top: -80%; width: 200%; height: 200%; background: radial-gradient(closest-side, rgb(255 255 255 / .55), rgb(255 255 255 / 0)); }
.abi-vis { height: var(--abi-vis); display: flex; align-items: flex-start; transform: translateZ(16px); }
.abi-num { display: flex; align-items: baseline; margin: 16px 0 0; font-family: var(--font-site); color: var(--ink); transform: translateZ(12px); }
.abi-num, .abi-cap, .abi-desc { opacity: 0; transition: opacity .56s ease var(--t); }
.abi-cap, .abi-desc { transform: translateZ(6px); }
.ab-info.is-in .abi-stat { transform: none; }
.ab-info.is-in :is(.abi-num, .abi-cap, .abi-desc) { opacity: 1; }
.abi-num b, .abi-suf { font-size: clamp(2.8rem, 3.4vw, 3.3rem); font-weight: 700; line-height: .9; letter-spacing: -.045em; font-variant-numeric: tabular-nums; }
.abi-suf { margin-left: .03em; color: var(--accent); opacity: 0; transition: opacity .4s ease calc(var(--t) + 1365ms); }
.ab-info.is-in .abi-suf { opacity: 1; }
.abi-cap { margin: 12px 0 0; font: 700 .7rem/1.2 var(--font-site); letter-spacing: .14em; text-transform: uppercase; color: var(--accent); }
.abi-desc { margin: 3px 0 0; font: 400 .9rem/1.35 var(--font-site); color: var(--muted); }
/* the 20 years: a tall run of blocks from 2006 down to 2026; the last 15 light up in the accent, bracketed and named */
.abi-spine { grid-row: span 2; }
.abi-spine .abi-vis { flex: 1; height: auto; align-items: stretch; }
.abi-tl { flex: 1; display: grid; grid-template-columns: 50px 7px minmax(0, 1fr); grid-template-rows: repeat(20, minmax(0, 1fr)); column-gap: 8px; row-gap: 3px; }
.abi-tl > i { grid-column: 1; border-radius: 3px; background: color-mix(in srgb, var(--ink) 10%, transparent); transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .44s var(--e), background-color .4s ease; transition-delay: calc(var(--c) + var(--i) * 20ms), calc(var(--c) + 455ms + (var(--i) - 5) * 22ms); }
.ab-info.is-in .abi-tl > i { transform: none; }
.ab-info.is-in .abi-tl > i.is-on { background: var(--accent); }
.abi-y0, .abi-note em { font: 700 .62rem/1 var(--font-site); font-style: normal; letter-spacing: .06em; color: var(--muted); font-variant-numeric: tabular-nums; }
.abi-y0 { grid-column: 3; grid-row: 1 / span 3; align-self: start; padding-top: 1px; opacity: 0; transition: opacity .48s ease var(--c); }
.abi-br { grid-column: 2; grid-row: 6 / 21; border: 2px solid var(--accent); border-left: 0; border-radius: 0 4px 4px 0; transform: scaleY(0); transform-origin: 50% 0; transition: transform .64s var(--e) calc(var(--c) + 490ms); }
.abi-note { grid-column: 3; grid-row: 6 / 21; display: flex; flex-direction: column; justify-content: space-between; opacity: 0; transform: translateX(-6px); transition: opacity .48s ease calc(var(--c) + 665ms), transform .64s var(--e) calc(var(--c) + 665ms); }
.abi-note em:last-child { align-self: flex-start; }
.abi-note > span { font: 600 .82rem/1.3 var(--font-site); color: var(--muted); }
.abi-note b { display: block; margin-bottom: 4px; font-size: 1.9rem; font-weight: 700; line-height: .9; letter-spacing: -.035em; color: var(--accent); font-variant-numeric: tabular-nums; }
.ab-info.is-in .abi-y0, .ab-info.is-in .abi-note { opacity: 1; transform: none; }
.ab-info.is-in .abi-br { transform: none; }
/* the tools: eight tiles warming from Flash toward agentic AI, the last in the accent with one soft ping as it lands */
.abi-tools { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; width: 100%; }
.abi-tools > span { display: grid; place-items: center; aspect-ratio: 1; border-radius: 10px; font: 700 .86rem/1 var(--font-site); letter-spacing: -.01em; color: var(--ink);
  background: color-mix(in srgb, var(--accent) calc(4% + var(--i) * 4.5%), #fff); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) calc(10% + var(--i) * 3%), transparent);
  opacity: 0; transform: translateY(12px) scale(.86); transition: transform .64s var(--e), opacity .36s ease; transition-delay: calc(var(--c) + var(--i) * 63ms); }
.abi-tools > span:last-child { color: #fff; background: var(--accent); box-shadow: 0 10px 20px -10px var(--accent); }
.ab-info.is-in .abi-tools > span { opacity: 1; transform: none; }
.ab-info.is-in .abi-tools > span:last-child { animation: abi-ping 1.04s ease-out calc(var(--c) + 665ms) both; }
@keyframes abi-ping { from { box-shadow: 0 10px 20px -10px var(--accent), 0 0 0 0 color-mix(in srgb, var(--accent) 45%, transparent); }
  to { box-shadow: 0 10px 20px -10px var(--accent), 0 0 0 12px transparent; } }
/* the projects: 99 dots in ink filling on a diagonal wave, then six accent dots trailing off for the "+" */
.abi-dots { display: grid; grid-template-columns: repeat(15, minmax(0, 1fr)); gap: 3.5px; width: 100%; }
.abi-dots > i { aspect-ratio: 1; border-radius: 50%; background: var(--ink); opacity: 0; transform: scale(.2); transition: transform .44s var(--e), opacity .28s ease; transition-delay: calc(var(--c) + var(--w) * 28ms); }
.abi-dots > i.is-plus { background: var(--accent); }
.ab-info.is-in .abi-dots > i { opacity: .2; transform: none; }
.ab-info.is-in .abi-dots > i.is-plus { opacity: var(--o); }
/* the industries: nine icons on the same diagonal wave, each name following its icon */
.abi-inds { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: 5px; width: 100%; }
.abi-ind { display: grid; justify-items: center; gap: 4px; font: 700 .5rem/1 var(--font-site); letter-spacing: .05em; text-transform: uppercase; color: var(--muted); white-space: nowrap; }
.abi-ind svg { width: 25px; height: 25px; fill: none; stroke: var(--accent); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; opacity: 0; transform: translateY(6px) scale(.7);
  transition: transform .56s var(--e), opacity .36s ease; transition-delay: calc(var(--c) + var(--w) * 63ms); }
.abi-ind svg .f { fill: var(--accent); fill-opacity: .14; stroke: none; }
.abi-ind svg circle { fill: #fff; }
.abi-ind > span { opacity: 0; transition: opacity .4s ease calc(var(--c) + 210ms + var(--w) * 63ms); }
.ab-info.is-in .abi-ind svg, .ab-info.is-in .abi-ind > span { opacity: 1; transform: none; }
/* the widest screen: a 32 ft curved immersive wall with a person standing before it for scale. Its edge draws in, it
   lights up and spills light on the floor, then the figure steps in and the 32 ft span is marked over it */
.abi-wall { display: block; width: 100%; overflow: visible; }
.abi-wall .w-edge { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 1.04s cubic-bezier(.65, 0, .25, 1) var(--c); }
.abi-wall .w-spill { fill: var(--accent); }
.abi-wall .w-glow, .abi-wall .w-spill { opacity: 0; transition: opacity .72s ease calc(var(--c) + 420ms); }
.abi-wall .w-dim { fill: none; stroke: var(--muted); stroke-width: 1; }
.abi-wall text { font: 700 7px var(--font-site); letter-spacing: .12em; fill: var(--muted); }
.abi-wall .w-dim, .abi-wall text { opacity: 0; transition: opacity .48s ease calc(var(--c) + 700ms); }
.abi-wall .w-person { fill: var(--ink); opacity: 0; transform: translateY(5px); transition: opacity .48s ease calc(var(--c) + 770ms), transform .64s var(--e) calc(var(--c) + 770ms); }
.ab-info.is-in .abi-wall .w-edge { stroke-dashoffset: 0; }
.ab-info.is-in .abi-wall :is(.w-glow, .w-spill, .w-dim, text, .w-person) { opacity: 1; transform: none; }
.ab-info.is-still *, .ab-info.is-still { transition: none !important; animation: none !important; }
@media (max-width: 900px) {
  .ab-hero.is-info { flex-direction: column; align-items: stretch; padding-bottom: clamp(24px, 3vw, 40px); }
  .ab-info { flex: none; grid-template-columns: repeat(2, minmax(0, 1fr)); transform: none; }
  .abi-spine { grid-row: auto; grid-column: 1 / -1; }
  .abi-spine .abi-vis { flex: none; height: 220px; }
}
/* tablets and narrow windows (561 to 900px): the board keeps its desktop arrangement under the copy, the timeline a tall
   card at the left and the four cards two by two beside it, at the desktop board's width, so no card stretches wide
   and leaves its picture lost in empty space */
@media (min-width: 561px) and (max-width: 900px) {
  .ab-info { grid-template-columns: repeat(3, minmax(0, 1fr)); width: 100%; max-width: 720px; }
  .abi-spine { grid-row: span 2; grid-column: auto; }
  .abi-spine .abi-vis { flex: 1; height: auto; }
}
@media (max-width: 560px) {
  .ab-info { --abi-vis: 96px; gap: 10px; }
  .abi-stat { padding: 14px; }
  .abi-ind > span { display: none; }
}

/* What sets me apart: each column glides up into place as it comes on, in turn (--i, set by approach-story.js), and its
   parts follow whole, never wiped or blurred: the icon rises in and fades up, then the heading
   and the paragraph each rise a short way and fade in, a beat apart. */
.about-animated .edge-item[data-reveal] { opacity: 1; transform: translateY(46px); transition: transform 1.4s var(--about-ease) calc(var(--i, 0) * 160ms); }
.about-animated .edge-item[data-reveal].is-revealed { transform: none; }
.about-animated .edge-item[data-reveal] > * { --s: calc(var(--i, 0) * 160ms); }
.about-animated .edge-item[data-reveal] > .edge-icon { opacity: 0; transform: translateY(22px);
  transition: opacity .8s ease var(--s), transform 1.3s var(--about-ease) var(--s); }
.about-animated .edge-item[data-reveal] > :is(h3, p) { opacity: 0; translate: 0 18px; transition: opacity .9s ease, translate 1.2s var(--about-ease); }
.about-animated .edge-item[data-reveal] > h3 { transition-delay: calc(var(--s) + 200ms); }
.about-animated .edge-item[data-reveal] > p { transition-delay: calc(var(--s) + 380ms); }
.about-animated .edge-item[data-reveal].is-revealed > :is(.edge-icon, h3, p) { opacity: 1; transform: none; translate: 0 0; }

/* A connected practice: as it scrolls into view its parts rise a short way and fade in, in turn: the eyebrow, each line
   of the heading, then the link. Whole, never wiped. */
.about-animated .ab-route .about-section-head[data-reveal] { opacity: 1; transform: none; transition: none; }
.about-animated .ab-route .about-section-head[data-reveal] :is(.about-kicker, h2, h2 em, .about-text-link) { opacity: 0; translate: 0 22px; transition: opacity .6s ease, translate .8s var(--about-ease); }
.about-animated .ab-route .about-section-head[data-reveal] h2 { transition-delay: 60ms; }
.about-animated .ab-route .about-section-head[data-reveal] h2 em { transition-delay: 130ms; }
.about-animated .ab-route .about-section-head[data-reveal] .about-text-link { transition-delay: 200ms; }
.about-animated .ab-route .about-section-head[data-reveal].is-revealed :is(.about-kicker, h2, h2 em, .about-text-link) { opacity: 1; translate: 0 0; }

/* The infographic in the dark theme (Nocturne): dark glass cards so the light figures and words read, the tool tiles
   warming from the page's own dark toward the accent, a fainter glare. */
html[data-variant=nocturne] .abi-face { background: linear-gradient(180deg, color-mix(in srgb, var(--ink) 11%, var(--bg)), color-mix(in srgb, var(--ink) 5%, var(--bg)));
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .09), 0 0 0 1px rgb(0 0 0 / .35), 0 26px 50px -28px rgb(0 0 0 / .7); }
html[data-variant=nocturne] .abi-glare > i { opacity: .18; }
html[data-variant=nocturne] .abi-tools > span { background: color-mix(in srgb, var(--accent) calc(10% + var(--i) * 6%), var(--bg)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) calc(22% + var(--i) * 4%), transparent); }
html[data-variant=nocturne] .abi-tools > span:last-child { background: var(--accent); color: #fff; }
html[data-variant=nocturne] .abi-ind svg circle { fill: var(--bg); }
html[data-variant=nocturne] .abi-tl > i { background: color-mix(in srgb, var(--ink) 16%, transparent); }

/* "Outside the work": the chapter rail as one slim line of bars pinned bottom centre between its two arrows. No label:
   each chapter already names itself in its own text. The bars stay links, the arrows step through. */
.curio-rail { column-gap: 8px; }
.curio-rail ol { margin: 0; gap: 6px; }
.curio-rail a { width: 34px; height: 20px; }
.curio-rail i { height: 2px; }
.curio-rail a:hover i, .curio-rail a.is-active i { height: 3px; }
.curio-rail .curio-rail-label { display: none; }
/* Phones: the chapter bars and arrows keep their look but get 44px tap targets, from an invisible pad around each. */
@media (max-width: 760px) {
  .curio-rail a::before, .curio-rail .curio-step::before { content: ''; position: absolute; inset: -12px -5px; }
  .curio-rail .curio-step { position: relative; }
  .curio-rail .curio-step::before { inset: -8px; }
}

/* The close, without a headline: the profile, the note and the two buttons as one centred block in the dark band,
   no divider, the note held to a comfortable measure. */
.about-page .ab-close { grid-template-columns: minmax(0, 1fr) !important; justify-items: center; text-align: center; }
.about-page .ab-close-aside { grid-area: auto; max-width: 36rem; padding: 0 !important; border: 0 !important; }
.about-page .ab-close-who { justify-content: center; text-align: left; }
.about-page .ab-close .about-actions { justify-content: center; }

