  /* ===== galleries (offline view) ===== */
  .gal{columns:3;column-gap:clamp(12px,1.4vw,20px)}
  @media (max-width:1000px){.gal{columns:2}}
  @media (max-width:600px){.gal{columns:1}}
  /* four speaking shots as one even strip - kept modest so the source
     files (1024–1200px) always render above 1x and stay sharp */
  .gal-feat{
    columns:auto;display:grid;grid-template-columns:repeat(4,1fr);
    gap:clamp(12px,1.4vw,20px);max-width:1700px;margin:0 auto;
  }
  .gal-feat .ph{margin:0;aspect-ratio:4/3}
  .gal-feat .ph img{height:100%;object-fit:cover}
  @media (max-width:900px){.gal-feat{grid-template-columns:repeat(2,1fr);max-width:900px}}
  @media (max-width:560px){.gal-feat{grid-template-columns:1fr;max-width:480px}}
  /* team roster - 3 columns x 2 rows of square photos beside the intro copy,
     kept short so the section doesn't run much taller than Tech Stack */
  .gal-roster{
    columns:auto;display:grid;grid-template-columns:repeat(3,1fr);
    gap:clamp(8px,1vw,14px);
  }
  .gal-roster .ph{margin:0;aspect-ratio:1}
  .gal-roster .ph img{height:100%;object-fit:cover}
  .ph{
    break-inside:avoid;margin:0 0 clamp(12px,1.4vw,20px);
    position:relative;overflow:hidden;border-radius:var(--rad);cursor:zoom-in;
    background:var(--line);
    /* every figure carries its real aspect ratio in --ar already - this is
       what actually uses it. Without it, the box has no height until the
       image finishes loading, so everything below it (and the whole rest
       of the column layout) jumps as each photo comes in. In the security
       view there's nothing photo-heavy enough for that shift to move a
       section's position before a click there resolves; here, with two
       36-plus-photo galleries, it was enough to land a nav click short of
       or past the section it was aimed at. */
    aspect-ratio:var(--ar,4/3);
  }
  .ph img{display:block;width:100%;height:auto;transition:scale calc(var(--mo) * 2) var(--mo-ease)}
  .ph:hover img{scale:1.05}
  .ph figcaption{
    position:absolute;left:0;right:0;bottom:0;padding:26px 16px 13px;
    font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:#fff;
    background:linear-gradient(transparent,rgba(10,9,8,.78));
    opacity:0;translate:0 8px;transition:opacity var(--mo) ease-out,translate var(--mo) ease-out;
  }
  .ph:hover figcaption,.ph:focus-visible figcaption{opacity:1;translate:0 0}
  /* lightbox */
  .lb{
    position:fixed;inset:0;z-index:98;display:none;place-items:center;
    background:rgba(12,11,9,.93);padding:clamp(16px,4vw,56px);cursor:zoom-out;
  }
  .lb.on{display:grid}
  .lb img{max-width:100%;max-height:82vh;border-radius:12px;display:block}
  .lb figcaption{
    margin-top:16px;text-align:center;font-family:var(--mono);font-size:11px;
    letter-spacing:.12em;text-transform:uppercase;color:var(--cream-dim);
  }
  .lb-close{
    position:absolute;top:clamp(12px,2vw,26px);right:clamp(12px,2vw,26px);
    width:44px;height:44px;border-radius:50%;border:1.5px solid #55504733;
    background:rgba(255,255,255,.08);color:var(--cream);font-size:20px;line-height:1;cursor:pointer;
  }

  /* off duty band */
  .off{background:var(--panel);border-radius:24px;margin:0 var(--gut);padding:clamp(28px,5vw,56px)}
  .off h2{font-family:var(--disp);font-weight:400;text-transform:uppercase;font-size:clamp(28px,4vw,52px);margin-bottom:16px}
  .off p{font-size:clamp(16px,1.35vw,19px);line-height:1.6;max-width:74ch;color:#403D36}
  .off p + p{margin-top:16px}
  /* highlights both use the page's own orange now - plain bold colored
     text, no pill background behind it */
  .off .stick{color:var(--orange);font-weight:700}
  .off .stick2{color:var(--orange);font-weight:700}
  .off .meta{margin-top:20px;font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--meta)}

  /* summary + contact form */
  .off-grid{display:grid;grid-template-columns:1.35fr 1fr;gap:clamp(28px,4vw,72px);align-items:start}
  @media (max-width:900px){.off-grid{grid-template-columns:1fr}}
  /* Group One: text+photo stack on the left, a 2x3 roster grid on the right */
  .grp-cols{grid-template-columns:1fr 1fr}
  @media (max-width:900px){.grp-cols{grid-template-columns:1fr}}
  .cform{display:flex;flex-direction:column;gap:7px}
  .cform h3{font-size:clamp(19px,1.7vw,24px);font-weight:700;letter-spacing:-.015em;margin-bottom:6px}
  .cform label{
    font-family:var(--mono);font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;
    color:var(--meta);margin-top:8px;
  }
  .cform input,.cform textarea{
    font:inherit;font-size:15px;color:var(--ink);
    background:#fff;border:1.5px solid var(--line);border-radius:12px;
    padding:12px 14px;width:100%;resize:vertical;
    transition:border-color .18s ease-out,box-shadow .18s ease-out;
  }
  .cform input::placeholder,.cform textarea::placeholder{color:#8A8479}
  .cform input:focus,.cform textarea:focus{
    outline:none;border-color:var(--ink);box-shadow:0 0 0 3px rgba(240,127,40,.22);
  }
  .cform input:user-invalid,.cform textarea:user-invalid{border-color:var(--pink)}
  .cform button[type=submit]{
    margin-top:16px;align-self:flex-start;cursor:pointer;
    font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;
    background:var(--ink);color:var(--light);border:0;border-radius:99px;padding:14px 26px;
    transition:background .18s ease-out,translate .18s ease-out;
  }
  .cform button[type=submit]:hover{background:var(--orange);translate:0 -2px}
  .cf-note{font-size:12px!important;color:var(--meta);margin-top:12px;line-height:1.5}
  .cf-note a{color:var(--ink)}
  .cf-copy{
    background:none;border:0;padding:0;cursor:pointer;color:var(--orange);
    font:inherit;font-size:12px;text-decoration:underline;
  }

  /* footer */
  footer{
    /* the photo backdrop is dark in every theme, so the footer's text and
       pill tokens are pinned to a light, warm tone here rather than
       following the active theme/view - --cream flips to a near-black
       ink in the light theme, which would vanish against this image */
    --cream:#F3EEE2; --cream-dim:#C7C0AE;
    --pill-line:rgba(255,255,255,.24); --pill-quiet:rgba(255,255,255,.28); --pill-fg:#BFB8A8;
    background-color:var(--card);color:var(--cream);
    position:relative;isolation:isolate;overflow:hidden;
    /* a quiet seam at the boundary, now that the section above and the
       footer can land on the same background tone with nothing else
       marking where one ends and the other begins */
    border-top:1px solid var(--pill-line);
    /* the gap before the footer used to be margin-top *and* its own
       padding-top doing almost the same job - the margin half sat outside
       footer's own dark box, in space that belonged to neither element's
       background, so it showed through as a stray light bar once the
       section above went dark. The padding alone is enough. */
    padding:clamp(56px,9vh,100px) var(--gut) clamp(40px,6vh,64px);
  }
  /* the fellowship shot: a single moody backdrop behind the glass card
     below, same in both themes since the overlay does the contrast work.
     Its own element (rather than living on footer's background) so it can
     rise into place the same way the tile does - up and in, every time the
     footer crosses into view, not just the first. */
  .f-bg{
    position:absolute;inset:-4% -4%;z-index:-1;
    background-image:url(../footer-bg.webp);
    background-size:cover;background-position:center 38%;background-repeat:no-repeat;
    opacity:0;translate:0 42px;
    transition:opacity .9s cubic-bezier(.16,1,.3,1),translate .9s cubic-bezier(.16,1,.3,1);
  }
  footer.on .f-bg{opacity:1;translate:0 0}
  @media (prefers-reduced-motion:reduce){.f-bg{transition:opacity .3s ease-out}}
  /* dark scrim between the photo and everything else, so cream text and
     the glass card's own light border stay legible against whatever part
     of the image lands behind them */
  footer::before{
    content:"";position:absolute;inset:0;z-index:0;
    background:linear-gradient(180deg,rgba(10,9,7,.55),rgba(10,9,7,.72) 55%,rgba(10,9,7,.86));
  }
  /* the tile itself: a liquid-glass pane floating over the photo - frosted,
     faintly lit at the top edge like light catching curved glass - plus a
     simple rise-and-fade every time it crosses into view, not just the
     first, so scrolling back down to it later still finds it arriving
     rather than sitting there already-on. */
  .f-tile{
    position:relative;z-index:1;
    max-width:900px;margin:0 auto;
    padding:clamp(44px,6vw,76px) clamp(20px,4.5vw,56px);
    border-radius:clamp(22px,3vw,34px);
    background:linear-gradient(165deg,rgba(255,255,255,.14),rgba(255,255,255,.04) 40%,rgba(255,255,255,.07));
    border:1px solid rgba(255,255,255,.24);
    box-shadow:0 24px 60px -20px rgba(0,0,0,.55),inset 0 1px 0 rgba(255,255,255,.35),inset 0 0 40px rgba(255,255,255,.04);
    backdrop-filter:blur(22px) saturate(160%);-webkit-backdrop-filter:blur(22px) saturate(160%);
    opacity:0;translate:0 30px;
    transition:opacity .7s cubic-bezier(.16,1,.3,1),translate .7s cubic-bezier(.16,1,.3,1);
  }
  footer.on .f-tile{opacity:1;translate:0 0}
  @media (max-width:600px){
    .f-tile{
      border-radius:20px;
      background:linear-gradient(165deg,rgba(255,255,255,.16),rgba(255,255,255,.05) 40%,rgba(255,255,255,.08));
      backdrop-filter:blur(14px) saturate(150%);-webkit-backdrop-filter:blur(14px) saturate(150%);
    }
  }
  /* the CTA text follows a beat behind the tile itself, so the two read as
     one arrival staged in two steps rather than everything landing at once */
  .f-intro{
    opacity:0;translate:0 34px;filter:blur(6px);
    transition:opacity .8s cubic-bezier(.16,1,.3,1) .1s,
               translate .8s cubic-bezier(.16,1,.3,1) .1s,
               filter .8s cubic-bezier(.16,1,.3,1) .1s;
  }
  footer.on .f-intro{opacity:1;translate:0 0;filter:blur(0)}
  @media (prefers-reduced-motion:reduce){
    .f-tile{transition:opacity .3s ease-out}
    .f-intro{transition:opacity .3s ease-out}
  }
  footer .big{
    font-family:var(--disp);font-weight:400;text-transform:uppercase;
    font-size:clamp(44px,8.4vw,128px);line-height:.96;text-align:center;
  }
  footer .big a{text-decoration:none;transition:color .18s ease-out}
  footer .big a:hover{color:var(--orange)}
  footer .sub{text-align:center;color:var(--cream-dim);font-size:14.5px;max-width:52ch;margin:20px auto 30px}
  /* plain labelled lines, not pills */
  .f-links{
    list-style:none;padding:0;display:grid;grid-template-columns:repeat(2,auto);
    justify-content:center;gap:clamp(20px,3vw,52px);
  }
  .f-links li{
    display:flex;flex-direction:column;gap:6px;min-width:0;
    font-family:var(--mono);font-size:clamp(10px,.78vw,12.5px);
  }
  .f-links .k{
    font-size:8.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--cream-dim);
  }
  .f-links a{
    color:var(--cream-dim);text-decoration:none;word-break:break-all;
    transition:color .18s ease-out;
  }
  .f-links a:hover{color:var(--orange)}
  @media (max-width:520px){.f-links{grid-template-columns:1fr;gap:16px}}
  /* social row: our own palette on a plain circular pill, not the
     platforms' own brand colors or artwork - the shape reads as "LinkedIn"
     or "GitHub" well enough on its own without borrowing their marks */
  .f-social{display:flex;justify-content:center;gap:14px;margin-top:clamp(30px,4.5vh,44px)}
  .f-soc{
    display:flex;align-items:center;justify-content:center;
    width:42px;height:42px;border-radius:50%;flex:none;
    border:1.5px solid var(--pill-quiet);color:var(--cream-dim);
    transition:border-color .18s ease-out,background .18s ease-out,color .18s ease-out,translate .18s ease-out;
  }
  .f-soc svg{width:19px;height:19px;fill:currentColor}
  /* the one outline icon in the set - everything else here is a solid path */
  .f-soc svg.f-ig{fill:none}
  .f-soc svg.f-ig rect,.f-soc svg.f-ig circle{fill:none;stroke:currentColor;stroke-width:1.7}
  .f-soc svg.f-ig .f-ig-dot{fill:currentColor;stroke:none}
  .f-soc:hover{background:var(--orange);border-color:var(--orange);color:#fff;translate:0 -3px}
  .f-bottom{
    display:flex;flex-direction:column;align-items:center;gap:8px;
    border-top:1px solid rgba(255,255,255,.18);margin-top:clamp(40px,7vh,72px);padding:16px 0 0;
    font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--cream-dim);
  }
  /* the credit is long - one line at this size rather than wrapping into a
     paragraph, with a quiet horizontal scroll as the escape hatch on a
     phone narrow enough that even the small size cannot fit it */
  .aud-credit{
    display:block;max-width:100%;overflow-x:auto;
    white-space:nowrap;scrollbar-width:none;-ms-overflow-style:none;
  }
  .aud-credit::-webkit-scrollbar{display:none}

  /* Security dark mode: the summary card itself now goes dark to match the
     rest of the profile, so its copy, headings, pills, and the contact
     form all get the same light-on-dark tokens the footer already uses. */
  html[data-theme="dark"] .off{background:var(--sec-hi)}
  html[data-theme="dark"] .off h2{color:var(--cream)}
  html[data-theme="dark"] .off p{color:var(--pill-fg)}
  html[data-theme="dark"] .off .meta{color:var(--pill-fg)}
  html[data-theme="dark"] .cform h3{color:var(--cream)}
  html[data-theme="dark"] .cform label{color:var(--pill-fg)}
  html[data-theme="dark"] .cform input,
  html[data-theme="dark"] .cform textarea{
    background:var(--sec-hi);color:var(--cream);border-color:var(--pill-line);
  }
  html[data-theme="dark"] .cform input::placeholder,
  html[data-theme="dark"] .cform textarea::placeholder{color:var(--pill-fg)}
  html[data-theme="dark"] .cform button[type=submit]{background:var(--cream);color:var(--sec-hi)}
  html[data-theme="dark"] .cf-note{color:var(--pill-fg)}
  html[data-theme="dark"] .cf-note a{color:var(--cream)}
  /* footer sits on --card everywhere else, which is correct there - but in
     security dark mode the section right above it now shares that exact
     tone, so a step lighter here gives the seam a second, independent cue
     beyond just the rule above */
  html[data-theme="dark"] footer{background-color:var(--sec-hi)}
