:root{--bg:#000;--fg:#fff;--acc:#F5A524;--mut:#7B7B7B;--pnl:#0D0D0D}
*{margin:0;padding:0;box-sizing:border-box}
/* overflow-x:clip, not hidden: `hidden` would make body a scroll container,
   which breaks the view()/scroll() timelines below. `clip` clips without that. */
body{background:var(--bg);color:var(--fg);font-family:Archivo,sans-serif;overflow-x:clip}
.wrap{width:100%;max-width:1240px;margin:0 auto;padding:0 26px}
nav{display:flex;justify-content:space-between;align-items:center;padding:22px 0}
.logo{font-weight:900;font-size:19px;letter-spacing:-.02em;color:inherit;text-decoration:none}
.pill{display:inline-block;background:var(--acc);color:#000;padding:12px 24px;border-radius:100px;text-decoration:none;font-weight:700;font-size:13px;text-transform:uppercase;letter-spacing:.06em}
.pill:hover{filter:brightness(1.12)}
/* overflow:clip rather than hidden — see body. `hidden` here made the hero its
   own scroll container, so its children's view() timeline resolved against a box
   that never scrolls and the exit drift never ran. */
/* No min-height and no vertical centring: on a phone that pushed the headline
   a full screen down. The hero is as tall as its content. */
.hero{position:relative;overflow:clip;padding:56px 0 64px}
.hero::before{content:"";position:absolute;inset:0;background:radial-gradient(120% 90% at 70% 40%,#1C1C1C 0%,#000 70%);z-index:-1}
h1{font-size:clamp(40px,7.6vw,104px);font-weight:900;line-height:.9;text-transform:uppercase;letter-spacing:-.045em;max-width:15ch}
h1 em{font-style:normal;color:var(--acc)}
.sub{font-size:clamp(19px,2.3vw,27px);font-weight:700;color:var(--fg);letter-spacing:-.015em;margin:28px 0 0}
/* #D9D9D9, not var(--mut): the muted grey failed to read against black at this
   size. ~11:1 on the hero's gradient, still visibly secondary to the sub. */
.hero-lede{color:#D9D9D9;font-size:17px;line-height:1.7;max-width:680px;margin:24px 0 36px}
.hero-lede p+p{margin-top:16px}
.hero-cta{display:flex;flex-wrap:wrap;align-items:center;gap:12px}
/* two-column hero: copy left, image right. h1 is stepped down from its
   full-width scale so it still fits a ~half-width column. */
.hero-grid{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr);gap:56px;align-items:center}
.hero-copy h1{font-size:clamp(34px,4.4vw,62px);max-width:18ch}
.hero-shot{margin:0}
.hero-shot img{display:block;width:100%;height:auto;border-radius:6px}
/* Phone order is headline, photo, sub, paragraph, button. .hero-copy dissolves
   into the grid (display:contents) so the photo can slot in after the headline. */
@media(max-width:900px){
  .hero{padding:14px 0 44px}
  .hero-grid{grid-template-columns:1fr;gap:0}
  .hero-copy{display:contents}
  .hero-copy h1{font-size:clamp(40px,7.6vw,104px);max-width:15ch;order:1}
  .hero-shot{order:2;margin-top:28px}
  .hero-copy .sub{order:3}
  .hero-copy .hero-lede{order:4}
  .hero-copy .hero-cta{order:5}
  .hero-shot img{max-width:460px}
}
section{padding:110px 0}
#about{padding:24px 0 0}
/* programs photo -> "The gap": two full section paddings stacked to 220px. */
#programs{padding-bottom:56px}
#gap{padding-top:56px}
.eyebrow{color:var(--acc);font-weight:700;font-size:12px;text-transform:uppercase;letter-spacing:.2em;margin-bottom:20px}
h2{font-size:clamp(34px,5vw,64px);font-weight:900;text-transform:uppercase;line-height:.92;letter-spacing:-.035em;margin-bottom:26px}
.split{display:grid;grid-template-columns:1fr 1fr;gap:2px;margin-top:44px}
.half{background:var(--pnl);padding:44px 38px}
.half.b{background:var(--acc);color:#000}
.half h3{font-size:13px;text-transform:uppercase;letter-spacing:.18em;margin-bottom:26px;opacity:.6}
.half ul{list-style:none}
.half li{padding:14px 0;border-bottom:1px solid rgba(255,255,255,.08);font-size:17px}
.half.b li{border-color:rgba(0,0,0,.13);font-weight:700}
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:2px}
.stat{background:var(--pnl);padding:40px 26px}
.num{font-size:52px;font-weight:900;color:var(--acc);letter-spacing:-.04em}
.lbl{font-size:12px;text-transform:uppercase;letter-spacing:.14em;color:var(--mut);margin-top:8px}
/* Equal columns and one shared treatment: the three options are presented as
   peers, so nothing about the bootcamp card should out-shout the other two. */
.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:2px;margin-top:44px}
.card{background:linear-gradient(160deg,#1F1A0D,#0D0D0D);border:1px solid #2B2314;padding:40px 34px;display:flex;flex-direction:column}
.card h3{font-size:26px;font-weight:900;text-transform:uppercase;margin-bottom:14px}
.card p{color:var(--mut);font-size:15px;line-height:1.65;flex:1;margin-bottom:22px}
.card .tag{font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--acc);margin-bottom:18px}
.card .pill{align-self:flex-start}
/* photo bands. Every source shot is 4:5 portrait, so the single band is a
   centred column rather than a full-width strip — a 16:9 crop would cut both
   people out of the frame. Capped at the source's own width so it never
   upscales past its 702px original. */
.band{max-width:520px;margin:44px auto 0}
.band img{display:block;width:100%;height:auto;border-radius:6px}
.trio{display:grid;grid-template-columns:repeat(3,1fr);gap:2px;margin-top:2px}
.trio figure{margin:0}
.trio img{display:block;width:100%;height:auto;aspect-ratio:4/5;object-fit:cover}

.quote{max-width:940px;margin:0 auto;text-align:center;font-size:clamp(21px,3vw,36px);
  font-weight:900;line-height:1.22;letter-spacing:-.03em;text-wrap:balance}
.quote .qm{color:var(--acc)}
/* On a phone only two of the three shots fit side by side at a readable size,
   so the first is dropped and the pair sits clear of the amber panel above. */
@media(max-width:900px){
  .trio{grid-template-columns:1fr 1fr;margin-top:32px}
  .trio figure:first-child{display:none}
}

.apply{text-align:center;padding-bottom:110px}
.apply-lede{color:#D9D9D9;font-size:17px;line-height:1.7;max-width:640px;margin:0 auto}
/* The form page has no big heading, so its h1 carries the eyebrow's size. */
h1.eyebrow{font-size:12px;line-height:1.5;max-width:none}

/* application form */
.form{max-width:760px;margin:44px auto 0;text-align:left;display:grid;gap:18px}
.f2{display:grid;grid-template-columns:1fr 1fr;gap:18px}
.form label{display:block;font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--acc);font-weight:700}
.form label small{text-transform:none;letter-spacing:0;color:var(--mut);font-weight:400;font-size:11px}
.form input,.form select,.form textarea{display:block;width:100%;margin-top:8px;background:var(--pnl);
  border:1px solid #262626;border-radius:4px;color:var(--fg);font:inherit;font-size:16px;padding:14px 16px}
.form textarea{resize:vertical;min-height:120px}
.form select{appearance:none;-webkit-appearance:none;padding-right:44px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' fill='none' stroke='%23F5A524' stroke-width='2'%3E%3Cpath d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 16px center}
.form select:invalid{color:var(--mut)}
.form input::placeholder,.form textarea::placeholder{color:#4C4C4C}
.form :is(input,select,textarea):focus{outline:none;border-color:var(--acc);box-shadow:0 0 0 3px rgba(245,165,36,.22)}
/* Red only after the first submit attempt, never while the visitor is still typing. */
.form.was-validated :is(input,select,textarea):invalid{border-color:#E5484D}
.form .pill{justify-self:start;border:0;cursor:pointer;font-family:inherit}
.form .pill[disabled]{opacity:.6;cursor:default}
.form-msg{font-size:15px;line-height:1.6;color:#D9D9D9;min-height:1.6em;margin:0}
.form-msg.err{color:#FF8A8E}
.form-msg a{color:var(--acc)}
.form-done{max-width:560px;margin:44px auto 0;padding:40px 32px;background:var(--pnl);border:1px solid #2B2314}
.form-done h3{font-size:22px;font-weight:900;text-transform:uppercase;margin-bottom:12px}
.form-done p{color:#D9D9D9;line-height:1.7}
.hp{position:absolute;left:-9999px;width:0;height:0;opacity:0}
@media(max-width:900px){.apply{padding-bottom:66px}.f2{grid-template-columns:1fr}}
.ico{width:18px;height:18px;flex:none;display:block}
footer.site{border-top:1px solid #1A1A1A;padding:30px 0;color:#3A3A3A;font-size:13px;display:flex;justify-content:space-between}
footer.site a{color:var(--mut);text-decoration:none}
footer.site a:hover{color:var(--acc)}
.foot-links{display:inline-flex;align-items:center;gap:8px}
.foot-links a{display:inline-flex;align-items:center}
.foot-links .ico{width:17px;height:17px}
@media(max-width:900px){.split,.cards{grid-template-columns:1fr}.stats{grid-template-columns:1fr 1fr}section{padding:66px 0}#about{padding:16px 0 0}#programs{padding-bottom:36px}#gap{padding-top:36px}footer.site{flex-direction:column;gap:10px}}

/* --- motion -----------------------------------------------------------------
   Two layers. Entrances run off the existing IntersectionObserver (.reveal ->
   .reveal.in). Continuous scroll-linked effects use native CSS scroll timelines
   and add no JS. Every hiding rule is prefixed .js so a no-JS page is fully
   readable. ------------------------------------------------------------------------- */

/* layer 1 — entrances */
.js .reveal{opacity:0;transform:translateY(24px)}
.js .reveal.in{opacity:1;transform:none;
  transition:opacity .75s cubic-bezier(.22,.7,.3,1) var(--d,0s),transform .75s cubic-bezier(.22,.7,.3,1) var(--d,0s)}

/* Headings wipe in from the left. The clip goes on an inner <span>, never on the
   observed element itself: a clip-path of inset(0 100% 0 0) leaves zero visible
   area, which makes the element's intersection rect empty so IntersectionObserver
   never fires and the heading stays hidden forever. End inset is -2px, not 0, so
   the clip can never shave a glyph edge. */
.js .reveal.wipe>span{display:inline-block;clip-path:inset(0 100% 0 0);transform:translateY(10px)}
.js .reveal.wipe.in>span{clip-path:inset(0 -2px 0 0);transform:none;
  transition:transform .7s cubic-bezier(.22,.7,.3,1) var(--d,0s),
             clip-path .95s cubic-bezier(.22,.7,.3,1) var(--d,0s)}

/* stats — amber rule grows across the foot of each box */
.stat{position:relative;overflow:hidden}
.stat::after{content:"";position:absolute;left:26px;right:26px;bottom:0;height:2px;
  background:var(--acc);transform:scaleX(0);transform-origin:0 50%}
.js .stat.in::after{transform:scaleX(1);transition:transform .85s cubic-bezier(.22,.7,.3,1) calc(var(--d,0s) + .18s)}

/* programs — cards land rather than just fade */
.js .card.reveal{transform:translateY(28px) scale(.97)}

/* The gap. .split is the observed element (unclipped, so the observer fires);
   the amber panel's wipe and both lists' staggers hang off .split.in. Clipping
   .half.b directly would zero its intersection area and it would never reveal. */
.js .split .half li{opacity:0;transform:translateX(-10px)}
.js .split.in .half li{opacity:1;transform:none;
  transition:opacity .55s ease var(--li,0s),transform .55s cubic-bezier(.22,.7,.3,1) var(--li,0s)}
.js .split .half li:nth-child(1){--li:.10s}
.js .split .half li:nth-child(2){--li:.20s}
.js .split .half li:nth-child(3){--li:.30s}
.js .split .half li:nth-child(4){--li:.40s}
.js .split .half li:nth-child(5){--li:.50s}
.js .split .half.b li:nth-child(1){--li:.55s}
.js .split .half.b li:nth-child(2){--li:.65s}
.js .split .half.b li:nth-child(3){--li:.75s}
.js .split .half.b li:nth-child(4){--li:.85s}
.js .split .half.b li:nth-child(5){--li:.95s}
.js .split .half.b{clip-path:inset(0 100% 0 0)}
.js .split.in .half.b{clip-path:inset(0 0 0 0);transition:clip-path 1s cubic-bezier(.22,.7,.3,1) .1s}

/* hero load-in */
.hero h1,.hero .sub,.hero .hero-lede,.hero .pill,.hero .hero-shot{animation:rise .9s cubic-bezier(.22,.7,.3,1) both}
.hero .sub{animation-delay:.1s}
.hero .hero-lede{animation-delay:.2s}
.hero .pill{animation-delay:.3s}
.hero .hero-shot{animation-delay:.25s}
@keyframes rise{from{opacity:0;transform:translateY(26px)}to{opacity:1;transform:none}}

/* scroll progress bar. Base state is scaleX(0), so where scroll timelines are
   unsupported it stays invisible rather than sitting stuck at full width. */
.progress{position:fixed;top:0;left:0;z-index:60;height:2px;width:100%;
  background:var(--acc);transform:scaleX(0);transform-origin:0 50%}
@keyframes prog{from{transform:scaleX(0)}to{transform:scaleX(1)}}

/* layer 2 — continuous, scroll-linked. `drift` declares only a `to` keyframe so
   its implicit `from` is whatever `rise` settled on; being later in the
   animation list it wins on transform/opacity while it has an effect. Each
   element drifts a different distance (--dy) to read as depth. */
@keyframes drift{to{transform:translateY(var(--dy,-40px));opacity:0}}
@supports (animation-timeline:view()){
  /* Longhands rather than the `animation` shorthand: the shorthand resets
     animation-timeline, and spelling the list out keeps the per-animation
     timeline/range pairing unambiguous. */
  .progress{animation-name:prog;animation-duration:auto;animation-timing-function:linear;
    animation-fill-mode:both;animation-timeline:scroll(root block)}
  .hero h1,.hero .sub,.hero .hero-lede,.hero .hero-shot{
    animation-name:rise,drift;
    animation-duration:.9s,auto;
    animation-timing-function:cubic-bezier(.22,.7,.3,1),linear;
    animation-fill-mode:both,both;
    animation-timeline:auto,view();
    animation-range:normal,exit 0% exit 100%}
  .hero .sub{animation-delay:.1s,0s}
  .hero .hero-lede{animation-delay:.2s,0s}
  .hero .hero-shot{animation-delay:.25s,0s}
  .hero .hero-cta{animation-name:drift;animation-duration:auto;
    animation-timing-function:linear;animation-fill-mode:both;
    animation-timeline:view();animation-range:exit 0% exit 100%}
  .hero h1{--dy:-34px}
  .hero .sub{--dy:-52px}
  .hero .hero-lede{--dy:-70px}
  .hero .hero-cta{--dy:-88px}
  .hero .hero-shot{--dy:-18px}
}

/* Reduced motion: reset every property the rules above touch, so the page
   renders complete and static. `animation:none` also disables the scroll
   timelines. */
@media(prefers-reduced-motion:reduce){
  .js .reveal,.js .reveal.in{opacity:1;transform:none;transition:none}
  .js .reveal.wipe>span,.js .reveal.wipe.in>span,
  .js .split .half.b,.js .split.in .half.b{transform:none;transition:none;clip-path:none}
  .js .split .half li,.js .split.in .half li{opacity:1;transform:none;transition:none}
  .stat::after,.js .stat.in::after{transform:scaleX(1);transition:none}
  .hero h1,.hero .sub,.hero .hero-lede,.hero .pill,.hero .hero-cta,.hero .hero-shot{animation:none}
  .progress{display:none}
}
