/* Motion complements the original typography, spacing and local artwork. */
:root{--motion-ease:cubic-bezier(.16,1,.3,1)}
html.lenis,html.lenis body{height:auto}
html.lenis.lenis-smooth{scroll-behavior:auto!important}
html:has(dialog[open]){overflow:hidden}
dialog{overscroll-behavior:contain}
/* The hover tint must follow the circular icon, not the square hit area. */
.round{border-radius:50%}
.button,.round,.play,.social-icons a,.dialog-close{transition:background-color .22s ease,color .22s ease,transform .3s var(--motion-ease),box-shadow .3s var(--motion-ease)}
.button .arrow,.all-news img,.discover img{transition:transform .3s var(--motion-ease)}
.nav-dropdown summary img{transition:transform .25s var(--motion-ease)}
.nav-dropdown[open] summary img{transform:rotate(45deg)}
.contact-form input,.contact-form textarea{transition:border-color .2s ease,box-shadow .2s ease,background-color .2s ease}
/* Shared white contact forms use an underline focus indicator, clear of their labels. */
.contact-form input:focus,.contact-form textarea:focus{outline:none;outline-offset:0;border-bottom-color:var(--magenta);box-shadow:0 2px 0 var(--magenta);background-color:rgb(27 11 86 / .025)}
.site-header nav a,.footer-nav a,.footer-legal>a,.past-sidebar a{transition:color .2s ease}
.news-card>a:first-child,.story-image,.overview-image{overflow:hidden}
.news-card>a img{transition:transform .55s var(--motion-ease)}
.finalist summary,.past-sidebar summary{transition:color .2s ease}
/* Statistic numbers: natural (proportional) digit widths and no extra tracking, so "19" sits tight. */
.stat-card>p,.impact-card>p,.impact-metric p{font-variant-numeric:proportional-nums;font-feature-settings:"pnum" 1,"tnum" 0;letter-spacing:0}
@media(hover:hover) and (pointer:fine) and (prefers-reduced-motion:no-preference){
 .button:hover .lucide{transform:translateX(4px)}
 .round:hover{transform:translateY(-3px);background-color:#ffffff16}
 .social-icons a:hover,.dialog-close:hover{transform:translateY(-3px)}
 .news-card>a:hover img{transform:scale(1.035)}
 .all-news:hover .lucide,.discover:hover .lucide{transform:translateX(5px)}
 .finalist summary:hover,.past-sidebar summary:hover{color:var(--lime)}
}
@media(prefers-reduced-motion:no-preference){
 .button:active,.round:active,.social-icons a:active{transform:scale(.97)}
 .play:hover{transform:translate(-50%,-50%) scale(1.04)}
 .play:active{transform:translate(-50%,-50%) scale(.97)}
 @keyframes backdrop-in{from{opacity:0}to{opacity:1}}
}
@media(prefers-reduced-motion:reduce){
 html{scroll-behavior:auto!important}
 *,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}
 .button:hover,.round:hover,.social-icons a:hover{transform:none}
}

/* Banner motion: one coordinated, CSS-only sequence (it starts before deferred scripts).
   1. The photo fades up from a soft zoom and settles; on scroll it drifts slower than the page.
   2. Overline tightens into place, then each headline line rises from behind a mask, then its
      magenta underline arrives. Supporting copy follows.
   3. The chevron outline sweeps in left to right (the brand arrow direction) and moves faster
      than the copy on scroll for depth. The copy eases up and dims as the banner leaves.
   Individual transform properties (scale/translate) let entrance and scroll motion stack.
   `backwards` fill releases everything afterwards, so hover states keep working. */
:is(.hero-background,.about-hero-background,.energy-hero-background){overflow:hidden}
@media(prefers-reduced-motion:no-preference){
 /* 1. Photo */
 :is(.hero-background,.about-hero-background,.energy-hero-background){animation:hero-fade 1.4s ease backwards}
 :is(.hero-background,.about-hero-background,.energy-hero-background) img{scale:1.1;animation:hero-settle 2.6s var(--motion-ease) backwards}
 .hero-pattern{animation:chevron-sweep 1.8s var(--motion-ease) .5s backwards}

 /* 2. Type */
 :is(.home-hero,.about-hero,.energy-hero,.contact-hero) h1>span{display:inline-block}
 :is(.home-hero .hero-copy,.about-hero-copy,.energy-hero-copy,.contact-hero>div)>:not(h1){animation:hero-rise 1.2s var(--motion-ease) backwards}
 :is(.about-hero-copy,.energy-hero-copy,.contact-hero>div)>.eyebrow{animation:overline-in 1.4s var(--motion-ease) .1s backwards}
 :is(.home-hero,.about-hero,.energy-hero,.contact-hero) h1>span:nth-of-type(1){animation:line-rise 1.1s var(--motion-ease) .22s backwards,underline-in .7s ease .95s backwards}
 :is(.home-hero,.about-hero,.energy-hero,.contact-hero) h1>span:nth-of-type(2){animation:line-rise 1.1s var(--motion-ease) .36s backwards,underline-in .7s ease 1.1s backwards}
 :is(.home-hero .hero-copy,.about-hero-copy,.energy-hero-copy,.contact-hero>div)>h1~*{animation-delay:.62s}
 :is(.home-hero .hero-copy,.about-hero-copy,.energy-hero-copy,.contact-hero>div)>h1~*~*{animation-delay:.74s}
 :is(.home-hero .hero-copy,.about-hero-copy,.energy-hero-copy,.contact-hero>div)>h1~*~*~*{animation-delay:.86s}
 .register-card{animation:card-in 1.2s var(--motion-ease) .9s backwards}

 /* 3. Chevron */
 :is(.about-chevron,.energy-chevron,.media-chevron,.contact-emblem){animation:chevron-sweep 1.6s var(--motion-ease) .55s backwards}

 @keyframes hero-fade{from{opacity:0}}
 @keyframes hero-settle{from{scale:1.2}}
 @keyframes hero-rise{from{opacity:0;transform:translateY(18px)}}
 @keyframes overline-in{from{opacity:0;letter-spacing:.75rem}}
 /* Mask reveal: the clip's bottom edge moves with the translation, so the line appears to rise
    from behind a fixed baseline. Negative insets leave room for the underline and descenders. */
 @keyframes line-rise{from{transform:translateY(105%);clip-path:inset(-.25em -.25em 105% -.25em)}to{transform:none;clip-path:inset(-.25em)}}
 @keyframes underline-in{from{text-decoration-color:transparent}}
 @keyframes chevron-sweep{from{opacity:0;transform:translateX(-2.5rem);clip-path:inset(0 100% 0 0)}to{clip-path:inset(0 -1% 0 0)}}
 @keyframes card-in{from{opacity:0;transform:translateX(24px);box-shadow:0 0 0 var(--lime)}}

 /* Scroll depth (browsers with scroll-driven animations; others keep the static banner). */
 @supports(animation-timeline:view()){
  :is(.hero-background,.about-hero-background,.energy-hero-background)>img{
   animation:hero-settle 2.6s var(--motion-ease) backwards,hero-drift linear both;
   animation-timeline:auto,scroll(root);animation-range:normal,0 100vh}
  /* 10% scale overscan covers the 4% drift, so no edge ever shows. */
  @keyframes hero-drift{to{translate:0 4%}}
  :is(.about-chevron,.energy-chevron,.media-chevron,.contact-emblem,.hero-pattern){
   animation:chevron-sweep 1.6s var(--motion-ease) .55s backwards,chevron-lift linear both;
   animation-timeline:auto,scroll(root);animation-range:normal,0 100vh}
  @keyframes chevron-lift{to{translate:0 -4.5rem}}
  :is(.home-hero .hero-copy,.about-hero-copy,.energy-hero-copy,.contact-hero>div){
   animation:copy-out linear both;animation-timeline:view();animation-range:exit 5% exit 95%}
  @keyframes copy-out{to{translate:0 -2.5rem;opacity:.2}}
 }
}

/* Section reveals (motion.js): only content below the fold starts pending; motion.js supplies the
   entrance (text first, then media), so the pending state only needs to hide. */
.reveal-pending{opacity:0}
.stat-line img,.impact-card:after{transform-origin:left;transition:transform .8s var(--motion-ease) calc(var(--reveal-delay,0ms) + .3s)}
.reveal-pending .stat-line img,.impact-card.reveal-pending:after{transform:scaleX(0)}
@media(prefers-reduced-motion:reduce){.reveal-pending{opacity:1!important;transform:none!important}}
@media print{.reveal-pending{opacity:1!important;transform:none!important}}

/* Page-to-page: cross-document view transitions (Chrome/Edge 126+, Safari 18.2+).
   Other browsers simply navigate as before. The header holds still while content swaps. */
@media(prefers-reduced-motion:no-preference){
 @view-transition{navigation:auto}
 .site-header{view-transition-name:site-header}
 ::view-transition-group(site-header){animation-duration:0s}
 ::view-transition-old(root){animation:page-out .28s cubic-bezier(.4,0,.6,1) both}
 ::view-transition-new(root){animation:page-in .7s var(--motion-ease) .06s both}
 @keyframes page-out{to{opacity:0;transform:translateY(-6px)}}
 @keyframes page-in{from{opacity:0;transform:translateY(10px)}}
}

/* Loader: brand chevron on first visit or reload only (html.is-loading is set by an inline head
   script before first paint). Drawn on html pseudo-elements so it exists before <body> parses.
   A CSS failsafe clears it after 5s even if scripts never run. */
html.is-loading::before{content:'';position:fixed;inset:0;z-index:1000;background:var(--purple);
 animation:loader-failsafe .3s 5s forwards}
html.is-loading::after{content:'';position:fixed;z-index:1001;left:50%;top:50%;width:3.5rem;height:4.75rem;margin:-2.375rem 0 0 -1.75rem;
 background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 49 67'%3E%3Cpath fill='%23c8ff24' d='M16.5 2 48 33.5 16.5 65 1 49.5 17 33.5 1 17.5z'/%3E%3C/svg%3E") center/contain no-repeat;
 animation:loader-in .6s var(--motion-ease) both,loader-nudge .9s ease-in-out .6s infinite,loader-failsafe .3s 5s forwards}
/* Exit: the wipe gathers up to the arrow while it winds back, then the arrow shoots left to right
   with the opening edge glued behind it (both share keyframe stops and easing from 40%). */
html.is-loading.is-leaving::after{animation:loader-sweep 1.1s linear forwards}
html.is-loading.is-leaving::before{animation:loader-open 1.1s linear forwards}
/* Hold page entrance animations until the loader starts leaving, so they play in view. */
html.is-loading:not(.is-leaving) body *{animation-play-state:paused!important}
@keyframes loader-in{from{opacity:0;transform:translateX(-18px)}}
@keyframes loader-nudge{50%{transform:translateX(8px)}}
@keyframes loader-sweep{0%{transform:none;animation-timing-function:cubic-bezier(.4,0,.2,1)}40%{transform:translateX(-10px);animation-timing-function:cubic-bezier(.7,0,.3,1)}100%{transform:translateX(calc(50vw + 4rem))}}
@keyframes loader-open{0%{clip-path:inset(0 0 0 0);animation-timing-function:cubic-bezier(.4,0,.2,1)}40%{clip-path:inset(0 0 0 calc(50% - 1.75rem - 10px));animation-timing-function:cubic-bezier(.7,0,.3,1)}100%{clip-path:inset(0 0 0 calc(100% + 2.25rem))}}
@keyframes loader-failsafe{to{opacity:0;visibility:hidden}}
@media print{html.is-loading::before,html.is-loading::after{display:none}}

/* CTA hover: the existing hover magenta fills in left to right (echoing the loader sweep) and exits
   to the right rather than rewinding; the arrow leads and the button lifts. Colours are unchanged. */
.button{background-image:linear-gradient(#c22f8b,#c22f8b);background-repeat:no-repeat;background-position:right center;background-size:0% 100%;
 transition:background-size .65s var(--motion-ease),transform .55s var(--motion-ease),color .3s ease}
.button :is(.arrow,.lucide){transition:transform .6s var(--motion-ease)}
@media(hover:hover) and (pointer:fine){
 .button:hover{background-color:var(--magenta);background-image:linear-gradient(#c22f8b,#c22f8b);background-position:left center;background-size:100% 100%;transform:translateY(-2px)}
 .button:hover :is(.arrow,.lucide){transform:translateX(6px)}
 .button:hover:active{transform:translateY(-1px) scale(.98);transition-duration:.55s,.12s,.22s}
}

/* Navigation dropdowns: frosted panel aligned to the label text, lime accent that draws in,
   panel unfolds downward and links follow in sequence. Closing plays .is-closing (motion.js)
   before the native <details> closes, so it never just vanishes. */
:root{interpolate-size:allow-keywords}
@media(min-width:1001px){
 .nav-dropdown>div{left:-1.25rem;padding:.5rem;min-width:17rem;background:rgb(27 11 86 / .94);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);border:1px solid #ffffff14;border-top:0;
  box-shadow:0 1.5rem 3rem -1rem rgb(8 3 36 / .7)}
 /* Same 1px weight and row as the nav's current-page/hover rule (it sits just above the header border). */
 .nav-dropdown>div::before{content:'';position:absolute;inset:-1px 0 auto;height:1px;background:var(--lime);transform-origin:left}
 .nav-dropdown>div a{position:relative;padding:.75rem;font-weight:500;transition:color .3s ease,background-color .3s ease,padding-left .45s var(--motion-ease)}
 .nav-dropdown>div a::before{content:'';position:absolute;left:.85rem;top:50%;width:.4rem;height:.4rem;border:solid var(--lime);border-width:2px 2px 0 0;
  transform:translate(-.5rem,-50%) rotate(45deg);opacity:0;transition:transform .45s var(--motion-ease),opacity .3s ease}
 .nav-dropdown>div a:is(:hover,:focus-visible),.nav-dropdown>div a[aria-current=page]{color:var(--lime);background:#ffffff0a;padding-left:1.85rem}
 .nav-dropdown>div a:is(:hover,:focus-visible)::before,.nav-dropdown>div a[aria-current=page]::before{opacity:1;transform:translate(0,-50%) rotate(45deg)}
 .nav-dropdown>div a[aria-current=page]:after{display:none}
 /* Top-level links: lime rule grows from the left on hover, matching the current-page rule.
    Dropdown labels get no rule: the panel's lime accent is their single indicator, so the two
    never stack at the header edge. */
 .site-header nav>a:not([aria-current])::after{content:'';position:absolute;left:0;right:0;bottom:0;height:1px;background:var(--lime);
  transform:scaleX(0);transform-origin:right;transition:transform .5s var(--motion-ease)}
 .site-header nav>a:not([aria-current]):hover::after{transform:scaleX(1);transform-origin:left}
 .nav-dropdown summary img{transition:transform .5s var(--motion-ease)}
}
@media(prefers-reduced-motion:no-preference){
 @media(min-width:1001px){
  .nav-dropdown[open]>div{animation:panel-unfold .5s var(--motion-ease) both}
  .nav-dropdown[open]>div::before{animation:accent-draw .6s var(--motion-ease) .08s both}
  .nav-dropdown[open]>div>:is(a,button){animation:item-in .5s var(--motion-ease) both}
  .nav-dropdown[open]>div>:nth-child(1){animation-delay:.08s}
  .nav-dropdown[open]>div>:nth-child(2){animation-delay:.13s}
  .nav-dropdown[open]>div>:nth-child(3){animation-delay:.18s}
  .nav-dropdown[open]>div>:nth-child(n+4){animation-delay:.23s}
  .nav-dropdown.is-closing>div{animation:panel-fold .2s cubic-bezier(.4,0,1,1) both}
 }
 @media(max-width:1000px){
  /* Mobile menu: accordion grows to its natural height (where interpolate-size is supported;
     elsewhere it simply fades). */
  .nav-dropdown[open]>div{overflow:hidden;animation:accordion-open .45s var(--motion-ease) both}
  .nav-dropdown.is-closing>div{overflow:hidden;animation:accordion-close .3s cubic-bezier(.4,0,.2,1) both}
 }
 @keyframes panel-unfold{from{opacity:0;transform:translateY(-.5rem);clip-path:inset(0 0 100% 0)}to{opacity:1;transform:none;clip-path:inset(-2px -2rem -3rem -2rem)}}
 @keyframes panel-fold{to{opacity:0;transform:translateY(-.375rem);clip-path:inset(0 0 100% 0)}}
 @keyframes accent-draw{from{transform:scaleX(0)}}
 @keyframes item-in{from{opacity:0;transform:translateX(-.5rem)}}
 @keyframes accordion-open{from{height:0;opacity:0;margin-block:0}}
 @keyframes accordion-close{to{height:0;opacity:0;margin-block:0}}
}

/* Media Center tabs and switches (motion.js adds the indicators, so without JS the original
   static styles apply). One lime rule slides between tabs; a lime block slides between switch
   options; bold tab labels reserve their width so the row never shifts. */
.media-tabs{position:relative}
.media-tabs button{display:inline-grid;justify-items:center;transition:color .35s ease}
.media-tabs button::after{content:attr(data-text);font-weight:700;height:0;visibility:hidden;overflow:hidden;pointer-events:none}
.tab-indicator{position:absolute;left:0;top:0;height:1px;background:var(--lime);pointer-events:none;
 width:var(--w,0);transform:translate(var(--x,0),var(--y,0));transition:transform .6s var(--motion-ease),width .6s var(--motion-ease)}
.has-slider{position:relative;isolation:isolate}
.has-slider button{position:relative;z-index:1;transition:color .4s ease,border-color .4s ease}
.has-slider button[aria-pressed=true]{background:transparent}
.slider-block{position:absolute;left:0;top:0;z-index:0;background:var(--lime);pointer-events:none;
 width:var(--w,0);height:var(--h,0);transform:translate(var(--x,0),var(--y,0));
 transition:transform .55s var(--motion-ease),width .55s var(--motion-ease),height .55s var(--motion-ease)}
.media-shell img{transition:opacity .7s ease}
.media-shell img.is-loading{opacity:0}
@media(prefers-reduced-motion:reduce){.tab-indicator,.slider-block{transition:none}}

/* Search panel: results and field get the same tactile treatment as the nav dropdowns, adapted
   for the white dialog (magenta replaces lime, which is unreadable on white). */
.dialog-search{transition:border-color .3s ease,box-shadow .35s var(--motion-ease)}
.dialog-search:focus{border-color:var(--purple);box-shadow:0 2px 0 var(--magenta)}
.dialog-search:focus-visible{outline:2px solid var(--purple);outline-offset:3px}
.search-results a{position:relative;transition:color .3s ease,padding-left .45s var(--motion-ease)}
.search-results a::before{content:'';position:absolute;left:.15rem;top:50%;width:.4rem;height:.4rem;border:solid var(--magenta);border-width:2px 2px 0 0;
 transform:translate(-.4rem,-50%) rotate(45deg);opacity:0;transition:transform .45s var(--motion-ease),opacity .3s ease}
.search-results a::after{content:'';position:absolute;left:0;right:0;bottom:-1px;height:1px;background:var(--magenta);
 transform:scaleX(0);transform-origin:right;transition:transform .5s var(--motion-ease)}
.search-results a:is(:hover,:focus-visible),.search-results a[aria-current=page]{color:var(--magenta);padding-left:1.1rem;text-decoration:none}
.search-results a:is(:hover,:focus-visible)::before,.search-results a[aria-current=page]::before{opacity:1;transform:translate(0,-50%) rotate(45deg)}
.search-results a:is(:hover,:focus-visible)::after{transform:scaleX(1);transform-origin:left}
/* The site-wide lime focus ring disappears on the white site dialog; use purple there.
   (The video and profile dialogs are dark purple, so they keep the lime ring.) */
#site-dialog :is(a,button,input,textarea,summary):focus-visible{outline-color:var(--purple)}

/* Mobile menu exit: keep the panel rendered (but inert to taps) while motion.js rolls it up. */
.site-header nav.is-closing{display:flex;pointer-events:none}
/* Menu icon: the incoming glyph (☰ or ×) rotates and scales in as they swap. Gated on the first
   toggle so nothing animates on page load. */
@media(prefers-reduced-motion:no-preference){
 .menu-toggle.has-toggled .menu-symbol .ui-icon{animation:icon-swap .45s var(--motion-ease)}
 @keyframes icon-swap{from{opacity:0;transform:rotate(-90deg) scale(.6)}}
}

/* Floating "Stay updated" (homepage): a small icon tab fixed to the right edge once the hero card
   has scrolled away; it slides the same white card (lime offset shadow) out to its left. */
.float-card{position:fixed;right:0;top:50%;z-index:20;display:flex;align-items:center;gap:14px;
 transform:translate(calc(100% + 8px),-50%);opacity:0;visibility:hidden;pointer-events:none;
 transition:transform .55s var(--motion-ease),opacity .35s ease,visibility 0s linear .55s}
.float-card.is-visible{transform:translate(0,-50%);opacity:1;visibility:visible;pointer-events:auto;
 transition:transform .55s var(--motion-ease),opacity .35s ease,visibility 0s}
.float-card-toggle{display:grid;place-items:center;width:52px;height:56px;background:var(--magenta);
 box-shadow:-4px 4px 0 var(--lime);transition:background-color .3s ease,width .45s var(--motion-ease)}
/* The brand arrow (as on every button): points left to pull the box out, turns right to push it back. */
.float-card-arrow{width:16px;height:22px;transform:rotate(180deg);transition:transform .5s var(--motion-ease)}
.float-card.is-open .float-card-arrow{transform:none}
.float-card-toggle:hover,.float-card.is-open .float-card-toggle{background:#c22f8b}
.float-card-panel{position:relative;width:min(20rem,calc(100vw - 92px));background:#fff;color:var(--purple);padding:1.25rem;
 box-shadow:-.9375rem .9375rem 0 var(--lime);opacity:0;visibility:hidden;transform:translateX(24px);
 transition:opacity .3s ease,transform .5s var(--motion-ease),visibility 0s linear .5s}
.float-card.is-open .float-card-panel{opacity:1;visibility:visible;transform:none;transition:opacity .3s ease,transform .5s var(--motion-ease),visibility 0s}
.float-card-panel>p:first-of-type{text-transform:uppercase;font-size:.75rem;font-weight:500;padding-right:2rem}
.float-card-panel h2{font-size:clamp(20px,1.6vw,28px);margin:.5rem 0;color:var(--purple)}
.float-card-panel>p:nth-of-type(2){font-size:.875rem;color:#1b0b56b3;font-weight:500}
.float-card-panel .button{margin-top:1rem;width:100%;color:#fff}
.float-card-close{position:absolute;top:.5rem;right:.5rem;width:36px;height:36px;display:grid;place-items:center}
.float-card-close img{width:18px;height:18px}
.float-card-close:focus-visible,.float-card-panel .button:focus-visible{outline-color:var(--purple)}
html.menu-open .float-card,html:has(dialog[open]) .float-card{opacity:0;visibility:hidden}
@media(prefers-reduced-motion:reduce){.float-card,.float-card.is-visible,.float-card-panel,.float-card.is-open .float-card-panel{transition:none}}
@media print{.float-card{display:none}}
