/* ChatCEO light — build 2026-06-14b — PRODUCTION (promoted from CTD); hero top padding 80→40 */
/* ============================================================
   ChatCEO — style.css
   Colour is four tokens plus one exception; see the COLOUR
   block below. Type and spacing tokens follow it.
   ============================================================ */

/* ============================================================
   COLOUR  —  four colours, one exception, no alpha.

   Named by COLOUR, never by use. A token called --dark always
   holds a dark value. Nothing here is a background or a
   foreground; the ROLES block below decides that.

   gold, gray, green and red are each picked to carry on BOTH
   dark and light ground, so the theme toggle never touches
   them. Only the roles swap.
   ============================================================ */
:root {
  /* ---- the four ---- */
  --dark:   #0C182A;
  --light:  #EEE;
  --gray:   #777;
  --gold:   #9A7A2F;

  /* ---- the one exception ---- */
  --green:  #4C8062;                  /* "go", in three places: the brief's
                                         revenue meter, the submit button once
                                         the form is valid, and the founding
                                         CTA on hover. One colour, one meaning.
                                         Tuned to gold's energy: both now sit
                                         at 56%% of their own available chroma,
                                         so neither out-shouts the other where
                                         they meet (the poster's two goal cards).
                                         Was #2F855A, which ran at 82%%. */

  /* ---- warnings ---- */
  --red:    #C00;                     /* required *, "please complete"     */

  /* No alpha anywhere. Every colour on the page is one of the values
     above at full strength: no derived steps, no rgb(from ...), no
     opacity: in any rule, no rgba() literal. A thing gets a colour or
     it is not painted. The five derived steps that used to live here
     (gold-alpha-15, gold-alpha-strong, gray-alpha, dark-alpha,
     light-alpha) are gone; every consumer now names a real colour or
     the --line / --line-band role. */

  /* ---- gold, brighter ----
     The one colour beyond your list. It is the link/button hover
     state; without it hover has no feedback at all. Candidate to
     delete when the new gold is chosen. */
  --gold-hover: #8A6C28;   /* --gold +17 on every channel */
}

/* ============================================================
   ROLES  —  what each colour is FOR.

   The page is a light ground with alternating dark bands and
   cards sitting on it. "ink" is text on the ground; "band-ink"
   is text on a band or card.

   There is one theme. The dark-ground variant and its toggle
   were removed on 2026-09-13: the page had been designed and
   judged entirely in this one, and the other had drifted into
   14 contrast failures nobody was looking at.

   Nothing below should ever be a raw palette name in a rule.
   If a rule says var(--dark) where it means "text on the
   ground", it will be wrong the next time anything moves --
   that is exactly how the dark variant rotted.
   ============================================================ */
:root {
  --ground:    var(--light);        /* page background                   */
  --ink:       var(--dark);         /* text on the ground                */
  --band:      var(--dark);         /* bands, cards, inputs, nav         */
  --band-ink:  var(--light);        /* text on a band or card            */
  --line:      var(--dark);         /* hairline drawn on the ground      */
  --line-band: var(--light);        /* hairline drawn on a band or card  */
  --mark:      var(--dark);         /* the logo, and both bands          */
  --tri:       var(--dark);         /* 27-tri on the ground              */
  --tri-band:  var(--light);        /* 27-tri on a band                  */
}

/* ============================================================
   Non-colour tokens
   ============================================================ */
:root {
  --easing:       cubic-bezier(0.2, 0.7, 0.2, 1);

  --font-sans:    -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-head:    -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-display: "Iowan Old Style", Georgia, serif;
  --font-mono:    ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --maxw:  1280px;
  --tri-spin: 15s;          /* one full turn of the hero triangles (8 deg/s) */
  --tri-sweep: 95%;         /* share of hero height the swept circle may fill */
  /* The bar and the gold rule under it are separate, and --nav-h is what
     the two of them OCCUPY. Everything that has to clear the nav reads
     --nav-h (the hero's min-height, scroll-padding-top), so changing
     either number here moves all of them together.
     box-sizing is border-box, so the rule is drawn inside --nav-h:
     66 total = 60 bar + 6 rule.

     --rule is NOT nav-specific: the same band opens the page under the
     nav and closes it above the footer. One number so the opener and the
     closer cannot drift apart. */
  --nav-bar:  60px;
  --rule:     6px;
  --nav-h:    calc(var(--nav-bar) + var(--rule));

  /* The closing bookend. nav + hero fills the first viewport; founding +
     footer fills the last one, so scrolling to the bottom lands on a
     clean full-height panel instead of a sliver of the section above.
     Measured at 129px and stable at every landscape width from 1024 up;
     DECLARED here and enforced on .footer in the landscape block below,
     so if the footer ever grows a row it breaks loudly instead of
     drifting the calc quietly out of true. Border-box, so the 6px rule
     is inside this number: 129 = 123 + 6. */
  --footer-bar: 123px;
  --footer-h:   calc(var(--footer-bar) + var(--rule));

}

*, *::before, *::after { box-sizing: border-box; }
/* The nav is sticky, so it stays in the flow and <main> already begins
   below it — but on arrival at an anchor the stuck nav covers the first
   --nav-h of the target. scroll-padding-top tells the scroll container to
   stop that much short, for every anchor on the page, current and future.
   It reads the same token the nav is sized with, so it cannot drift. */
html { scroll-behavior: smooth; scroll-padding-top: var(--nav-h); }
body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3 { font-family: var(--font-head); font-weight: 800; margin: 0; }
a { color: var(--gold); text-decoration: none; }
a:hover { color: var(--gold-hover); }
/* The two gold links carry their rule as a border, which a colour change on
   :hover does not touch -- so the text lit up and the underline stayed
   behind. Both move together now. */
.link-gold:hover, .featured__ft:hover { border-bottom-color: var(--gold-hover); }
img { max-width: 100%; display: block; }

.text-gold { color: var(--gold); }
.link-gold {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--gold); font-family: var(--font-head); font-weight: 700;
  font-size: 16px; border-bottom: 2px solid var(--gold); padding-bottom: 2px;
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--font-head); font-weight: 700; letter-spacing: 0.01em;
  border: none; border-radius: 10px; cursor: pointer;
  padding: 14px 22px; font-size: 15.5px;
  /* ASYMMETRIC on purpose. A transition declared here governs the way OUT
     of :hover; one declared on :hover governs the way in. Going to green
     should feel immediate -- it is a "go" signal. Coming BACK is where the
     trouble is: the eye adapts to the green while you hover, and when the
     gold returns the leftover adaptation lays a magenta-red afterimage over
     it, so the gold reads reddish for a moment. That is opponent-process,
     not the colour being wrong, and the only thing that helps is giving the
     adaptation time to decay -- hence 400ms out against 140ms in.

     colour is in the list now too. It was not, so the label snapped while
     the fill faded, which sharpened the whole event. */
  transition: background 400ms var(--easing), color 400ms var(--easing),
              transform 80ms var(--easing);
}
.btn--gold { background: var(--gold); color: var(--light); }
/* Gold goes GREEN on hover -- traffic-light "go", and the same green the
   submit button turns when the form is valid, so the page says "go" in one
   colour rather than two. The change travels 66deg of HUE rather than
   lightness (dE 12.8, larger than a +34 brightness step) which is why it
   reads as decisive while getting DARKER instead of washing out. --light
   on --green is 3.91:1, better than the 3.01:1 it rests at. */
.btn--gold:hover { background: var(--green); color: var(--light); }
.btn--gold:hover  { transition: background 140ms var(--easing), color 140ms var(--easing); }
.btn--gold:active { background: var(--gold); transform: translateY(1px); }

/* ---------- Nav ---------- */
.nav {
  position: sticky; top: 0; z-index: 50;
  background: var(--ground);
  color: var(--ink);
  border-bottom: var(--rule) solid var(--mark);
  height: var(--nav-h);
}
.nav__inner {
  max-width: var(--maxw); margin: 0 auto;
  padding: 16px 64px;
  display: flex; align-items: center; justify-content: space-between;
}
.nav__brand { display: inline-flex; }
.nav__logo { height: 26px; width: auto; fill: var(--mark); display: block; }
.nav__brand:hover .nav__logo { fill: var(--gold-hover); }

/* ---------- Hero ---------- */
.hero {
	padding: 0 64px;
	position: relative;
	overflow: hidden;
	min-height: calc(100dvh - var(--nav-h));
	display: flex;
	align-items: center;
}
/* The 27-tri. Every path is the same triangle at scale(k), so they all
   share SVG (0,0) — which is also what rotate() pivots about. Centring
   this element therefore centres the PIVOT, not the ink.

   top was 44.5%, putting the pivot 45.9px above the hero's centre: the
   figure looked centred standing still but would have orbited that
   offset point once animated, and swung 59px past the hero's top edge.
   top:50% puts the pivot on the hero's centre.

   Size needs no arithmetic. The artwork's circumcircle touches the edges
   of its square viewBox, so the swept circle IS the element box: height
   95% means the spin occupies 95% of the hero, full stop. Box centre,
   circle centre, centroid and pivot are all the same point, which is why
   nothing here needs a centring nudge.

   The ink's own bbox centre is (0, -6.264) — NOT the pivot. Do not
   "correct" that: translating it onto the pivot grows the sweep from
   34.41 to 37.87 units. (0,0) is nearer the minimum-enclosing-circle
   centre than the bbox centre is. */
.hero__triangles {
  position: absolute;
  left: 50%; top: 50%;
  width: auto;
  height: var(--tri-sweep);
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  pointer-events: none; z-index: 0;

  /* Spin. transform-origin defaults to the element's own centre, and the
     viewBox is "-100 -100 200 200", so the element's centre IS SVG (0,0)
     — the same point the <g rotate()> pivots about. No extra origin
     needed. The keyframes must repeat the translate, or the animation
     would drop it and the figure would jump by half its own size. */
  animation: tri-spin var(--tri-spin) linear infinite;
}
@keyframes tri-spin {
  from { transform: translate(-50%, -50%) rotate(0deg); }
  to   { transform: translate(-50%, -50%) rotate(360deg); }
}

/* ---- TO REVERT to the big static tri that filled the hero ----
   .hero__triangles { top: 44.5%; height: 103.2%; animation: none; }
   and delete the @keyframes. 44.5%/300% centred the INK but put the
   PIVOT 45.9px high, which is why it could not be spun. -------------- */
.hero__inner {
  position: relative; z-index: 1;
  max-width: var(--maxw); margin: 0 auto;
  display: grid; grid-template-columns: minmax(0,1.15fr) minmax(0,1fr);
  gap: 72px; align-items: center;
}
.hero__title {
  color: var(--ink);
  font-size: 80px; line-height: 0.98; letter-spacing: -0.04em;
  text-wrap: balance;
}
.hero__sub {
  font-size: 20px; line-height: 1.55; color: var(--ink);
  max-width: 560px; margin: 28px 0 0;
}

/* ---------- Apply card / form ---------- */
.apply-card {
  background: var(--ground);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 36px 40px;
  color: var(--ink);
}
.apply-card__title { color: var(--ink); font-size: 26px; line-height: 1.1; letter-spacing: -0.02em; margin: 0 0 8px; }
.apply-card__note { font-size: 13.5px; line-height: 1.5; color: var(--ink); margin: 0 0 18px; }

.field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }

/* ---------- Featured band ---------- */
.featured { border-top: 1px solid var(--line-band); border-bottom: 1px solid var(--line-band); background: var(--band); color: var(--band-ink); }
.featured__inner {
  max-width: var(--maxw); margin: 0 auto; padding: 28px 64px;
  display: flex; flex-direction: column; align-items: center; gap: 18px;
}
.featured__row { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; justify-content: center; }
.featured__ft {
  font-family: var(--font-display); font-weight: 700; font-size: 19px;
  color: var(--gold); text-decoration: none;
  border-bottom: 2px solid var(--gold); padding-bottom: 1px;
  letter-spacing: -0.01em;
}
.featured__ft span { font-family: var(--font-display); font-weight: 700; font-size: 18px; margin-left: 4px; }
.featured__eyebrow {
  font-family: var(--font-head); font-weight: 700;
  font-size: 11px; letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--gray);
}
.featured__eyebrow--sub {
  font-weight: 600;
  font-size: 10.5px; letter-spacing: 0.18em;
  color: var(--gray);
  transform: translateY(3px);
}
.featured__pub { font-family: var(--font-display); font-weight: 700; font-size: 17px; color: var(--band-ink); letter-spacing: -0.01em; }

/* ---------- System section ---------- */
.system { padding: 120px 64px; }
.system__inner {
  max-width: 1180px; margin: 0 auto;
  display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1.4fr);
  gap: 80px; align-items: center;
}
.system__title { color: var(--ink); font-size: 60px; line-height: 1; letter-spacing: -0.035em; margin: 0 0 24px; text-wrap: balance; }
.system__lead { color: var(--ink); font-size: 17.5px; line-height: 1.6; margin: 0 0 28px; }
.system__art { display: flex; justify-content: center; }

/* ---------- Testimonials ---------- */
.tst { padding: 120px 64px; background: var(--band); color: var(--band-ink); border-top: 1px solid var(--line-band); border-bottom: 1px solid var(--line-band); }
.tst__inner { max-width: 1200px; margin: 0 auto; }
.tst__head { text-align: center; margin-bottom: 56px; }
.tst__title { color: var(--band-ink); font-size: 48px; line-height: 1.05; letter-spacing: -0.03em; margin: 0 auto 18px; max-width: 880px; text-wrap: balance; }
.tst__sub { color: var(--band-ink); font-size: 16px; max-width: 720px; margin: 0 auto; }
.tst__grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 20px; }

.tcard { margin: 0; display: flex; flex-direction: column; gap: 18px; background: var(--band); color: var(--band-ink); border: 1px solid var(--line-band); border-radius: 14px; padding: 26px 28px; height: 100%; }
.tcard__quote { font-size: 16px; line-height: 1.6; color: var(--band-ink); margin: 0; }
.tcard__person { display: flex; align-items: center; gap: 14px; }
.tcard__photo { width: 48px; height: 48px; border-radius: 50%; object-fit: cover; border: 1px solid var(--line-band); flex: none; }
.tcard__name { font-weight: 100; font-size: 14.5px; color: var(--band-ink); }
.tcard__lastname { font-weight: bold; }

.tcard__meta { font-size: 12.5px; color: var(--gray); }

/* ---------- FAQ ---------- */
.faq { padding: 120px 64px; }
.faq__inner { max-width: 860px; margin: 0 auto; }
.faq__title { color: var(--ink); font-size: 48px; letter-spacing: -0.03em; text-align: center; margin: 0 0 48px; }
.faq__list { display: flex; flex-direction: column; gap: 14px; }
/* No border, for the reason .tree__node has none: --line-band is var(--light),
   and these cards sit on the off-white GROUND, not on a dark band. The hairline
   was therefore the same value as what is behind it -- invisible as a line, and
   on a textured ground its antialiased curve picks up the grain and reads as a
   rough corner. --line-band is for a line drawn ON a dark surface (.tcard on
   .tst, .faq__icon on this card) where it has something to contrast with.
   The 14px gap in .faq__list keeps the items apart without it. 2026-09-14. */
.faq__item { background: var(--band); color: var(--band-ink); border-radius: 14px; overflow: hidden; }
.faq__q {
  width: 100%; display: flex; align-items: center; gap: 18px;
  padding: 22px 26px; background: transparent; border: none; cursor: pointer; text-align: left;
}
.faq__q-text { flex: 1; font-family: var(--font-head); font-weight: 800; font-size: 24px; letter-spacing: -0.02em; color: var(--band-ink); line-height: 1.2; }
/* 2px, AND THE PLUS INSIDE STAYS AT 1px ON PURPOSE.

   A 1px straight line sits on pixel boundaries and renders solid. A 1px CURVE
   crosses them at every angle, so every pixel around the ring is partial
   coverage and it can never be solid -- it reads thin and broken however
   carefully it is drawn. That is a property of the shape, not of the colour,
   and the only fix is width.

   The + is drawn at stroke-width 2 in a 24-unit viewBox rendered at 12px,
   which is also 1px on screen. It does not need the same treatment because it
   is straight, and matching it to the ring would make a 2px stroke on a 7px
   line -- a heavy mark where a hairline is wanted. A container may be heavier
   than the detail inside it. 2026-09-14. */
.faq__icon { width: 28px; height: 28px; border-radius: 999px; border: 2px solid var(--line-band); display: grid; place-items: center; flex: none; transition: transform 200ms var(--easing); }
.faq__item.is-open .faq__icon { transform: rotate(45deg); }
.faq__body { max-height: 0; overflow: hidden; transition: max-height 360ms var(--easing); }
/* The open height is set inline by app.js from the body's own
   scrollHeight. A fixed cap here clipped the long answers at phone
   widths; .is-open is only ever added by that same script, so there is
   no no-JS path this rule would have covered. */
.faq__body-inner { padding: 0 26px 28px; }
.faq__lead { font-family: var(--font-head); font-weight: 700; font-size: 20px; line-height: 1.3; color: var(--band-ink); margin: 0 0 16px; }
.faq__a { color: var(--band-ink); font-size: 15px; line-height: 1.65; margin: 0 0 12px; max-width: 720px; }
.faq__bio { display: grid; grid-template-columns: 180px 1fr; gap: 28px; align-items: start; }
.faq__bio-photo { width: 180px; height: 220px; border-radius: 12px; object-fit: cover; object-position: center 15%; border: 1px solid var(--line-band); }

/* ---------- Founding CTA ---------- */
.founding { padding: 120px 64px 140px; text-align: center; }
.founding__inner { max-width: 640px; margin: 0 auto; }
.founding__title { color: var(--ink); font-size: 64px; line-height: 0.98; letter-spacing: -0.035em; margin: 0 0 22px; text-wrap: balance; }
.founding__sub { color: var(--ink); font-size: 17.5px; line-height: 1.65; margin: 0 auto 36px; max-width: 460px; }

/* ---------- Footer ---------- */
/* The closer. Same band as the nav's opener, same token, attached to
   the footer the way the nav owns its own -- a rule floating on the
   section above belonged to neither side of the boundary. */
.footer { border-top: var(--rule) solid var(--mark); padding: 32px 64px; }
.footer__inner { max-width: var(--maxw); margin: 0 auto; display: flex; flex-direction: column; gap: 14px; }
.footer__row { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.footer__row--top { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; }
.footer__row--top .footer__logo { justify-self: start; }
.footer__row--top .footer__links { justify-self: end; }
.footer__row--bot { justify-content: center; }
.footer__logo { height: 22px; width: auto; fill: var(--ink); flex: none; }
.footer__tag { color: var(--gray); font-size: 14px; margin: 0; display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.footer__tag--motto { font-family: var(--font-head); font-weight: 700; color: var(--ink); }
.footer__xpertloop { height: 13px; width: auto; fill: var(--ink); vertical-align: middle; }

/* ---------- Responsive ---------- */
/* The form sets this number. A form-columns-2 field is (cardW - 90) / 2
   wide, and "Number of employees*" needs 164.0px to stay on one line,
   so the card needs 418px. In the two-up hero the card is the right
   column, which falls below 418px at a viewport of ~1099. Stack above
   that, or the label wraps to two lines and the row heights go uneven.
   If the label text or the form font ever changes, re-measure. */
@media (max-width: 1120px) {
  /* Stacked, the hero is a full viewport tall but its content is not, so
     centring bunched the headline and the form in the middle -- directly
     over the hub of the spinning art, with dead ground above and below.
     Stretch the inner to the hero's height and push the two rows apart:
     copy rides up under the nav, the card drops to the bottom, and the
     centre of the artwork is left clear. gap is the FLOOR, not the
     spacing -- space-between distributes whatever slack is left. */
  .hero { align-items: stretch; padding-top: 64px; }
  .hero__inner {
    grid-template-columns: 1fr;
    gap: 48px;
    align-content: space-between;
  }
  /* Stacked, the hero is driven by its CONTENT height, not the viewport --
     a tall headline plus a full-width form. The art is 95% of that height
     and square, so it grew as the hero grew while the viewport got
     narrower: ~840px of triangles inside a 390px-tall rotated phone, and
     wider than the window in a portrait desktop. Below this breakpoint the
     short axis is the width, so size off width and let aspect-ratio derive
     the height. Not an orientation query: a rotated phone is landscape and
     still stacks. */
  .hero__triangles { width: var(--tri-sweep); height: auto; }
  /* Stacked, the card runs to the hero's bottom edge and butts straight
     into the band below. Padding rather than margin: the hero clips the
     triangles to its padding box, so padding carries the artwork through
     the new space while a margin would cut it off and leave a blank
     strip. (gap cannot do it -- one flex child, nothing to space.) */
  .hero { padding-bottom: 64px; }
}
@media (max-width: 980px) {
  .system__inner { grid-template-columns: 1fr; gap: 48px; }
  .hero__title { font-size: 56px; }
  .system__title, .founding__title { font-size: 44px; }
  .tst__grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 760px) {
  /* The hero art goes away entirely on a phone: the apply card covers
     most of it, the sweep has no room left to read as a figure, and what
     shows through is just texture behind the form.

     The pull band KEEPS its triangles and keeps them turning -- that art
     is the point of the band. There was a .pull__triangles{animation:none}
     here that never did anything (the base rule is declared later and a
     media query adds no specificity, so source order won), which is why
     they have been spinning on phones all along. Removed rather than
     repaired: the spin is wanted, and a rule that only works once someone
     tidies the file is a trap. */
  .hero__triangles { display: none; }
  .nav__inner, .hero, .featured__inner, .system, .tst, .faq, .founding, .footer { padding-left: 24px; padding-right: 24px; }
  .hero { padding-top: 48px; padding-bottom: 48px; }
  .hero__title { font-size: 44px; }
  .tst__grid { grid-template-columns: 1fr; }
  .tst__title, .faq__title { font-size: 34px; }
  .faq__bio { grid-template-columns: 1fr; }
  .faq__bio-photo { width: 140px; height: 170px; }
}

/* ---------- Footer legal links ---------- */
.footer__links { display: flex; gap: 20px; flex-wrap: wrap; justify-content: center; }
.footer__links a { color: var(--ink); font-size: 14px; }
.footer__links a:hover { text-decoration: underline; }

/* ---------- Daily Brief ---------- */
/* The poster inside is a frozen 760px inline-styled block, tilted
   -1.2deg, so its footprint is wider than its box: at 360px it pushed
   the document to 385px and the whole page scrolled sideways. clip,
   not hidden -- clip contains the spill without making this a scroll
   container. Remove when brief.css lands and the poster can be made
   to fit honestly. */
.brief { padding: 120px 64px; overflow-x: clip; }
.brief__inner { max-width: 1100px; margin: 0 auto; }
.brief__head { text-align: center; margin-bottom: 56px; }
.brief__title { color: var(--ink); font-size: 48px; line-height: 1.05; letter-spacing: -0.03em; margin: 0 auto 18px; max-width: 820px; text-wrap: balance; }
.brief__sub { color: var(--ink); font-size: 17px; line-height: 1.6; max-width: 720px; margin: 0 auto; }

/* ---------- Pull Quote ---------- */
.pull { padding: 100px 64px; background: var(--gold); color: var(--band-ink); border-top: 1px solid var(--line-band); border-bottom: 1px solid var(--line-band); position: relative; overflow: hidden; }
.pull__triangles {
  position: absolute;
  left: 50%; top: 50%;
  width: auto; height: 95%;   /* was 300% of a box the art filled 34.4% of */
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  pointer-events: none; z-index: 0;
  animation: tri-spin var(--tri-spin) linear infinite;
}
.pull__inner { max-width: 1000px; margin: 0 auto; position: relative; z-index: 1; text-align: center; }
.pull__quote { font-family: var(--font-head); font-weight: 700; font-size: 40px; line-height: 1.18; letter-spacing: -0.025em; color: var(--band-ink); margin: 0; text-wrap: balance; }
.pull__muted { color: var(--dark); }
.pull__foot { font-size: 24px; color: var(--dark); font-weight: bold; font-style: italic; margin: 24px 0 0; }

@media (max-width: 760px) {
  .brief, .pull { padding-left: 24px; padding-right: 24px; }
  .brief__title { font-size: 34px; }
  .pull__quote { font-size: 28px; }
}

/* ---------- CEO Operating System  ----------
   A hierarchy, not an orbit. One trunk, five branches, read top to
   bottom. Replaced a circle whose node positions were computed by
   trigonometry but read as arbitrary -- and which was display:none
   below 980px, so tablets and phones lost the section entirely. This
   survives every width. */
.system__art { display: flex; justify-content: center; min-width: 0; }

.tree {
  --elbow:   38px;    /* how far a branch reaches out from the trunk */
  --radius:  10px;    /* the turn at the elbow */
  --row-gap: 14px;
  /* ONE size for the root and the branch labels. They are the same rank of
     type doing the same job, so they read as one family and the width of
     the block is governed by whichever string happens to be longest. */
  --tree-font: clamp(19px, 2.1vw, 26px);

  /* Row height is the one knob. The badge and the icon inside it are
     fractions of it, so raising --row-h carries them along instead of
     leaving a small disc floating in a taller bar. A percentage would
     not work here: the row is sized by min-height, which is not a
     definite height, so a % on the badge would resolve to auto.
     0.53 and 0.28 are the ratios the 72px row already had. */
  --row-h:  72px;
  --badge:  calc(var(--row-h) * 0.53);
  --icon:   calc(var(--row-h) * 0.28);

  /* The ROOT sets the width of everything. max-content sizes the block to
     the longest line it contains -- which is the root's own text plus its
     padding -- and the branch rows then stretch to whatever is left after
     the indent. So the gold box is fit-to-its-words with even padding on
     both sides, and the blue boxes are governed by it rather than by the
     column they happen to sit in. max-width keeps it honest on a narrow
     screen, where it shrinks and the text wraps instead of overflowing. */
  width: max-content;
  max-width: 100%;
}

/* the parent: wider AND taller than its children, so the level reads
   before you trace a single connector */
.tree__root {
  display: flex; align-items: center; gap: 12px;
  min-height: 88px;
  padding: 0 26px;
  background: var(--gold); color: var(--light);
  border: 1px solid var(--line);
  border-radius: 14px;
  font-family: var(--font-head); font-weight: 800;
  font-size: var(--tree-font); letter-spacing: -0.02em;
}
.tree__root-the {
  align-self: center;
  font-family: var(--font-head); font-weight: 700; font-size: 10px;
  letter-spacing: 0.22em; text-transform: uppercase; color: var(--light);
}

.tree__list { list-style: none; margin: 0; padding: 0 0 0 22px; }

.tree__item {
  position: relative;
  padding-left: calc(var(--elbow) + 14px);
  margin-top: var(--row-gap);
}
/* The elbow -- down from the trunk, then right. Both borders live on ONE
   element so the turn can be rounded; split across two pseudo-elements
   there is no joint to put a radius on. It starts a --row-gap high so it
   bridges the space above and meets the trunk without a seam. */
.tree__item::before {
  content: ""; position: absolute; left: 0;
  top: calc(-1 * var(--row-gap));
  width: var(--elbow); height: calc(50% + var(--row-gap));
  border-left: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  border-bottom-left-radius: var(--radius);
}
/* The trunk carries on past every row but the last, which is what makes
   the final row an automatic elbow-and-stop with no special case. */
.tree__item:not(:last-child)::after {
  content: ""; position: absolute; left: 0; top: 50%;
  bottom: calc(-1 * var(--row-gap));
  border-left: 1px solid var(--line);
}

/* NO BORDER, and that is the fix rather than a simplification.

   It was 1px solid var(--line-band) -- and --line-band is var(--light), the
   same off-white the section ground is. So the border was invisible AS a
   border, and two things followed from that:

     the perceived edge of the box became the INNER edge of the ring, an 11px
     radius rather than 12. One pixel tighter on a 72px row is enough to read
     as chamfered instead of rounded.

     the real 12px curve was a light-on-light antialiased boundary sitting on
     a TEXTURED ground, so its edge pixels varied with the grain. That is the
     roughness -- the antialiasing of an edge you cannot see picking up the
     noise behind it.

   Dark blue against the ground is contrast enough on its own; the border was
   only ever separating it from a white page. 2026-09-14. */
.tree__node {
  display: flex; align-items: center;
  min-height: var(--row-h);
  background: var(--band); color: var(--band-ink);
  border-radius: 12px;
  overflow: hidden;
}
.tree__badge {
  width: var(--badge); height: var(--badge); border-radius: 999px;
  border: 1px solid var(--line-band);
  background: var(--gold);
  display: grid; place-items: center; flex: 0 0 auto;
  margin: 0 12px 0 14px;
}
/* The number rides on the label's line rather than stacking above it, so
   a row is one line of type and the longest LABEL sets the width of the
   whole tree -- the root then comes out one indent wider, which is what
   makes the parent bigger without setting its size by hand. */
.tree__text {
  /* centre, not baseline. The number is 11px against a 26px label, so a
     shared baseline drops it to the bottom of the line and it reads as
     having fallen. One line of text per row means nothing is riding on
     the baseline, so centring is free. */
  display: flex; align-items: center; gap: 10px;
  flex: 1 1 0; min-width: 0; padding-right: 18px;
}
.tree__num {
  flex: 0 0 auto;
  font-family: var(--font-mono); font-weight: 600;
  font-size: 11px; color: var(--gray); letter-spacing: 0.08em;
}
.tree__label {
  min-width: 0;
  font-family: var(--font-head); font-weight: 700;
  font-size: var(--tree-font); color: var(--band-ink);
  line-height: 1.15; letter-spacing: -0.01em;
  white-space: nowrap;
}

/* ─────────── LEGAL PAGES (privacy / terms) ─────────── */
.legal { max-width: 820px; margin: 0 auto; padding: 72px 24px 96px; }
.legal__inner { background: var(--band); color: var(--band-ink); border: 1px solid var(--line-band); border-radius: 14px; padding: 40px 44px; }
.legal__title { font-family: var(--font-head); font-weight: 800; font-size: 40px; letter-spacing: -0.02em; color: var(--band-ink); margin: 0 0 24px; }
.legal__inner .meta { font-family: var(--font-mono); font-size: 13px; color: var(--gold); letter-spacing: 0.04em; margin: 0 0 28px; }
.legal__inner h3 { font-family: var(--font-head); font-weight: 700; font-size: 19px; color: var(--band-ink); margin: 28px 0 10px; }
.legal__inner h3:first-of-type { margin-top: 0; }
.legal__inner p { color: var(--band-ink); font-size: 15px; line-height: 1.65; margin: 0 0 16px; }
.legal__inner ul { margin: 0 0 16px 22px; }
.legal__inner li { color: var(--band-ink); font-size: 15px; line-height: 1.65; margin-bottom: 10px; }
.legal__inner a { color: var(--gold); }

.hs-form {
	width: 100%;
}

.hs-form-required {
	color: var(--red);
}

/* The field box. font-family is set explicitly because form controls do
   NOT inherit it from the page — without this line the inputs render in
   the UA default (Arial) while everything around them is Inter. */
.hs-input {
	height: 43px;
	padding: 11px 14px;
	font-family: var(--font-sans);
	font-size: 15px;
	border-radius: 6px;
	border: 1px solid var(--line);   /* same hairline as the form frame */
	background-color: var(--ground);
	color: var(--ink);
}

/* The submit is the same box as a field, filled in: identical height,
   padding, font, border and radius. HubSpot ships it as a bare
   input[type=submit], so every one of these is overriding a UA default
   (21px tall, 2px outset border, square corners, 13.3px Arial). */
.hs-button.primary.large {
	height: 43px;
	padding: 11px 28px;   /* side padding doubled — it read too narrow at 14 */
	font-family: var(--font-sans);
	font-size: 15px;
	line-height: 1;
	border: 1px solid var(--ink);
	border-radius: 6px;
	background-color: var(--dark);
	color: var(--light);
	cursor: pointer;
}

/* .actions wraps the button in a block, so the button sits on a line box
   and picks up ~4px of descender leading above it. Flex removes the line
   box so the spacing below is exact. */
.apply-card .hs-form-private .actions {
	display: flex;
}

/* Stand the submit off the last field by a full row step, so it reads as
   the next row down: 6px + one label + 6px = 37.6px. 1.6em is one label —
   they inherit 16px at line-height 1.6.
   This carries the whole step, not the remainder: .hs_submit and the last
   fieldset are adjacent block siblings, so the fieldset's 6px bottom
   margin COLLAPSES with this one instead of adding to it. Only the larger
   of the two ever applies. */
.apply-card .hs-form-private .hs_submit {
	margin-top: calc(1.6em + 12px);
}

/* ── HubSpot legacy form: field widths ──────────────────────────────────
   v2.js compiles its stylesheet into the bundle and injects it as
   <style id="hs-form-style0"> at the END of <head> — after this file — so
   equal-specificity rules lose on source order. The .apply-card prefix
   takes these to (0,4,1) and outranks HubSpot's (0,3,1) without !important.

   Reference copy of what is being overridden: hubspot-v2-injected.css
   (documentation only — do not link it from index.html).

   In DevTools the injected rules read .hs-form-<guid>_<uuid>, not
   .hs-form-private; the <form> carries both and only the latter is stable
   across page loads.
   ───────────────────────────────────────────────────────────────────── */

/* Row rhythm. Inside a field, label->input is 6px, set by the row-gap on
   .field. Between rows, HubSpot supplies nothing at all — input to the
   next label measured 0.0px — so the two spacings did not match. Each
   fieldset is one row, so its bottom margin is the between-row gap.
   Both numbers are 6px; change them together. */
.apply-card .hs-form-private fieldset {
	margin-bottom: 6px;
}

/* overrides: .hs-form-private fieldset { max-width: 500px } */
.apply-card .hs-form-private fieldset {
	max-width: none;
	width: 100%;
}

/* overrides: fieldset.form-columns-1 .hs-input { width: 95% }.
   Also sizes the 2-up rows, which HubSpot gives no width at all on
   desktop — they sit at the browser's default text-input size. */
.apply-card .hs-form-private fieldset .hs-input:not([type=checkbox]):not([type=radio]) {
	width: 100%;
}

/* HubSpot's 8px wrapper margin is the column gutter on the 2-up rows
   (firstname/lastname, company/numemployees) — keep it there, drop it on
   the full-width rows. */
.apply-card .hs-form-private fieldset.form-columns-1 .input {
	margin-right: 0;
}

/* HubSpot builds 2-up rows from floats at width:50% and fakes the gutter
   with margin-right:8px on BOTH columns. That puts 8px of dead space on
   the right edge and makes the columns unequal (231.9px vs 239.9px here),
   because column one loses its margin to the gutter and column two loses
   its margin to nothing.
   Flex instead: the gutter becomes a real gap, both columns are exactly
   equal, and both outer edges line up with the full-width fields. */
.apply-card .hs-form-private fieldset.form-columns-2 {
	display: flex;
	gap: 8px;
}
.apply-card .hs-form-private fieldset.form-columns-2 .hs-form-field {
	float: none;
	width: auto;
	flex: 1 1 0;
	min-width: 0;
}
.apply-card .hs-form-private fieldset.form-columns-2 .input {
	margin-right: 0;
}

.hs_firstname label,
.hs_lastname label,
.hs_email label,
.hs_company label,
.hs-hs_linkedin_url label,
.hs_numemployees label {
	color: var(--ink);
}

/* The open dropdown list. The <option>s ship with background-color
   transparent, so the popup is painted by Windows in its own gray —
   this is the one part of the form the OS owns. Naming a colour on the
   options takes it back. color-scheme keeps the popup's own chrome
   (scrollbar, border) on the same side as the colours.
   This replaces the old `.select select option` rule, which never
   matched anything: HubSpot's select is not inside a `.select`. */
.apply-card .hs-form-private select.hs-input {
	color-scheme: dark;
}
.apply-card .hs-form-private select.hs-input option {
	background-color: var(--ground);
	color: var(--ink);
}
.apply-card .hs-form-private select.hs-input option:disabled {
	color: var(--gray);
}

/* ── Validation messages ───────────────────────────────────────────────
   HubSpot emits these as a <ul><li><label>. The bullet and the 40px
   indent are not HubSpot's doing — the <ul> carries a "no-list" class
   that has no rule anywhere in the bundle, so the browser's own
   list-style:disc / padding-left:40px apply. Hence resetting both here.
   The dark colour was inherited --band-ink, not set by HubSpot either.
   The leading * mirrors the * on each required field's label.
   ──────────────────────────────────────────────────────────────────── */
.apply-card .hs-form-private .hs-error-msgs {
	list-style: none;
	padding-left: 0;
	margin: 6px 0 0;
}
.apply-card .hs-form-private .hs-error-msgs label {
	color: var(--red);
	font-size: 13.5px;
	line-height: 1.4;
}
.apply-card .hs-form-private .hs-error-msg::before {
	content: "*";
	margin-right: 4px;
}

/* ── Submit validity ───────────────────────────────────────────────────
   Green once every required field satisfies its own constraint, dark
   until then. :has() reads the live validity of the fields, so no JS.
   The form carries novalidate, which only suppresses the browser's
   native popups — :invalid still matches, so this keeps working.
   The button is NOT pointer-events:none while dark: clicking it is what
   makes HubSpot render the per-field messages above, and taking that
   away would leave the user with a dead button and no reason given.
   ──────────────────────────────────────────────────────────────────── */
.apply-card .hs-form-private:has(.hs-input:invalid) .hs-button.primary.large {
	background-color: var(--dark);
	border-color: var(--ink);
	color: var(--light);
	cursor: not-allowed;
}
.apply-card .hs-form-private:not(:has(.hs-input:invalid)) .hs-button.primary.large {
	background-color: var(--green);
	border-color: var(--green);
	cursor: pointer;
}
/* ---------- SVG paint ----------
   Every mark names its own colour. Nothing reads an ancestor's `color`,
   so a mark cannot change because something above it changed. -------- */
.hero__triangles path      { stroke: var(--tri); }
.hero__triangles use       { fill:   var(--tri); }   /* the mark, same gray as the outlines */
.pull__triangles path      { stroke: var(--tri-band); }
.pull__triangles use       { fill:   var(--tri-band); }   /* the mark, same as its outlines */
/* THE COLOUR WAS NEVER WRONG. --band-ink and --line-band both resolve to
   var(--light), so the + has always been the same #eee as the ring around it.
   It RENDERED grey, which is a different problem with a different fix.

   The svg is 12px drawn from a 24-unit viewBox, so everything is at half
   scale. The vertical line sits at x=12, which renders at x=6.0, and
   stroke-width 2 renders as 1px -- spanning 5.5 to 6.5. That is half of pixel
   5 and half of pixel 6: two half-lit pixels, and half of #eee over #113 is
   grey. A 1px line is only crisp when its centre lands on a HALF integer, and
   this one is centred on a whole one.

   stroke-width 4 renders as 2px, spanning 5.0 to 7.0 -- pixels 5 and 6 at
   full coverage, nothing partial, solid #eee. It also matches the ring, which
   went to 2px for the related reason that a 1px curve can never be solid at
   all. The earlier note here about keeping the detail lighter than its
   container assumed the 1px line was actually being drawn; it was not.
   2026-09-14. */
.faq__icon svg             { stroke: var(--band-ink); stroke-width: 4; }
.tree__badge svg           { stroke: var(--dark); fill: none; stroke-width: 1.5;
                             stroke-linecap: round; stroke-linejoin: round;
                             width: var(--icon); height: var(--icon); }  /* on the gold disc */

/* ---------- Phone: one field per row ----------
   The binding constraint is NOT the label. "Number of employees*" needs
   164.0px, but HubSpot'"'"'s validation message -- "* Please complete this
   required field." -- needs 217.6px, and it appears in the same column.
   Sizing to the label left a dead band from 480 to ~570px where the
   columns fitted and the error wrapped to two lines.

   600px, from the measurement: a stacked-hero card gives each field
   (vw - 130) / 2, which crosses 217.6px at a viewport of ~573. Round up
   for slack. If that message text ever changes, re-measure.

   This lives at the END of the file on purpose. It shares its selector
   and specificity (0,4,1) with the form-columns-2 rule above, and a
   media query adds no specificity, so source order is the only thing
   that decides. Higher up the page it lost, and the stacked pairs kept
   the 8px desktop gutter instead of the 6px vertical rhythm. -------- */
@media (max-width: 600px) {
  .apply-card .hs-form-private fieldset.form-columns-2 {
    flex-direction: column;
    gap: 6px;                 /* matches fieldset margin-bottom */
  }
  .apply-card .hs-form-private fieldset.form-columns-2 .hs-form-field {
    flex: 0 0 auto; width: 100%;
  }
}

/* ---------- The closing panel  (landscape, real screens only) --------
   The mirror of the hero. .hero is min-height: 100dvh - --nav-h, so the
   nav plus the hero is exactly one viewport and nothing of the next
   section shows until you scroll. This does the same in reverse: at full
   scroll the founding section starts exactly at the viewport top and the
   footer closes it out, with no sliver of the FAQ hanging above.

   The arithmetic: page height H, scroll bottoms out at H - vh. Founding
   top sits at H - footer - founding = H - fh - (vh - fh) = H - vh. The
   two land on the same pixel by construction, not by tuning.

   Landscape only, and only on a real screen. The founding section is
   three small things -- a heading, a line of copy, a button -- and
   stretching that to fill a tall portrait viewport leaves a lake of
   empty ground. min-height guards a landscape phone, which is landscape
   but far too short for this to read as anything but a gap. */
@media (orientation: landscape) and (min-width: 1024px) and (min-height: 600px) {
  .footer { height: var(--footer-h); }
  .founding {
    min-height: calc(100dvh - var(--footer-h));
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
}

/* ---------- Reduced motion ----------
   At the END of the file on purpose. Media queries add no specificity,
   so this competes with the plain .hero__triangles / .pull__triangles
   rules on source order alone. Higher up it lost to whichever animation
   rule came after it -- which is how the pull set kept spinning while
   the hero sat still, and made reduced motion look innocent. -------- */
@media (prefers-reduced-motion: reduce) {
  .hero__triangles, .pull__triangles { animation: none; }
}

/* Close control, top-right INSIDE the card -- where a modal's X sits, which
   is what these are on TAC.

   COLOUR TRAP: .legal__inner is `background: var(--band)`, i.e. the dark
   navy. The nav version used var(--mark), which is ALSO the dark navy --
   correct against the #eee nav, invisible against this card. It has to be
   --band-ink here, the same token the card's own text uses. */
.legal__inner { position: relative; }
.legal__inner .legal__close {
  position: absolute; top: 14px; right: 14px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  border-radius: 8px; color: var(--band-ink); text-decoration: none;
  transition: color 120ms ease-out, background 160ms ease-out;
}
.legal__inner .legal__close svg { width: 19px; height: 19px; display: block; }
.legal__inner .legal__close:hover { color: var(--gold); background: rgba(254, 254, 254, 0.10); }
.legal__inner .legal__close:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* The title must not run under the X. */
.legal__title { padding-right: 44px; }

/* ---------- the Message field ----------------------------------------------
   Added with the Talk With Us form, 2026-09-20. It is the first textarea on any
   of these forms, which is why nothing above accounts for one.

   .hs-input sets height:43px for every field. That is right for a one-line
   input and wrong for a textarea: it arrives a single line tall, and a visitor
   has to notice the drag handle in the corner to discover it is a textarea at
   all. Most will not, and will type one sentence into what looks like a text
   field.

   min-height, NOT height. Two reasons. It clamps the starting size regardless
   of the height above, so there is no specificity fight with the longer
   .apply-card .hs-form-private fieldset .hs-input selector. And it sets a floor
   rather than a size, so the browser still grows the box when someone drags it.

   There is no rows="7" to set. HubSpot builds this element at runtime from the
   form definition, so there is no markup in the page to put an attribute on --
   CSS is the only lever, which is the thing the legacy form buys us.

   Seven rows is the proportion John arrived at by dragging it on the live page.
   ------------------------------------------------------------------------- */
.hs-form textarea.hs-input {
  min-height: calc(7 * 1.5em + 22px);   /* 7 rows, plus .hs-input's 11px padding top and bottom */
  line-height: 1.5;
  resize: vertical;                     /* horizontal drag would break the column */
}
