/* Shared shell for subpages (about, evals, companies).
   index.html keeps its own bespoke stylesheet.
   Page-specific overrides (widths, kicker color, h1 scale) live in each page's <style>. */
/* Gardiant: the logo face, self-hosted. One Regular weight only, so every rule
   using it must state font-weight:400 or the browser synthesises a fake bold. */
@font-face{font-family:"Gardiant";src:url("/assets/fonts/gardiant.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap}
:root{
  --void:#000000;
  --ink:#0a0d1c;
  --porcelain:#f6f7fa;
  --porcelain-dim:#a6acbd;
  --porcelain-rgb:246,247,250;
  --void-rgb:0,0,0;
  --ink-rgb:10,13,28;
  /* The ramp, read off the reference: deep navy through royal blue into warm
     orange and gold, the blue/amber pair the image is built on. Surfaces,
     display type and the shader shapes only. Text uses the single accent, which
     is what keeps a four-stop gradient from becoming four competing colours. */
  --g1:#141a4d;
  --g2:#2447c9;
  --g3:#e8842a;
  --g4:#f7b955;
  --g-warm:#ffd9a0;
  --accent:#6f9dff;
  --accent-rgb:111,157,255;
  /* Gold at the bottom-left running to blue at the top-right. Rims only. */
  --accent-grad:linear-gradient(to top right,#f7b955 0%,#e8842a 30%,#5b7ff0 68%,#2447c9 100%);
  /* Two more cuts of the same ramp, because one cannot serve every job:
     -fill sits under a light label, so the vivid ramp drops to .42 alpha over
      the ground (white on vivid gold is 1.75:1, unreadable);
     -text swaps the dark blue end for a light one, since #2447c9 on black is
      2.82:1 and an eyebrow is 10px. */
  --accent-grad-fill:linear-gradient(to top right,rgba(247,185,85,.42) 0%,rgba(232,132,42,.42) 30%,rgba(91,127,240,.42) 68%,rgba(36,71,201,.42) 100%);
  --accent-grad-text:linear-gradient(to top right,#fbd08a 0%,#f7c27e 30%,#e8ded9 52%,#bcd2ff 74%,#b4ceff 100%);
  /* semantic only, held at lower chroma so they never read as brand */
  --ok:#7be9cd;
  --warn:#ff9685;
  /* Shape scale. Three container steps, a focus radius, the pill and a
     circle, so the site stops shipping eleven radii with no rule.
     --r-chrome covers inputs, thumbnails and small controls; --r-card covers
     cards, grid cells, the calendar and dropdown menus; --r-panel covers
     large panes, dialogs and hero panels; --r-pill is every button; 50%
     stays for true circles. Anything outside these needs a reason in a
     comment. tests/design-system.test.mjs fails on a bare pixel radius. */
  /* Type scale. Four roles, so a heading never has to guess which face it is.
     --font-title is the wordmark face and belongs to the brand voice: the
     logotype and the h1 it anchors, nothing smaller.
     --font-display is the width-axis face, for the uppercase structural
     headings and the oversized numerals that lean on font-stretch.
     --font-body is every sentence-case heading, all running copy and all UI.
     --font-mono is labels, counters and anything that reads as data.
     A raw family name anywhere else is drift; tests/design-system.test.mjs
     fails on one. */
  --font-title:"Gardiant",sans-serif;
  --font-display:"Archivo",sans-serif;
  --font-body:"Sora",system-ui,sans-serif;
  --font-mono:"JetBrains Mono",monospace;
  --r-focus:4px;
  --r-chrome:14px;
  --r-card:22px;
  --r-panel:28px;
  --r-pill:100px;
  /* The pane material: one glass surface for every container, so cards,
     dialogs and menus read as the same family as the pill buttons and the
     orb imagery. A gradient wash over ink, a hairline rim and a lit top edge.
     .glass composes these with backdrop blur; a cell that cannot afford the
     blur uses the tokens directly. */
  --pane-bg:linear-gradient(135deg,rgba(var(--porcelain-rgb),.07),rgba(var(--porcelain-rgb),.02) 46%),rgba(var(--ink-rgb),.55);
  --pane-line:rgba(var(--porcelain-rgb),.11);
  --pane-line-hover:rgba(var(--porcelain-rgb),.24);
  --pane-edge:inset 0 1px 0 rgba(var(--porcelain-rgb),.16),inset 0 -1px 0 rgba(var(--porcelain-rgb),.05);
  /* Inputs: a darker well than the pane so a field reads as a recess in it,
     and a soft accent halo on focus. */
  --field-bg:rgba(var(--void-rgb),.55);
  --field-ring:0 0 0 4px rgba(var(--accent-rgb),.18);
  --line:rgba(var(--porcelain-rgb),.1);
  /* Control boundaries, not hairlines. WCAG 1.4.11 wants 3:1 for the edge of
     an input; --line is .1 alpha and lands at 1.2:1. .38 clears it. */
  --field-line:rgba(var(--porcelain-rgb),.38);
  /* dark native scrollbars, form controls and select popups */
  color-scheme:dark;
}
*{margin:0;padding:0;box-sizing:border-box}
/* [hidden] is (0,1,0) and loses to any `.class element` rule, so a bare
   el.hidden=true silently does nothing. It cost us the join form staying
   on screen, JOIN FREE and all, after a successful join. */
[hidden]{display:none!important}
::selection{background:var(--accent);color:var(--void)}
:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:var(--r-focus)}
/* Keyboard bypass for the repeated nav. Matches index.html, which carries its
   own copy. Translated rather than offset so the reveal is compositor-only. */
.skip{position:fixed;top:12px;left:16px;z-index:300;background:var(--porcelain);color:var(--void);
  padding:10px 18px;border-radius:var(--r-chrome);font-size:13px;text-decoration:none;
  transform:translateY(-200%);transition:transform .2s}
.skip:focus{transform:translateY(0)}
/* Off-screen for the eye, present for assistive tech. Use this, not
   display:none or visibility:hidden, whenever text is dropped for space rather
   than because it stopped applying: both of those take the text out of the
   accessible name as well, which is how a link ends up announcing "Back" when
   it goes to the homepage. clip-path over the old clip:rect, plus the 1px box,
   so the text cannot be read but is still laid out and still announced.
   assets/page-shell.css restates these properties for .bk-x, because CSS
   cannot add a class at one breakpoint and remove it at another. */
.sr-only{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0;padding:0}
/* ---------- edge bloom ---------- */
/* Matches index.html. The ground is pitch black through the middle, where the
   type lives; colour blooms in from the corners only. Fixed and behind
   everything, with pointer-events:none and a negative z-index so it stays out
   of every interaction and stacking decision. */
body::before{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:radial-gradient(ellipse 46% 36% at 0% 6%,rgba(36,71,201,.30),transparent 68%),
    radial-gradient(ellipse 42% 34% at 100% 24%,rgba(111,157,255,.16),transparent 70%),
    radial-gradient(ellipse 52% 34% at 8% 100%,rgba(232,132,42,.16),transparent 72%),
    radial-gradient(ellipse 48% 38% at 96% 94%,rgba(20,26,77,.40),transparent 72%)}
body{background:var(--void);color:var(--porcelain);font-family:var(--font-body);font-weight:300;line-height:1.6;-webkit-font-smoothing:antialiased;-webkit-tap-highlight-color:transparent}
a,button,summary,[role="button"]{touch-action:manipulation}
/* Small uppercase links are ~20px tall. Grow the touch target, not the type. */
@media(pointer:coarse){
  .back,.about-links a,.offer-cta,.foot-contact,footer a{position:relative}
  .back::after,.about-links a::after,.offer-cta::after,.foot-contact::after,footer a::after{
    content:"";position:absolute;left:0;right:0;top:50%;height:44px;transform:translateY(-50%);
  }
}
/* Titles are white; the accent lives on kickers and links, not headlines. */
/* One face across the whole title, emphasised line included. Gardiant has no
   width axis, so the stretch and tracking Archivo needed go with it. */
/* em inherits the title's own face: forcing the logo face here put Gardiant
   inside the mono page titles and split one heading across two fonts. */
h1 em{font-style:normal;color:var(--porcelain)}
/* Display type must not inherit the 1.6 body leading, and headings should not
   strand a single word on the last line. */
h1,h2,h3,h4{text-wrap:balance}
h2,h3,h4{line-height:1.1;letter-spacing:-.02em}
p,.lead{text-wrap:pretty}
/* The reading lead under a page title. Four pages each declared their own
   copy of this and the homepage declared none, so the same component ran
   at 17px on subpages and 16px on the homepage. Pages set width, not type. */
.lead{color:var(--porcelain-dim);font-size:17px}
select option{background:var(--ink);color:var(--porcelain)}
/* The dialog shell's material: the one pane that floats over the page, so
   the one pane that casts a shadow. Frosted heavier than a card. Each page
   still sets its own width, radius and padding on dialog.modal. */
dialog.modal{overscroll-behavior:contain;color:var(--porcelain);border:1px solid rgba(var(--porcelain-rgb),.16);
  border-radius:var(--r-panel);
  background:linear-gradient(135deg,rgba(var(--porcelain-rgb),.08),rgba(var(--porcelain-rgb),.02) 46%),rgba(var(--ink-rgb),.72);
  backdrop-filter:blur(28px) saturate(160%);-webkit-backdrop-filter:blur(28px) saturate(160%);
  box-shadow:var(--pane-edge),0 60px 140px rgba(var(--void-rgb),.7)}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  dialog.modal{background:rgba(var(--ink-rgb),.97)}
}
@media (prefers-reduced-transparency:reduce){
  dialog.modal{background:rgba(var(--ink-rgb),.97);backdrop-filter:none;-webkit-backdrop-filter:none}
}
/* Lock the page while a dialog or the mobile menu is up. The lock lives on
   <html>, not <body>: <html> already sets overflow-x:clip on the homepage, so a
   body overflow rule would never reach the viewport. overscroll-behavior on the
   dialog and .mnav only contains scrolls that start on them; the backdrop and
   the fixed nav bar (a layer above .mnav) still scrolled the document. */
html:has(dialog[open]),html:has(.mnav.open){overflow:hidden}

/* ---------- pane ----------
   .glass keeps its name but is a plain pane now (2026-08-18): the frosted
   blur and the lit top edge came off every block, as they did on the sponsor
   page. A translucent fill, a hairline border and the inset edge light.
   Reduced-transparency falls back to an opaque surface. */
.glass{
  position:relative;
  border-radius:var(--r-card);
  background:var(--pane-bg);
  border:1px solid var(--pane-line);
  box-shadow:var(--pane-edge);
  transition:transform .35s cubic-bezier(.16,1,.3,1),border-color .35s;
}
/* A grid of panes: each cell is its own capsule, no shared 1px walls. The
   pages set columns; this sets the gutter and clears the old hairline frame.
   Cards in a grid lift a touch under the pointer. */
.pane-grid{display:grid;gap:16px;background:none;border:0}
.pane-grid>.glass:hover,a.glass:hover{transform:translateY(-3px);border-color:rgba(var(--porcelain-rgb),.28)}
@media (prefers-reduced-transparency:reduce){
  .glass{background:var(--ink)}
}
/* ---------- reveal ----------
   Blocks rise in as they enter the viewport. reveal.js marks <html> .js and
   adds .in; without JS or with reduced motion nothing is ever hidden. */
@media(prefers-reduced-motion:no-preference){
  .js .rv{opacity:0;transform:translateY(14px);transition:opacity .6s cubic-bezier(.16,1,.3,1),transform .6s cubic-bezier(.16,1,.3,1)}
  .js .rv.in{opacity:1;transform:none}
  .js .rv:nth-child(2){transition-delay:.06s}.js .rv:nth-child(3){transition-delay:.12s}.js .rv:nth-child(4){transition-delay:.18s}
}
@media(prefers-reduced-motion:reduce){.glass{transition:none}.pane-grid>.glass:hover,a.glass:hover{transform:none}}

/* ---------- button ----------
   One definition, shared by every subpage. It used to be copy-pasted into all
   four of them at 14px sentence case, while index.html ran 12.5px tracked
   uppercase, so the same component read as two different products. This is
   index.html's treatment, which matches the nav and the footer.
   Colour on the rim, not the fill. */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:10px;
  font-family:var(--font-body);font-size:12px;font-weight:500;letter-spacing:.16em;
  text-transform:uppercase;padding:16px 34px;border-radius:var(--r-pill);text-decoration:none;
  cursor:pointer;position:relative;
  /* Liquid glass: the body is a translucent accent-tinted pane over whatever
     sits behind it, and the light lives on the inner rim. The stack is one
     custom property so hover can add a glow without restating eight shadows. */
  --glass-shadow:0 2px 6px rgba(var(--void-rgb),.28),0 0 12px rgba(var(--void-rgb),.18),
    inset 3px 3px .5px -3.5px rgba(var(--porcelain-rgb),.09),
    inset -3px -3px .5px -3.5px rgba(var(--porcelain-rgb),.85),
    inset 1px 1px 1px -.5px rgba(var(--porcelain-rgb),.6),
    inset -1px -1px 1px -.5px rgba(var(--porcelain-rgb),.6),
    inset 0 0 6px 6px rgba(var(--porcelain-rgb),.12),
    inset 0 0 2px 2px rgba(var(--porcelain-rgb),.06);
  background:linear-gradient(135deg,rgba(var(--porcelain-rgb),.10),rgba(var(--porcelain-rgb),.03) 46%),rgba(var(--accent-rgb),.14);
  border:1px solid var(--accent);color:var(--porcelain);
  box-shadow:var(--glass-shadow);
  backdrop-filter:blur(4px) saturate(1.4);
  -webkit-backdrop-filter:blur(4px) saturate(1.4);
  transition:color .3s,border-color .3s,box-shadow .3s,transform .3s;
}
/* The accent rim as a gradient: gold bottom-left to blue top-right. Painted by
   a pseudo-element because `border` cannot take a gradient while the body stays
   transparent. Gated on mask support: without it the element paints a filled
   slab rather than a ring. The solid rim above stands in. */
@supports ((mask-composite:exclude) or (-webkit-mask-composite:xor)){
  .btn{border-color:transparent}
  .btn::after{
    content:"";position:absolute;inset:0;border-radius:inherit;padding:1px;
    background:var(--accent-grad);pointer-events:none;
    -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
    -webkit-mask-composite:xor;
    mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
    mask-composite:exclude;
  }
  .btn > span{position:relative;z-index:1}
}
.btn:hover{color:var(--porcelain);transform:scale(1.04);
  box-shadow:var(--glass-shadow),0 0 0 1px rgba(var(--accent-rgb),.5),0 0 20px -7px rgba(var(--accent-rgb),.7)}
.btn:active{transform:scale(.98)}
/* Every subpage disables the submit button while the request is in flight;
   only certification.html used to style that state. */
/* At 320px a 23-character label ("Fund a scholarship seat") had 208px of inner
   width and wrapped to two lines. Tighter padding and tracking buy it back
   without touching the type size. */
@media(max-width:400px){.btn{padding:15px 18px;letter-spacing:.1em}}
.btn[disabled]{opacity:.55;pointer-events:none}
/* A glass button keeps the glass fill. .btn and .glass are both (0,1,0), so
   whichever sheet comes last would otherwise decide, and .btn resets
   background to transparent for the UA button face. index.html is the only
   page that composes the two, and its inline sheet loads after this file,
   so ordering alone cannot settle it. (0,2,0) can. */
.btn.glass{background:var(--pane-bg);border-color:var(--pane-line);border-radius:var(--r-pill)}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .btn.glass{background:var(--ink)}
}
@media (prefers-reduced-transparency:reduce){
  .btn.glass{background:var(--ink)}
}
/* Secondary variant. The rim is the hierarchy: the primary wears the gradient
   ring, the secondary a porcelain hairline with no accent wash, so the two
   buttons in the hero read as primary and secondary rather than twins.
   (0,2,x) so it beats .btn, .btn::after and .btn.glass regardless of order. */
.btn.btn-line{border-color:rgba(var(--porcelain-rgb),.32);color:var(--porcelain)}
.btn.btn-line:not(.glass){background:linear-gradient(135deg,rgba(var(--porcelain-rgb),.08),rgba(var(--porcelain-rgb),.02) 46%)}
.btn.btn-line::after{content:none}
.btn.btn-line:hover{border-color:rgba(var(--accent-rgb),.6);
  box-shadow:var(--glass-shadow),0 0 18px -8px rgba(var(--accent-rgb),.6)}
/* Primary variant: a filled accent pill with ink text. One primary treatment
   for the whole site (hero, nav Join pill, form submits). Same (0,2,x)
   footing as the secondary, so it beats index.html's older .btn-solid rules
   and the .btn::after ring in every cascade order. Ink on the accent is 7.9:1;
   porcelain on it would fail AA. */
.btn.btn-solid{background:var(--accent);color:var(--void);font-weight:600;border-color:var(--accent);
  backdrop-filter:none;-webkit-backdrop-filter:none;
  box-shadow:0 2px 6px rgba(var(--void-rgb),.28),0 0 12px rgba(var(--void-rgb),.18),
    inset 0 1px 0 rgba(var(--porcelain-rgb),.35)}
.btn.btn-solid::after{content:none}
.btn.btn-solid:hover{background:#8ab0ff;border-color:#8ab0ff;color:var(--void);
  box-shadow:0 2px 6px rgba(var(--void-rgb),.28),0 0 22px -6px rgba(var(--accent-rgb),.8),
    inset 0 1px 0 rgba(var(--porcelain-rgb),.35)}
/* The glass body needs the page visible behind it. Without backdrop-filter,
   or when the visitor asks for reduced transparency, fall back to the opaque
   accent fill this button carried before it went glass. .btn.glass above is
   (0,2,0) and still wins its own fallback. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .btn{background:var(--accent-grad-fill),var(--void)}
}
@media (prefers-reduced-transparency:reduce){
  .btn{background:var(--accent-grad-fill),var(--void);backdrop-filter:none;-webkit-backdrop-filter:none}
}

/* The footer takes the nav's face: tracked uppercase at the nav's size and
   weight. It shipped here as 13px sentence case and on the homepage as
   11.5px tracked caps, so the same bar read as two different components. */
footer{border-top:1px solid var(--line);padding:40px 0 max(40px,env(safe-area-inset-bottom));
  color:var(--porcelain-dim);font-size:11px;font-weight:500;letter-spacing:.13em;text-transform:uppercase}
footer a{color:var(--porcelain-dim)}
/* Legal fine print: its own line, one step below the footer's own size. */
.foot-rights{display:block;font-size:10px;letter-spacing:.16em;margin-top:10px}
/* The separator travels with the link. Tracked caps push this line past a
   320px screen, and a bare · was being left stranded at the end of the
   first line while Privacy wrapped alone to the second. */
.foot-sep{white-space:nowrap}
/* The brand name in the footer is the logo, so it takes the logo face. The
   inline margin keeps the year off the wordmark: at this size the word space
   alone let "2026" crowd the G. */
.foot-brand{font-family:var(--font-title);font-weight:400;letter-spacing:.06em;text-transform:uppercase;color:var(--porcelain);margin-inline:7px}
/* ---------- footer sitemap ----------
   The homepage footer, ported to every subpage on 2026-08-14: the copyright
   block on the left, four labelled link columns on the right. index.html
   carries its own copy of these rules in its inline sheet; keep the two in
   step. Same shape at both ends: a left column that stretches to the height
   of the link columns so the made-by line sits on their last row. */
.foot{display:flex;justify-content:space-between;gap:40px;flex-wrap:wrap;align-items:flex-start}
.foot a{text-decoration:none;transition:color .25s}
.foot a:hover{color:var(--porcelain)}
.foot-left{display:flex;flex-direction:column;align-self:stretch}
.foot-made{display:block;font-size:10px;letter-spacing:.16em;margin-top:auto;padding-top:22px;color:var(--porcelain-dim)}
/* 44px between columns, not the homepage's 56: most subpages read in an 880px
   column, and at 56 the four columns wrapped under the copyright block. */
.foot-cols{display:flex;flex-wrap:wrap;gap:28px 44px}
.foot-col{display:flex;flex-direction:column;gap:12px;align-items:flex-start}
.foot-h{font-family:var(--font-mono);font-size:11px;letter-spacing:.26em;color:var(--porcelain);margin-bottom:2px}
/* text-transform and letter-spacing are not part of the `font` shorthand, and
   the UA sets both on a button, so `font:inherit` alone leaves Contact in
   sentence case and untracked next to identical footer links. */
.foot-contact{background:none;border:none;color:var(--porcelain-dim);font:inherit;
  text-transform:inherit;letter-spacing:inherit;transition:color .25s;cursor:pointer;padding:0}
.foot-contact:hover{color:var(--porcelain)}
@media(max-width:700px){.foot{justify-content:center;text-align:center}.foot-cols{justify-content:center;gap:28px 40px}.foot-col{align-items:center}}

/* Phones: 10 and 11px tracked caps are hard to read at arm's length, and an
   11px link is an 18px tap row. One step up across the footer, and 3px of
   vertical padding lifts each link box to about 24px. */
@media(max-width:480px){
  footer,.foot-h{font-size:12px}
  .foot-rights,.foot-made{font-size:12px;letter-spacing:.14em}
  .foot a,.foot-contact{padding:3px 0}
}

/* forms.js sets aria-invalid on the field the server rejected. Without a
   visible state that only ever reached screen readers, and everyone else was
   left hunting for which field was wrong. Its own rule, not a widening of any
   input selector. Every page styles its own inputs, so this is an attribute
   selector rather than a class one. !important because those per-page :focus
   rules are more specific, and being focused is exactly the state this field
   is in: flagEmail() focuses it. index.html carries its own copy, since it
   does not load this file. */
[aria-invalid="true"]{border-color:var(--warn)!important}
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation:none!important;transition:none!important}
  /* Transitions are killed above, so the hover scale would jump instead of
     glide. Kill the transform too. */
  .btn:hover,.btn:active{transform:none}
}

/* Print. Every page is light text on black and browsers print without
   backgrounds by default, so without this block headings came out white on
   white and body copy faint grey. Flip to black on white, drop the chrome
   (nav, canvases, video, dialogs, buttons, custom cursor), and force the
   scroll-reveal blocks visible since no observer runs on paper. !important
   throughout: per-page stylesheets come later in the cascade. */
@media print{
  *,*::before,*::after{background:transparent!important;color:#000!important;
    box-shadow:none!important;text-shadow:none!important;opacity:1!important;
    transform:none!important;animation:none!important;transition:none!important}
  html,body{background:#fff!important;cursor:auto!important}
  nav,canvas,video,dialog,.btn,.cursor,.cursor-ring,.mnav,.scrim{display:none!important}
  .reveal,.hero-line>span{opacity:1!important;transform:none!important}
  a{text-decoration:underline}
  a[href^="http"]::after{content:" (" attr(href) ")";font-size:.8em}
  pre,code{border:1px solid #999!important;white-space:pre-wrap;word-break:break-word}
  h1,h2,h3,h4{page-break-after:avoid}
  img,pre,blockquote{page-break-inside:avoid}
}
