@font-face{font-family:Oswald;src:url(../fonts/Oswald-Regular.woff2) format("woff2");font-weight:400;font-display:swap}
@font-face{font-family:Oswald;src:url(../fonts/Oswald-Bold.woff2) format("woff2");font-weight:700;font-display:swap}
:root{--bg:#0c1017;--bg2:#131a24;--card:#171f2b;--text:#eef2f7;--muted:#9fb0c3;--orange:#f1420b;--orange-2:#f1420b;--blue:#2a93c1;--blue-2:#3b9bd5;--blue-3:#3a60ab;--cyan:#009dd9;
  --panel:rgba(12,16,23,.80);--mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;--ease:cubic-bezier(.2,.7,.1,1)}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
a,button{touch-action:manipulation}
html{scroll-behavior:smooth;background:var(--bg)}
body{margin:0;color:var(--text);font:400 18px/1.65 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:var(--bg);overflow-x:hidden}
a{color:var(--blue-2)}a:hover{color:#fff}
:focus-visible{outline:3px solid var(--blue-2);outline-offset:3px;border-radius:4px}
img{max-width:100%;height:auto}
h1,h2,h3,.title,.display,.eyebrow,.btn,.site-head{font-family:Oswald,Impact,"Arial Narrow",sans-serif}
.skip{position:absolute;left:-999px;top:8px;z-index:100;background:#fff;color:#000;padding:8px 12px}.skip:focus{left:8px}
#world{position:fixed;inset:0;width:100vw;height:100vh;height:100lvh;z-index:0;display:none;pointer-events:none}
html[data-mode="3d"] #world,html[data-mode="lite"] #world,html[data-mode="2d"] #world{display:block}
.grain{position:fixed;inset:0;z-index:1;pointer-events:none;background:radial-gradient(ellipse at 70% 20%,rgba(42,147,193,.10),transparent 55%),radial-gradient(ellipse at 15% 85%,rgba(241,66,11,.08),transparent 50%)}
html[data-mode="3d"] .grain,html[data-mode="lite"] .grain{background:none}
.site-head,main,.site-foot{position:relative;z-index:2}
.site-head{position:sticky;top:0;display:flex;align-items:center;justify-content:space-between;gap:16px;padding:10px clamp(16px,4vw,48px);background:rgba(12,16,23,.72);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border-bottom:1px solid rgba(59,155,213,.18);z-index:20}
.brand{display:inline-flex;align-items:center;min-height:44px}.brand img{display:block;height:44px;width:auto}
.site-head ul{display:flex;flex-wrap:wrap;gap:4px 18px;list-style:none;margin:0;padding:0}
.site-head nav a{display:inline-flex;align-items:center;min-height:44px;color:var(--text);text-decoration:none;text-transform:uppercase;letter-spacing:.08em;font-size:14px}
.site-head nav a:hover{color:var(--orange-2)}
.nav-toggle{display:none;background:none;border:1px solid var(--blue-2);color:var(--text);font:inherit;padding:6px 14px;min-height:44px;border-radius:6px}
@media (max-width:980px){.nav-toggle{display:block}.site-head nav{display:none;position:absolute;top:100%;left:0;right:0;background:rgba(12,16,23,.97);padding:16px 24px}.site-head nav.open{display:block}.site-head ul{flex-direction:column;gap:12px}}
/* hero */
.hero{min-height:100vh;min-height:100svh;display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);align-items:center;gap:24px;padding:96px clamp(20px,5vw,72px) 64px;position:relative}
.hero-copy{position:relative;z-index:2;max-width:720px}
.eyebrow{font-size:13px;text-transform:uppercase;letter-spacing:3px;color:var(--muted);margin:0 0 8px}
.display{font-size:clamp(56px,10vw,148px);line-height:.92;font-weight:700;text-transform:uppercase;margin:0 0 16px;letter-spacing:-.01em}
.display .ch{display:inline-block}
.role{font-family:Oswald,sans-serif;font-size:clamp(20px,2.4vw,28px);margin:0 0 10px}
.ventures a{font-family:Oswald,sans-serif;color:var(--orange-2);text-decoration:none;text-transform:uppercase;letter-spacing:.06em;margin-right:14px;font-size:18px}
.ventures a:hover{color:#fff}
.tagline{font-size:clamp(20px,2vw,26px);margin:14px 0 6px;color:#fff;text-wrap:pretty}
.tagline-long{color:var(--muted);font-size:15px;max-width:60ch}
.soc{display:flex;flex-wrap:wrap;gap:8px;list-style:none;padding:0;margin:14px 0}
.soc a{display:inline-flex;align-items:center;min-height:44px;font-size:14px;padding:6px 14px;border:1px solid rgba(59,155,213,.45);border-radius:999px;color:var(--text);text-decoration:none;background:rgba(19,26,36,.6)}
.soc a:hover{border-color:var(--orange-2)}
.btn{display:inline-block;background:var(--orange-2);color:#0c1017;border:0;font-size:17px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;padding:12px 22px;border-radius:6px;text-decoration:none;cursor:pointer;margin:4px 8px 4px 0}
@media (hover:hover) and (pointer:fine){.btn:hover{background:#fff;color:#0c1017}}
.btn.ghost{background:transparent;color:var(--text);border:1px solid var(--blue-2)}
.hero-portrait{margin:0;justify-self:center;width:min(440px,80%);aspect-ratio:1;position:relative}
.hero-portrait img{width:100%;height:100%;object-fit:cover;clip-path:polygon(50% 2%,92% 26%,92% 74%,50% 98%,8% 74%,8% 26%);background:radial-gradient(circle,#2a93c1,#3a60ab 60%,#f1420b)}
.hexframe{position:absolute;inset:0;fill:none;stroke:var(--blue-2);stroke-width:.8;filter:drop-shadow(0 0 6px rgba(59,155,213,.8))}
html.gl-portrait[data-mode="3d"] .hero-portrait,html.gl-portrait[data-mode="lite"] .hero-portrait{opacity:0;transition:opacity .45s}
.hero-banner{display:none}
.motion-toggle{position:absolute;right:clamp(16px,3vw,32px);bottom:20px;z-index:3;background:rgba(12,16,23,.7);color:var(--muted);border:1px solid rgba(159,176,195,.35);border-radius:999px;font:13px var(--mono);padding:6px 14px;min-height:44px;cursor:pointer}
html[data-mode="static"] .motion-toggle,html:not(.js) .motion-toggle{display:none}
@media (max-width:860px){.hero{grid-template-columns:1fr;padding-top:84px;text-align:left}.hero-portrait{grid-row:1;width:min(300px,72vw);height:auto}
  html[data-mode="3d"] .hero-portrait,html[data-mode="lite"] .hero-portrait{height:min(300px,72vw)}}
/* Mobile (<=767px) hero re-order (Jared round 5, 2026-11-05): HELLO,I'M -> JARED SANBORN (tight) ->
   Founder & CEO (ABOVE photo) -> photo -> brand links (tight under photo, ONE line) -> tagline
   ("what I do for people", must sit above the fold) -> CTAs. CSS-only: .hero is a flex column and
   .hero-copy is flattened with display:contents so the portrait (a sibling) orders between role and
   the brand links. DOM order, no-JS order and >=768 layout are all UNCHANGED (everything here is
   scoped to <=767). A small 8px flex gap replaces the inherited 24px grid gap and per-element
   margins are zeroed so the stack is tight and the tagline clears a 390x844 / 360x780 fold. */
@media (max-width:767px){
  .hero{display:flex;flex-direction:column;align-items:stretch;padding-top:16px;gap:6px}
  .hero-copy{display:contents}
  .hero .eyebrow{order:1;margin:0}
  /* Name on ONE line <414 too (QA r5b: broke "Sanbo|rn" at 360, "Sanbor|n" at 390-402).
     nowrap keeps the .ch spans on one row; a vw-scaled clamp shrinks the Oswald name so
     13 uppercase chars fit the ~viewport-40px content width at 360 and never wrap, capped
     at 56px for larger phones. <=767 only; the >=768 rule (white-space:nowrap) is untouched. */
  #hero-name{order:2;margin:0;white-space:nowrap;font-size:clamp(34px,11.5vw,56px);line-height:.9}
  .hero .role{order:3;margin:0}
  /* Portrait trimmed from 72vw to 62vw on phones so the role (above) + brand links + tagline all
     clear the fold at 360x780 and 390x844. Still ~223px at 360 / ~242px at 390. The 3D headshot
     renders at this box (world.js station 'hero'), so the data-mode height is matched. */
  .hero-portrait{order:4;align-self:center;margin:2px 0 0;width:min(240px,54vw)}
  html[data-mode="3d"] .hero-portrait,html[data-mode="lite"] .hero-portrait{height:min(240px,54vw)}
  /* Brand links: Pure Technology blue (--cyan, the live site's #009dd9) AT REST, highlight
     (--orange-2) only on hover/tap/focus. One line at 360/390/414: nowrap flex row, viewport-scaled
     font + tight tracking/gap so the three uppercase links never wrap or overflow horizontally. */
  .hero .ventures{order:5;margin:0;display:flex;flex-wrap:nowrap;justify-content:center;align-items:baseline;gap:clamp(5px,2vw,11px);white-space:nowrap}
  .hero .ventures a{margin:0;font-size:clamp(10px,2.9vw,14px);letter-spacing:.01em;color:var(--cyan);white-space:nowrap}
  .hero .ventures a:focus-visible,.hero .ventures a:active{color:var(--orange-2)}
  /* Tagline ("what I do for people") must sit above a REAL iPhone-Safari usable fold
     (390x700, 360x660) AND clear the floating chat mascot. Smaller mobile type + tighter
     line-height cuts it from ~7 lines to ~4 without touching the copy (Jared owns wording).
     Desktop (>=768) keeps clamp(20px,2vw,26px). <=767 only. */
  .hero .tagline{order:6;margin:6px 0 0;font-size:clamp(16px,4.2vw,18px);line-height:1.3}
  .hero .cta-row{order:7;padding-bottom:28px;margin:4px 0 0}
  /* Pause-motion control (WCAG 2.2.2). ROOT FIX (2026-11-05, Task E): the base rule (line 48) makes
     this button position:absolute;bottom:20px, pinning it to the hero's bottom edge. The hero is
     min-height:100svh and starts ~65px below the sticky header, so the button's TOP landed ~1px
     BELOW the fold on load (measured: top=845 at innerH=844 / top=781 at 780) -> fully off-screen.
     The existing order:8 was a dead rule under position:absolute. On a real iPhone, activating an
     off-screen button triggers Safari's scroll-into-view-on-focus (plus dynamic URL-bar resize),
     so the whole page lurches -- what Jared saw as "everything gets wonky". Pausing itself causes
     ZERO content shift (verified); the bug was purely the off-screen button placement. Fix: flow it
     in the hero column (order:8 now live), discoverable, so interacting never scroll-lurches. Fixed
     min-width + centered so the "Pause motion" <-> "Play motion" label swap does not move the button
     (zero rect delta on toggle). <=767 only; desktop keeps the absolute placement unchanged. */
  .hero .motion-toggle{order:8;position:static;right:auto;bottom:auto;align-self:center;margin:10px 0 0;min-width:140px;text-align:center}
  .hero-banner{order:9}
}
/* Tap/hover highlight gated to fine pointers so mobile Safari's sticky :hover does not flip the
   brand-link colour on a stray tap (per 2026-11-05 iOS sticky-hover RCA). :active/:focus-visible
   above cover touch + keyboard. */
@media (max-width:767px) and (hover:hover) and (pointer:fine){
  .hero .ventures a:hover{color:var(--orange-2)}
}
/* Short real-iPhone-Safari usable viewports (390x700, 360x660, 375x667): the floating chat
   mascot (mascot.v1.js .oc-root, fixed bottom:66px => its TOP sits at viewport-138px) was
   painting over the tagline's last line. The mascot is a third-party widget NOT in this repo;
   rather than override its position, we tighten the hero ONLY on short screens (<=710px tall)
   so the tagline bottom clears viewport-138. Photo -> 46vw, gaps/line-height trimmed. Taller
   phones keep the 54vw photo and were already clear. Copy is untouched (Jared owns wording). */
@media (max-width:767px) and (max-height:710px){
  .hero{gap:4px;padding-top:12px}
  .hero-portrait{width:min(185px,46vw);margin:0 auto}
  html[data-mode="3d"] .hero-portrait,html[data-mode="lite"] .hero-portrait{height:min(185px,46vw)}
  .hero .tagline{font-size:clamp(15px,4vw,17px);line-height:1.24;margin:4px 0 0}
  .hero .cta-row{padding-bottom:16px;margin:2px 0 0}
}
/* sections */
.band{padding:clamp(56px,10vh,120px) clamp(16px,5vw,72px);position:relative}
.panel{max-width:820px;background:var(--panel);border:1px solid rgba(59,155,213,.16);border-radius:18px;padding:clamp(22px,4vw,48px);box-shadow:0 30px 80px rgba(0,0,0,.35)}
.panel.wide{max-width:1180px;margin:0 auto}
.panel.split{max-width:1180px;display:grid;grid-template-columns:minmax(0,1.3fr) minmax(0,.9fr);gap:40px;align-items:center}
html[data-mode="3d"] .site-head,html[data-mode="lite"] .site-head,html[data-mode="2d"] .site-head{backdrop-filter:none;-webkit-backdrop-filter:none;background:rgba(12,16,23,.9)}
html[data-mode="3d"] .panel,html[data-mode="lite"] .panel{background:rgba(12,16,23,.88)}
@media (max-width:860px){.panel.split{grid-template-columns:minmax(0,1fr)}}
.band:nth-of-type(odd) .panel{margin-left:auto}
.title{font-size:clamp(40px,6vw,72px);line-height:1;font-weight:700;text-transform:uppercase;margin:0 0 18px}
.sub{font-family:Oswald,sans-serif;color:var(--orange-2);font-size:22px;margin:-6px 0 14px}
.lede{font-size:19px;max-width:66ch}
.lede a,.prose a{overflow-wrap:anywhere}
.ai-partners{list-style:none;margin:22px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:28px}
.ai-partners figure{margin:0;display:flex;align-items:center;gap:12px}
.ai-partners img{width:72px;height:72px;border-radius:50%;object-fit:cover;display:block;border:2px solid var(--orange-2)}
.ai-partners figcaption{display:flex;flex-direction:column;line-height:1.2}
.ai-partners figcaption strong{font-family:Oswald,sans-serif;font-size:18px}
.ai-partners figcaption span{color:var(--muted);font-size:14px}
.quote{margin:20px 0;padding:6px 0 6px 20px;border-left:3px solid var(--orange-2);font-family:Oswald,sans-serif;font-size:clamp(20px,2.3vw,26px);line-height:1.35;color:#fff}
.quote p{margin:0}
.motto{color:var(--orange-2);font-family:Oswald,sans-serif;letter-spacing:.04em}
.about-photo img,.node-photo img{border-radius:14px;display:block}
.node-photo{max-width:240px;justify-self:center;margin:0}
.hint{color:var(--muted);font-size:14px}
.ring-stage{height:clamp(260px,42vh,420px);touch-action:pan-y;cursor:grab;display:none;margin:8px 0}
.ring-stage.tall{height:clamp(320px,52vh,520px)}
html[data-mode="3d"] .ring-stage,html[data-mode="lite"] .ring-stage{display:block}
.ring-ctl button{min-height:44px;min-width:44px;font:14px var(--mono);background:rgba(19,26,36,.8);color:var(--text);border:1px solid var(--blue-2);border-radius:6px;padding:8px 14px;cursor:pointer}
html:not([data-mode="3d"]):not([data-mode="lite"]) .js-only{display:none}
/* PRESS list — interactive logo wall. Logos only by default; each is a disclosure
   <button>; its headline/excerpt/link live in a .press-panel that is in the HTML at
   load (crawlable + SR-reachable), collapsed with grid-rows:0fr (mobile accordion) or
   visibility (desktop popover) — never display:none. The 16-logo press RING above is
   a separate atlas-driven canvas (world.js) and is untouched. */
.press-grid{list-style:none;padding:0;margin:20px 0 0;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
@media (min-width:768px){.press-grid{grid-template-columns:repeat(4,minmax(0,1fr))}.press-logo{aspect-ratio:111/10;-webkit-mask-size:var(--msd,auto 94%);mask-size:var(--msd,auto 94%)}}
.press-card{position:relative;margin:0}
.press-trigger{display:flex;align-items:center;justify-content:center;width:100%;min-height:60px;margin:0;padding:12px 14px;border-radius:12px;background:var(--card);border:1px solid rgba(59,155,213,.18);color:var(--text);font:inherit;cursor:pointer;-webkit-appearance:none;appearance:none;transition:transform .35s var(--ease),border-color .35s}
/* Every logo is recoloured to one brand tint (--text) by masking a solid fill with the
   logo's own alpha. mask-size is set per logo, per breakpoint, INLINE as --msd (desktop) /
   --msm (mobile) in build.py (table PRESS_MASK): a single-auto-axis value so the mask aspect
   is preserved and the ink is GUARANTEED to fit inside the tile (width capped ~84%, height
   ~94%, whichever binds first for the tile aspect) with margin — wide wordmarks go width-bound
   (slightly shorter) instead of clipping at the tile edge. --arm-m overrides the mobile tile
   aspect for a short thin wordmark that needs more vertical room (CEOWORLD). */
/* mask-image is set INLINE per logo (document-relative url) in build.py — NOT here and NOT
   via a custom property: a relative url() in a custom property resolves against this
   stylesheet's base (assets/css/) and 404s -> empty tiles. Here we set only the geometry. */
.press-logo{position:relative;display:block;width:100%;aspect-ratio:var(--arm-m,111/14);background-color:var(--text);opacity:.82;-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:var(--msm,auto 94%);mask-repeat:no-repeat;mask-position:center;mask-size:var(--msm,auto 94%);transition:opacity .35s var(--ease)}
.press-logo img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;opacity:0;pointer-events:none}
.press-trigger:focus-visible{outline:2px solid var(--orange-2);outline-offset:3px}
.press-card.is-open>.press-trigger{border-color:var(--orange-2)}
.press-card.is-open .press-logo{opacity:1}
@media (hover:hover) and (pointer:fine){.press-trigger:hover{transform:translateY(-3px);border-color:var(--orange-2)}.press-trigger:hover .press-logo,.press-trigger:focus-visible .press-logo{opacity:1}}
.press-panel .outlet{display:block;font:600 12px var(--mono);letter-spacing:.03em;text-transform:uppercase;color:var(--blue-2)}
.press-panel .headline{margin:4px 0 0;font-weight:600;line-height:1.3;color:var(--text)}
.press-panel .excerpt{margin:6px 0 0;font-size:14px;line-height:1.5;color:var(--muted)}
.press-link{display:inline-block;align-self:flex-start;margin-top:10px;font:13px var(--mono);color:var(--orange-2);text-decoration:none;border-bottom:1px solid currentColor;padding-bottom:1px}
.press-link:focus-visible{outline:2px solid var(--orange-2);outline-offset:3px}
.press-panel-inner{display:flex;flex-direction:column}
/* No-JS baseline: details are plain visible blocks under each logo (crawlable, usable). */
html:not(.js) .press-panel{padding:8px 2px 0}
/* JS reveal (ALL widths): details are an absolute popover card anchored under the logo. It
   OVERLAYS and never changes layout, so opening a tile moves/reorders no neighbour and adds
   zero CLS (fixes the mobile open-reflow that orphaned cells + reordered tiles). JS flips
   alignment at grid edges (.pp-left/.pp-right) so the card never overflows the viewport on the
   2-col (mobile) or 4-col (desktop) grid. One-open-at-a-time, tap-outside, Escape, aria all in
   site.js. Hover-to-open stays desktop-only (site.js gates it on the hover/fine media query). */
html.js .press-panel{position:absolute;top:calc(100% + 8px);left:50%;transform:translateX(-50%) translateY(6px);width:min(300px,86vw);max-width:300px;z-index:6;display:block;padding:16px;background:var(--card);border:1px solid var(--orange-2);border-radius:12px;box-shadow:0 18px 50px rgba(0,0,0,.5);visibility:hidden;opacity:0;pointer-events:none;transition:opacity .22s var(--ease),transform .22s var(--ease)}
html.js .press-panel.pp-left{left:0;transform:translateX(0) translateY(6px)}
html.js .press-panel.pp-right{left:auto;right:0;transform:translateX(0) translateY(6px)}
html.js .press-panel-inner{overflow:visible;padding:0}
html.js .press-card.is-open{z-index:7}
html.js .press-card.is-open>.press-panel{visibility:visible;opacity:1;pointer-events:auto;transform:translateX(-50%) translateY(0)}
html.js .press-card.is-open>.press-panel.pp-left,html.js .press-card.is-open>.press-panel.pp-right{transform:translateX(0) translateY(0)}
.outlet{font:12px var(--mono);color:var(--muted);text-transform:uppercase;letter-spacing:.1em}
.headline{font-family:Oswald,sans-serif;font-size:19px;line-height:1.25;color:#fff}
.excerpt{font-size:14px;color:var(--muted);line-height:1.5}
.skills{list-style:none;padding:0;display:grid;grid-template-columns:1fr;gap:18px}
.skill h3{font-size:22px;margin:0;display:flex;justify-content:space-between}.pct{color:var(--orange-2);font-family:var(--mono);font-size:16px}
.meter{height:6px;background:rgba(159,176,195,.18);border-radius:3px;overflow:hidden;margin:6px 0}
.meter span{display:block;height:100%;width:calc(var(--p)*1%);background:linear-gradient(90deg,var(--blue-3),var(--blue),var(--cyan));transform-origin:left;transition:transform 1.4s var(--ease)}
html.js .skill:not(.in) .meter span{transform:scaleX(0)}
.skill p{margin:4px 0 0;font-size:16px;color:#d7dee8}
.timeline,.edus{list-style:none;padding:0;margin:24px 0 0;position:relative}
.timeline::before{content:"";position:absolute;left:6px;top:0;bottom:0;width:2px;background:linear-gradient(var(--blue),var(--orange-2))}
.role-card,.edu{position:relative;padding:0 0 30px 34px}
.role-card::before,.edu::before{content:"";position:absolute;left:0;top:8px;width:14px;height:14px;border-radius:50%;background:var(--bg);border:2px solid var(--orange-2);box-shadow:0 0 12px rgba(241,66,11,.7)}
.role-card h3,.edu h3{font-size:clamp(24px,3vw,32px);margin:0;line-height:1.1}
.dates{font:13px var(--mono);color:var(--muted);margin:0}
.rtitle{color:var(--orange-2);font-family:Oswald,sans-serif;margin:2px 0 8px;font-size:19px}
.rbody p{margin:0 0 10px;font-size:16.5px}
.rlinks{display:flex;flex-wrap:wrap;gap:8px 16px;padding:0;list-style:none;font-size:15px}
.gallery-grid{list-style:none;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px}
.gallery-grid figure{margin:0}.gallery-grid img{border-radius:10px;aspect-ratio:3/4;object-fit:cover;width:100%}
html[data-mode="3d"] .gallery-grid,html[data-mode="lite"] .gallery-grid{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
/* gallery cells are real buttons (open the lightbox: click / Enter / Space). In 3d/lite the grid is sr-only,
   so it reveals itself when a keyboard user tabs into it (like the skip link) — that is the keyboard path. */
html[data-mode="3d"] .gallery-grid:focus-within,html[data-mode="lite"] .gallery-grid:focus-within{position:static;width:auto;height:auto;overflow:visible;clip:auto}
.gcell{display:block;width:100%;margin:0;padding:0;border:0;background:none;cursor:zoom-in;border-radius:10px}
.gcell>img{display:block;pointer-events:none}
/* ---- GALLERY LIGHTBOX (position:fixed overlay; brand tokens only; no layout shift) */
.lightbox[hidden]{display:none}
.lightbox{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;padding:4vmin}
.lightbox-backdrop{position:absolute;inset:0;background:rgba(6,9,14,.93);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
.lightbox-fig{position:relative;z-index:1;margin:0;max-width:92vw;max-height:92vh;display:flex}
.lightbox-img{display:block;max-width:92vw;max-height:92vh;width:auto;height:auto;object-fit:contain;border-radius:10px;box-shadow:0 24px 90px rgba(0,0,0,.65)}
.lightbox-close{position:absolute;z-index:2;top:max(12px,env(safe-area-inset-top,0px));right:max(12px,env(safe-area-inset-right,0px));min-width:44px;min-height:44px;font:700 24px/1 Oswald,Impact,sans-serif;color:var(--text);background:var(--panel);border:1px solid var(--blue-2);border-radius:8px;cursor:pointer}
.lightbox-close:hover{border-color:var(--orange-2);color:#fff}
.lightbox-nav{position:absolute;z-index:2;top:50%;transform:translateY(-50%);display:flex;align-items:center;justify-content:center;min-width:52px;min-height:52px;font:700 30px/1 Oswald,Impact,sans-serif;color:var(--text);background:var(--panel);border:1px solid var(--blue-2);border-radius:999px;cursor:pointer;padding:0}
.lightbox-prev{left:max(12px,env(safe-area-inset-left,0px))}
.lightbox-next{right:max(12px,env(safe-area-inset-right,0px))}
.lightbox-nav:hover,.lightbox-nav:focus-visible{border-color:var(--orange-2);color:#fff}
.lightbox-nav:focus-visible{outline:2px solid var(--orange-2);outline-offset:2px}
@media (max-width:480px){.lightbox-nav{min-width:44px;min-height:44px;font-size:24px}}
html.lb-open,html.lb-open body{overflow:hidden}
@media (prefers-reduced-motion:no-preference){.lightbox{animation:lbin .18s var(--ease)}}
@keyframes lbin{from{opacity:0}to{opacity:1}}
.net-groups{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:24px}
.net-group h3{font-size:20px;margin:0 0 8px;color:var(--orange-2)}
.net{list-style:none;padding:0;margin:0;display:grid;gap:8px}
.net a{display:flex;align-items:center;min-height:44px;gap:10px;color:var(--text);text-decoration:none;font-size:15px}.net a:hover span{color:var(--orange-2)}
.net img{width:32px;height:32px;border-radius:8px}
.cards{list-style:none;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(270px,1fr));gap:16px}
.card a{display:flex;flex-direction:column;gap:6px;background:var(--card);border-radius:12px;overflow:hidden;text-decoration:none;color:var(--text);border:1px solid rgba(59,155,213,.16);height:100%;padding-bottom:14px;transition:transform .35s var(--ease)}
@media (hover:hover) and (pointer:fine){.card a:hover{transform:translateY(-4px)}}
.card img{aspect-ratio:16/9;object-fit:cover;width:100%}
.card .dates,.card .ctitle,.card .cex{padding:0 14px}.ctitle{font-family:Oswald,sans-serif;font-size:20px;line-height:1.2;color:#fff}.cex{font-size:14px;color:var(--muted)}
.minis{list-style:none;padding:0;margin:20px 0;font-size:15px}.minis p{margin:2px 0 10px;color:var(--muted)}
.contact{display:grid;gap:12px}
.contact label{display:grid;gap:4px;font-family:Oswald,sans-serif;letter-spacing:.04em}
.contact input,.contact textarea{font:inherit;font-size:16px;padding:10px 12px;border-radius:8px;border:1px solid rgba(159,176,195,.35);background:rgba(23,31,43,.9);color:var(--text)}
.note{font-size:14px;color:var(--muted)}
.site-foot{text-align:center;padding:48px 20px 64px;color:var(--muted);font-size:14px;background:rgba(12,16,23,.9)}
.site-foot .sig{width:240px;opacity:.9}.fine{font-size:12px}
/* Follow links relocated from the hero into the footer (Jared, 2026-11-05). Compact pills,
   centered to match footer typography, wrapping at 390/768/1440. */
.foot-follow{margin:4px 0 16px}
.soc-foot{justify-content:center;gap:6px 8px;margin:0}
.soc-foot a{min-height:38px;font-size:13px;padding:5px 13px}
/* Footer clearance (Jared review, 2026-11-05; QA fix 2026-11-05): the fixed bottom-right OctoPure
   mascot sits with its TOP at innerHeight-184px at every width (390..1440), so the last footer
   text lines (the "Designed by... Privacy Policy" credit and the copyright) fell under it at max
   scroll. Measured on the staging preview: mascot top = innerHeight-184 at 390/768/1024/1100/1280/
   1440, so the last footer line must clear ~190-200px from the viewport bottom. The old 150px at
   <=860px was short (768 overlapped at true max; 1024 kept the 64px default and overlapped too).
   Reserve >=200px (plus the iOS home-indicator safe-area) at <=1100px so the last footer lines
   scroll clear of the mascot's vertical band at every affected width. Desktop >1100px is left at the
   64px default: the centered footer text's ink never reaches the mascot's x there (clears by
   182px at 1280, 262px at 1440 - measured), so there is no overlap to fix. */
@media (max-width:1100px){.site-foot{padding-bottom:max(150px, calc(env(safe-area-inset-bottom, 0px) + 200px))}}
/* cinematic reveals (JS modes only; content is visible without JS) */
html.js:not([data-mode="static"]) .reveal{opacity:0;transform:translate3d(0,40px,0) scale(.985);transition:opacity .9s var(--ease),transform 1.1s var(--ease)}
html.js .reveal.in{opacity:1;transform:none}
html.js:not([data-mode="static"]) .cine{opacity:0;transform:translateY(18px);filter:blur(6px)}
html.js .cine.on{opacity:1;transform:none;filter:none;transition:opacity .7s var(--ease),transform .9s var(--ease),filter .7s}
html.js:not([data-mode="static"]):not(.paused) .display .ch{animation:chin .8s var(--ease) both;animation-delay:calc(var(--i)*30ms)}
@keyframes chin{from{transform:translateY(.35em) rotateX(-70deg)}to{transform:none}}
html.paused *{animation-play-state:paused!important}
/* The gallery lightbox opens by calling setPaused(true) to freeze the ring/world; without this exemption the
   html.paused rule above froze the .lightbox lbin fade-in (opacity 0->1) at its first frame, so the photo and
   its close button rendered invisible and the page looked frozen (round-7 bug). Keep scene pause for everything
   else; let the lightbox and its children animate so the photo is visible when opened. */
html.paused .lightbox,html.paused .lightbox *{animation-play-state:running!important}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}*{transition:none!important;animation:none!important}}
/* sub pages */
.sub-main{max-width:860px;margin:0 auto;padding:48px 20px 80px}
.ptitle{font-size:clamp(34px,5vw,58px);line-height:1.05;text-transform:uppercase;margin:6px 0 10px}
.meta{font:14px var(--mono);color:var(--muted)}.pex{font-size:20px;color:#fff}
.feat{border-radius:14px;margin:12px 0 24px;width:100%}
.prose{font-size:18px}.prose h2{font-size:30px;margin-top:1.6em}.prose h3{font-size:23px}.prose hr{border:0;border-top:1px solid rgba(59,155,213,.25);margin:2em 0}
.prose table{border-collapse:collapse;width:100%}.prose td{border:1px solid rgba(159,176,195,.3);padding:8px}
.pn{display:flex;justify-content:space-between;gap:16px;margin-top:48px;font-family:Oswald,sans-serif}
.chips{display:flex;flex-wrap:wrap;gap:8px;list-style:none;padding:0}.chips a{display:inline-flex;align-items:center;min-height:44px;padding:4px 14px;border:1px solid rgba(59,155,213,.4);border-radius:999px;text-decoration:none;color:var(--text);font-size:14px}
.taxo h2{font-size:18px;color:var(--muted);text-transform:uppercase;letter-spacing:.1em}
.qs{list-style:none;padding:0;display:grid;gap:16px}
.q fieldset{border:1px solid rgba(59,155,213,.22);border-radius:12px;padding:16px;background:var(--card)}
.q legend{padding:0 6px}.qn{font-family:var(--mono);color:var(--orange-2)}.dim{display:block;font:12px var(--mono);color:var(--muted);text-transform:uppercase;letter-spacing:.08em}
.scale{display:flex;gap:8px;margin-top:10px}.scale label{flex:1}
.scale input{position:absolute;opacity:0}.scale span{display:block;text-align:center;padding:11px 0;min-height:44px;border:1px solid rgba(159,176,195,.35);border-radius:8px;cursor:pointer;font-family:var(--mono)}
.scale input:checked+span{background:var(--orange-2);color:#0c1017;border-color:var(--orange-2)}.scale input:focus-visible+span{outline:3px solid var(--blue-2)}
.anchors{display:flex;justify-content:space-between;font-size:13px;color:var(--muted);margin:6px 0 0}
.live{font-family:var(--mono)}.tiers{list-style:none;padding:0;display:grid;gap:14px}
.tier{border-left:4px solid var(--tc);padding:10px 16px;background:var(--card);border-radius:0 10px 10px 0}.tier h3{margin:0}.th{font-family:Oswald,sans-serif;font-size:20px;color:#fff}
.result{border:1px solid var(--orange-2);border-radius:14px;padding:20px;margin:24px 0;background:var(--card)}
/* round 2: every section owns a 3D stage beside (desktop) or above (mobile) its text; never under it */
.st-stage{display:none;pointer-events:none}
.drag-cue{display:none}
html[data-mode="3d"] .st-stage,html[data-mode="lite"] .st-stage{display:block;height:clamp(250px,44vh,400px);margin:0 0 12px}
html[data-mode="3d"] .ringpanel,html[data-mode="lite"] .ringpanel{background:transparent;border-color:transparent;box-shadow:none}
html[data-mode="3d"] .ringpanel .title,html[data-mode="3d"] .ringpanel .hint,html[data-mode="lite"] .ringpanel .title,html[data-mode="lite"] .ringpanel .hint{text-shadow:0 2px 18px #0c1017,0 0 4px #0c1017}
html[data-mode="3d"] .ring-stage,html[data-mode="lite"] .ring-stage{position:relative}
html[data-mode="3d"] .drag-cue,html[data-mode="lite"] .drag-cue{display:block;position:absolute;left:50%;bottom:6px;transform:translateX(-50%);font:13px var(--mono);letter-spacing:.2em;text-transform:uppercase;color:#fff;
  background:rgba(12,16,23,.6);border:1px solid rgba(241,66,11,.7);border-radius:999px;padding:6px 14px;animation:cue 2.4s var(--ease) infinite;pointer-events:none}
.ring-stage.used .drag-cue{opacity:0;transition:opacity .6s;animation:none}
@keyframes cue{0%,100%{transform:translateX(-58%)}50%{transform:translateX(-42%)}}
@media (min-width:861px){
  html[data-mode="3d"] .band.has-stage,html[data-mode="lite"] .band.has-stage{min-height:100vh;display:flex;align-items:center}
  html[data-mode="3d"] .has-stage .st-stage,html[data-mode="lite"] .has-stage .st-stage{position:absolute;top:0;bottom:0;height:auto;margin:0;right:clamp(16px,3vw,48px);width:calc(100% - min(780px,54vw) - clamp(16px,5vw,72px) - clamp(32px,6vw,96px))}
  html[data-mode="3d"] .has-stage:nth-of-type(odd) .st-stage,html[data-mode="lite"] .has-stage:nth-of-type(odd) .st-stage{left:clamp(16px,3vw,48px);right:auto}
  html[data-mode="3d"] .has-stage .panel,html[data-mode="lite"] .has-stage .panel{width:min(780px,54vw);max-width:none;margin:0 auto 0 0}
  html[data-mode="3d"] .has-stage:nth-of-type(odd) .panel,html[data-mode="lite"] .has-stage:nth-of-type(odd) .panel{margin:0 0 0 auto}
  html[data-mode="3d"] .has-stage .panel.split,html[data-mode="lite"] .has-stage .panel.split{grid-template-columns:minmax(0,1fr)}
  html[data-mode="3d"] .has-stage .net-groups,html[data-mode="lite"] .has-stage .net-groups{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}
  html[data-mode="3d"] .has-stage .cards,html[data-mode="lite"] .has-stage .cards{grid-template-columns:repeat(auto-fill,minmax(220px,1fr))}
}
.pager a,a.older,a.newer{display:inline-flex;align-items:center;min-height:44px}
/* V2 task-2: keep the hero name on ONE line at tablet+ (>=768px). Mobile (<=767px) layout untouched. */
@media (min-width:768px){#hero-name.display{white-space:nowrap;font-size:clamp(38px,5.5vw,112px)}}
/* V2 task-1 (2026-11-05): tagline line 1 stays LARGE on desktop (>= the tablet 20px floor, never
   shrunk to fit). Exactly 2 lines is achieved by WIDENING the hero text column + tagline and
   shrinking the portrait column (per Jared), NOT by shrinking the font. Tablet/mobile untouched. */
@media (min-width:1024px){
  .hero{grid-template-columns:minmax(0,1fr) clamp(190px,19vw,440px);gap:clamp(20px,2vw,36px);padding-left:clamp(28px,4vw,72px);padding-right:clamp(28px,4vw,72px)}
  .hero-copy{max-width:860px}
  .tagline{font-size:clamp(20px,1.6vw,23px);max-width:none}
}
/* Wide screens have room: give the portrait/3D-headshot column back toward its full size.
   The tagline (capped at hero-copy 860px) still renders exactly 2 lines; the portrait shrink is
   localised to small laptops (1024–1439) where the width is genuinely tight. */
@media (min-width:1440px){
  .hero{grid-template-columns:minmax(0,1fr) clamp(360px,28vw,560px)}
}
/* V2 task-A: amplify line (tagline line 2) -> ALL CAPS + pt-tech-site gradient color sweep (stops verbatim from pt-tech-site index.html; site --blue/--orange tokens where they exist). Source text unchanged. */
.tagline .amplify-line{text-transform:uppercase}
.pt-gradient-headline{background:linear-gradient(100deg,#144fb0 0%,var(--blue,#65cdf0) 26%,#7fb4ff 42%,#ffffff 50%,#ffcfa8 58%,var(--orange,#f1420b) 74%,#c23108 100%);background-size:280% 100%;-webkit-background-clip:text;background-clip:text;color:transparent;-webkit-text-fill-color:transparent;animation:pt-sweep 9s ease-in-out infinite}
@keyframes pt-sweep{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}
@media (prefers-reduced-motion:reduce){.pt-gradient-headline{animation:none;background-position:50% 50%}}
/* V2 task (2026-11-05): mobile-only collapsible disclosure (progressive enhancement, built by site.js),
   SHARED by Experience roles (.role-card) and Education entries (.edu).
   No-JS and >=768px: role-head + rpanel are plain blocks, fully expanded (no visual change at >=768).
   <=767px: each entry collapses its body behind an accessible disclosure button overlaying its header. */
.role-head{position:relative}
.role-toggle{display:none}
.rpanel-inner{min-width:0}
@media (max-width:767px){
  .role-head{padding-right:30px}
  .role-toggle{display:block;position:absolute;inset:0;width:100%;height:100%;margin:0;padding:0;border:0;background:transparent;color:inherit;font:inherit;cursor:pointer;-webkit-appearance:none;appearance:none;z-index:2;border-radius:6px}
  .role-toggle:focus-visible{outline:2px solid var(--orange-2);outline-offset:4px}
  .role-chev{position:absolute;top:7px;right:3px;width:11px;height:11px;border-right:2px solid var(--orange-2);border-bottom:2px solid var(--orange-2);transform:rotate(225deg);transition:transform .3s var(--ease)}
  .is-collapsed .role-chev{transform:rotate(45deg)}
  .rpanel{display:grid;grid-template-rows:1fr;transition:grid-template-rows .32s var(--ease)}
  .rpanel-inner{overflow:hidden}
  .is-collapsed .rpanel{grid-template-rows:0fr}
}
@media (max-width:767px) and (prefers-reduced-motion:reduce){
  .rpanel,.role-chev{transition:none}
}

/* ABOUT expandable bio (item 5): collapsed preview + accessible "Read more" disclosure.
   .about-more is in the HTML at load and collapsed via max-height (NOT display:none) so it stays
   crawlable; JS adds .open and flips the button's aria-expanded. */
.about-toggle{display:inline-flex;align-items:center;justify-content:center;gap:.4em;min-height:44px;background:transparent;color:var(--orange-2);border:1px solid var(--orange-2);font-family:Oswald,sans-serif;font-size:15px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;padding:8px 16px;border-radius:6px;cursor:pointer;margin:14px 0 2px}
@media (hover:hover) and (pointer:fine){.about-toggle:hover{background:var(--orange-2);color:#0c1017}}
.about-toggle:focus-visible{outline:2px solid var(--orange-2);outline-offset:2px}
.about-toggle[aria-expanded="true"] .about-toggle-label::after{content:""}
.about-more{overflow:hidden;max-height:0;opacity:0;transition:max-height .4s ease,opacity .3s ease}
.about-more.open{max-height:120em;opacity:1;margin-top:.4em}
.about-more p{font-size:17px;max-width:66ch;margin:0 0 .9em}
@media (prefers-reduced-motion:reduce){.about-more{transition:none}}

/* Octopus mascot (item 1): the third-party chat mascot (mascot.v1.js .oc-root) must never cover the
   OPEN chat's close-X on mobile. The widget hides itself on open in current builds; this page-side
   net keys off its pbchat:state event (site.js adds html.jds-chat-open) and yields the mascot on
   narrow screens so the close-X stays fully visible and tappable. Scoped to the external .oc-root
   only; does not affect the ?octo=debug prototype. */
@media (max-width:600px){
  html.jds-chat-open .oc-root{opacity:0!important;visibility:hidden!important;pointer-events:none!important}
}
