/* Ocho design system. One family, Apple-grade neutrals, one accent, one motif (the eight). */
:root{
  --white:#ffffff; --ink:#1d1d1f; --ink-2:#6e6e73; --ground:#f5f5f7; --line:#d2d2d7;
  --black:#000000; --accent:#2d5bff; --accent-ink:#1a3fd6; --ok:#1f9d55;
  --font:-apple-system,BlinkMacSystemFont,"SF Pro Display","SF Pro Text","Inter","Helvetica Neue",Helvetica,Arial,sans-serif;
  --max:980px; --wide:1200px; --nav:48px; --r:18px; --r-sm:12px;
}
*{box-sizing:border-box} html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto} *,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important}}
body{margin:0;background:var(--white);color:var(--ink);font-family:var(--font);font-size:17px;line-height:1.47;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
a{color:var(--accent);text-decoration:none} a:hover{text-decoration:underline}
img{max-width:100%;height:auto;display:block}
h1,h2,h3,h4{margin:0;font-weight:600;letter-spacing:-.015em;line-height:1.08}
h1{font-size:clamp(40px,7vw,80px);font-weight:700;letter-spacing:-.03em}
h2{font-size:clamp(32px,4.6vw,56px);letter-spacing:-.025em}
h3{font-size:clamp(22px,2.4vw,28px)} h4{font-size:19px}
p{margin:0}
.lede{font-size:clamp(19px,2.2vw,28px);line-height:1.3;color:var(--ink-2);font-weight:400;letter-spacing:-.01em}
.small{font-size:14px;color:var(--ink-2);line-height:1.45}
:focus-visible{outline:3px solid var(--accent);outline-offset:3px;border-radius:6px}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* nav */
.nav{position:sticky;top:0;z-index:50;height:var(--nav);background:rgba(255,255,255,.72);backdrop-filter:saturate(180%) blur(20px);-webkit-backdrop-filter:saturate(180%) blur(20px);border-bottom:1px solid rgba(0,0,0,.08)}
.nav-in{max-width:var(--max);margin:0 auto;height:100%;display:flex;align-items:center;justify-content:space-between;padding:0 22px}
.nav-mark{display:flex;align-items:center;gap:10px;color:var(--ink);font-weight:600;font-size:15px}
.nav-mark img{height:22px;width:auto}
.nav-links{display:flex;gap:28px;align-items:center;list-style:none;margin:0;padding:0}
.nav-links a{color:var(--ink);font-size:14px;opacity:.85} .nav-links a:hover{opacity:1;text-decoration:none}
.nav.dark{background:rgba(0,0,0,.72);border-bottom-color:rgba(255,255,255,.12)} .nav.dark .nav-mark,.nav.dark .nav-links a{color:#f5f5f7}
@media (max-width:760px){.nav-links li.hide-m{display:none}}

/* buttons */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:44px;padding:10px 22px;border-radius:980px;font:inherit;font-size:16px;font-weight:500;border:1px solid transparent;cursor:pointer;transition:background .15s,color .15s,border-color .15s,transform .15s;white-space:nowrap}
.btn:hover{text-decoration:none}
.btn-primary{background:var(--accent);color:#fff} .btn-primary:hover{background:var(--accent-ink)}
.btn-ink{background:var(--ink);color:#fff} .btn-ink:hover{background:#000}
.btn-ghost{background:transparent;color:var(--accent);border-color:var(--accent)} .btn-ghost:hover{background:var(--accent);color:#fff}
.btn-light{background:#fff;color:var(--ink);border-color:var(--line)} .btn-light:hover{border-color:var(--ink)}
.btn:active{transform:scale(.985)}
.btn-lg{min-height:52px;padding:13px 30px;font-size:17px}
.link{font-weight:500} .link::after{content:" \203A";font-weight:600}

/* sections */
.section{padding:clamp(72px,10vw,140px) 22px}
.section.tight{padding-top:clamp(48px,6vw,80px);padding-bottom:clamp(48px,6vw,80px)}
.section.ground{background:var(--ground)} .section.black{background:var(--black);color:#f5f5f7}
.section.black .lede,.section.black .small{color:#a1a1a6}
.wrap{max-width:var(--max);margin:0 auto} .wrap-wide{max-width:var(--wide);margin:0 auto}
.center{text-align:center} .stack{display:flex;flex-direction:column;gap:18px}
.eyebrow-less{margin-bottom:14px}
.grid{display:grid;gap:18px}
.grid-2{grid-template-columns:repeat(2,1fr)} .grid-3{grid-template-columns:repeat(3,1fr)} .grid-4{grid-template-columns:repeat(4,1fr)}
@media (max-width:900px){.grid-3,.grid-4{grid-template-columns:repeat(2,1fr)}}
@media (max-width:600px){.grid-2,.grid-3,.grid-4{grid-template-columns:1fr}}

/* tiles: Apple grey tiles, radius by hierarchy (28 hero tile, 18 standard, 12 inner) */
.tile{background:var(--ground);border-radius:var(--r);padding:34px 30px;display:flex;flex-direction:column;gap:10px;min-height:220px}
.tile.white{background:#fff;border:1px solid var(--line)}
.tile.dark{background:#000;color:#f5f5f7} .tile.dark .small{color:#a1a1a6}
.tile.span-2{grid-column:span 2} @media (max-width:600px){.tile.span-2{grid-column:span 1}}
.tile h3{margin-bottom:4px} .tile .n{font-size:15px;font-weight:600;color:var(--ink-2);letter-spacing:.01em}
.tile.dark .n{color:#86868b}
.tile .foot{margin-top:auto;padding-top:12px}

/* hero */
.hero{padding:clamp(72px,11vw,150px) 22px clamp(56px,8vw,100px);text-align:center}
.hero .lede{max-width:720px;margin:22px auto 0}
.hero .cta{display:flex;gap:14px;justify-content:center;flex-wrap:wrap;margin-top:34px}
.hero-mark{width:min(320px,60vw);margin:0 auto 34px}

/* the eight: figure-eight motif */
.eight{width:min(760px,92vw);margin:0 auto;display:block}
.eight path.loop{fill:none;stroke:var(--ink);stroke-width:2.5;stroke-linecap:round;stroke-dasharray:2400;stroke-dashoffset:2400;animation:draw 2.4s cubic-bezier(.65,0,.35,1) .2s forwards}
.eight path.pulse{fill:none;stroke:var(--accent);stroke-width:5;stroke-linecap:round;stroke-dasharray:60 2400;stroke-dashoffset:2400;animation:travel 3.6s linear 2.4s infinite}
.eight text{font-family:var(--font);font-size:15px;font-weight:500;fill:var(--ink);opacity:0;animation:appear .6s ease forwards}
.eight text:nth-of-type(1){animation-delay:.6s}.eight text:nth-of-type(2){animation-delay:.9s}.eight text:nth-of-type(3){animation-delay:1.2s}.eight text:nth-of-type(4){animation-delay:1.5s}.eight text:nth-of-type(5){animation-delay:1.8s}.eight text:nth-of-type(6){animation-delay:2.1s}.eight text:nth-of-type(7){animation-delay:2.4s}.eight text:nth-of-type(8){animation-delay:2.7s}
@keyframes draw{to{stroke-dashoffset:0}} @keyframes travel{to{stroke-dashoffset:0}} @keyframes appear{to{opacity:1}}
@media (prefers-reduced-motion:reduce){.eight path.loop{stroke-dashoffset:0;animation:none}.eight path.pulse{display:none}.eight text{opacity:1;animation:none}}
.section.black .eight path.loop{stroke:#f5f5f7} .section.black .eight text{fill:#f5f5f7}

/* jobs list */
.jobs{display:grid;grid-template-columns:repeat(4,1fr);gap:14px 18px;counter-reset:job}
@media (max-width:900px){.jobs{grid-template-columns:repeat(2,1fr)}} @media (max-width:520px){.jobs{grid-template-columns:1fr}}
.job{padding:22px 0 18px;border-top:1px solid var(--line);counter-increment:job}
.job::before{content:counter(job);display:block;font-size:40px;font-weight:700;letter-spacing:-.04em;line-height:1;margin-bottom:10px;color:var(--ink)}
.job h4{margin-bottom:6px} .job p{color:var(--ink-2);font-size:15px;line-height:1.45}
.section.black .job{border-top-color:#333336} .section.black .job::before,.section.black .job h4{color:#f5f5f7} .section.black .job p{color:#a1a1a6}

/* forms */
.field{display:flex;flex-direction:column;gap:6px} .field label{font-size:14px;font-weight:500}
.input,select.input,textarea.input{font:inherit;font-size:16px;min-height:46px;padding:11px 14px;border:1px solid var(--line);border-radius:var(--r-sm);background:#fff;color:var(--ink);width:100%}
textarea.input{min-height:120px;padding:13px 15px;resize:vertical}
.input:focus{border-color:var(--accent);outline:none;box-shadow:0 0 0 4px rgba(45,91,255,.15)}
.row{display:flex;gap:12px;flex-wrap:wrap} .row>*{flex:1 1 220px}
.hint{font-size:13px;color:var(--ink-2)}
.notice{border-radius:var(--r-sm);padding:13px 16px;font-size:15px;background:var(--ground)}
.notice.ok{background:#e9f7ee;color:#0f5a30} .notice.err{background:#fdecec;color:#8a1c1c}

/* pulse tool */
.pulse-q{padding:0 0 22px;border-top:1px solid var(--line)} .pulse-q:first-of-type{border-top:0}
.pulse-q legend{font-weight:600;font-size:18px;padding:22px 0 12px}
.scale{display:flex;gap:8px;flex-wrap:wrap}
.scale label{flex:1 1 90px;text-align:center;border:1px solid var(--line);border-radius:12px;padding:12px 14px;cursor:pointer;font-size:14px;line-height:1.3;background:#fff}
.scale input{position:absolute;opacity:0;pointer-events:none}
.scale input:checked+span{color:#fff} .scale label:has(input:checked){background:var(--ink);border-color:var(--ink);color:#fff}
.scale label:has(input:focus-visible){outline:3px solid var(--accent);outline-offset:2px}
.bars{display:flex;flex-direction:column;gap:12px}
.bar{display:grid;grid-template-columns:150px 1fr 48px;align-items:center;gap:12px;font-size:15px}
.bar .track{height:10px;background:#e8e8ed;border-radius:6px;overflow:hidden} .bar .fill{height:100%;background:var(--ink);border-radius:6px;transition:width .6s ease}
.bar.weak .fill{background:var(--accent)} .bar .v{text-align:right;font-variant-numeric:tabular-nums;color:var(--ink-2)}
@media (max-width:520px){.bar{grid-template-columns:110px 1fr 40px}}

/* insights */
.posts{display:grid;grid-template-columns:repeat(2,1fr);gap:18px} @media (max-width:700px){.posts{grid-template-columns:1fr}}
.post{background:#fff;border:1px solid var(--line);border-radius:var(--r);padding:28px 28px 24px;display:flex;flex-direction:column;gap:10px}
.post .meta{font-size:13px;color:var(--ink-2)} .post h3{font-size:22px} .post p{color:var(--ink-2);font-size:15.5px}
.post a.link{margin-top:auto;padding-top:8px}
.article{max-width:680px;margin:0 auto} .article p{margin:0 0 22px;font-size:19px;line-height:1.55} .article h2{font-size:30px;margin:44px 0 14px} .article h3{margin:32px 0 10px} .article ul,.article ol{font-size:19px;line-height:1.55;margin:0 0 22px;padding-left:24px} .article li{margin-bottom:8px}
.article blockquote{margin:0 0 22px;padding-left:20px;border-left:3px solid var(--ink);font-size:21px;line-height:1.45;color:var(--ink)}

/* footer */
.footer{background:var(--ground);padding:40px 22px;font-size:13px;color:var(--ink-2);border-top:1px solid var(--line)}
.footer .wrap{display:flex;flex-direction:column;gap:14px}
.footer ul{list-style:none;margin:0;padding:0;display:flex;gap:20px;flex-wrap:wrap} .footer a{color:var(--ink-2)}
.footer .legal{max-width:760px;line-height:1.5}

/* app (ocho.tools) */
.app{display:grid;grid-template-columns:240px 1fr;min-height:100vh}
.side{background:var(--ground);border-right:1px solid var(--line);padding:22px 16px;display:flex;flex-direction:column;gap:6px;position:sticky;top:0;height:100vh}
.side .brand{padding:6px 10px 18px} .side .brand img{height:20px}
.side a{display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:10px;color:var(--ink);font-size:15px}
.side a:hover{background:#e8e8ed;text-decoration:none} .side a.on{background:var(--ink);color:#fff}
.side a .st{margin-left:auto;font-size:11px;color:var(--ink-2);background:#e8e8ed;border-radius:6px;padding:4px 9px} .side a.on .st{background:#333;color:#ddd}
.side .bottom{margin-top:auto;font-size:13px;color:var(--ink-2);padding:0 10px}
.main{padding:34px 40px;max-width:1100px;width:100%}
.main h1{font-size:34px;letter-spacing:-.02em;margin-bottom:6px}
.main .sub{color:var(--ink-2);margin-bottom:30px}
.mods{display:grid;grid-template-columns:repeat(3,1fr);gap:14px} @media (max-width:1000px){.mods{grid-template-columns:repeat(2,1fr)}} @media (max-width:640px){.mods{grid-template-columns:1fr}}
.mod{border:1px solid var(--line);border-radius:14px;padding:22px 20px;display:flex;flex-direction:column;gap:8px;background:#fff;min-height:150px}
.mod h3{font-size:18px} .mod p{color:var(--ink-2);font-size:14.5px} .mod .foot{margin-top:auto;display:flex;justify-content:space-between;align-items:center;font-size:13px;color:var(--ink-2)}
.pill{font-size:12px;font-weight:500;border-radius:6px;padding:5px 10px;background:var(--ground);color:var(--ink-2)} .pill.live{background:#e9f7ee;color:#0f5a30} .pill.beta{background:#eef2ff;color:var(--accent-ink)}
@media (max-width:860px){.app{grid-template-columns:1fr}.side{position:static;height:auto;flex-direction:row;flex-wrap:wrap;border-right:0;border-bottom:1px solid var(--line)}.side .brand{width:100%;padding-bottom:8px}.side .bottom{display:none}.main{padding:22px}}
/* chat */
.chat{display:flex;flex-direction:column;height:calc(100vh - 68px);max-width:820px}
.chat .log{flex:1;overflow:auto;display:flex;flex-direction:column;gap:14px;padding:10px 4px 20px}
.msg{max-width:88%;padding:12px 16px;border-radius:16px;font-size:16px;line-height:1.5;white-space:pre-wrap}
.msg.me{align-self:flex-end;background:var(--ink);color:#fff;border-bottom-right-radius:6px}
.msg.ai{align-self:flex-start;background:var(--ground);border-bottom-left-radius:6px}
.msg .src{display:block;margin-top:8px;font-size:13px;color:var(--ink-2)} .msg.ai .src a{display:block}
.chat form{display:flex;gap:10px;padding:12px 0 0;border-top:1px solid var(--line)}
.chat textarea{flex:1;min-height:52px;max-height:160px}
.gate{min-height:100vh;display:grid;place-items:center;padding:22px;background:var(--ground)}
.gate .card{background:#fff;border-radius:22px;padding:44px 40px;width:min(420px,100%);display:flex;flex-direction:column;gap:18px;border:1px solid var(--line)}
.gate img{height:26px;width:auto}
/* nav buttons must win over .nav-links a color */
.nav-links a.btn-ink{color:#fff} .nav-links a.btn-ink:hover{background:#000}
.nav.dark .nav-links a.btn-light{color:var(--ink)} .nav.dark .nav-links a.btn-light:hover{border-color:#fff}

/* referral readiness audit */
.audit-bar{display:flex;gap:10px;max-width:520px;margin:34px auto 0;flex-wrap:wrap}
.audit-bar .input{flex:1 1 240px;height:52px;font-size:17px;text-align:center}
.audit-bar .btn{flex:0 0 auto}
@media (max-width:520px){.audit-bar .btn{width:100%}}
#audit-out{max-width:760px;margin:44px auto 0;text-align:left}
.score-head{display:flex;align-items:baseline;gap:16px;flex-wrap:wrap;margin-bottom:8px}
.score-num{font-size:clamp(56px,10vw,88px);font-weight:700;letter-spacing:-.04em;line-height:1}
.score-band{font-size:22px;font-weight:600;letter-spacing:-.01em}
.score-meter{height:8px;border-radius:5px;background:#e8e8ed;overflow:hidden;margin:18px 0 22px}
.score-meter i{display:block;height:100%;border-radius:5px;background:var(--ink);width:0;transition:width .9s cubic-bezier(.22,1,.36,1)}
.score-read{font-size:18px;line-height:1.5;color:var(--ink);margin-bottom:34px}
.chk{border-top:1px solid var(--line);padding:20px 0;display:grid;grid-template-columns:26px 1fr;gap:14px;align-items:start}
.chk .mark{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;font-size:13px;font-weight:700;margin-top:2px}
.chk.pass .mark{background:#e9f7ee;color:#0f5a30}
.chk.miss .mark{background:var(--ink);color:#fff}
.chk h4{font-size:17px;margin-bottom:4px}
.chk .found{font-size:14.5px;color:var(--ink-2);line-height:1.45}
.chk .fix{font-size:15px;line-height:1.5;margin-top:10px;padding:14px 16px;background:var(--ground);border-radius:12px}
.chk .wt{font-size:12px;color:var(--ink-2);font-weight:500}
.audit-cta{margin-top:36px;padding-top:28px;border-top:1px solid var(--line)}
#audit-out{scroll-margin-top:70px}

/* Bounding boxes inset their text, always.
   The browser's default fieldset draws a border and hangs the legend on it, which put the
   Practice Pulse question text directly on the line. Reset that here rather than papering
   over it per component, and give every box a floor so this class of bug cannot come back. */
fieldset{border:0;margin:0;padding:0;min-width:0}
/* A legend is not laid out like a normal child: browsers pin it to the fieldset's border
   edge and ignore the fieldset's padding, which is why the question text sat on the rule.
   Floating it fixes the gap but drags the following flex row out of place, so the inset
   goes on the legend itself instead. */
legend{width:100%;margin:0}
.tile,.mod,.post,.notice,.msg,.chk .fix,.gate .card,.pulse-q,.scale label{overflow-wrap:break-word}
.nav-links .btn{min-height:32px;padding:6px 14px;font-size:13px}

/* ============================================================================
   Ocho glass: a pop of colour and light against the black and white.
   Reserved for the primary action in a view, and for Ocho himself, so it stays
   an event rather than wallpaper. The film, grit and rim layers are injected by
   ocho-glass.js, so markup stays <button class="btn btn-glass">Label</button>.
   ========================================================================= */
.btn-glass{
  --r:980px;
  position:relative;isolation:isolate;overflow:hidden;border:0;color:#fff;
  border-radius:var(--r);clip-path:inset(0 round var(--r));
  background:
    radial-gradient(58% 30% at 50% -4%, rgba(255,255,255,.98) 0%, rgba(255,255,255,.5) 22%, rgba(255,255,255,0) 55%),
    linear-gradient(168deg, rgba(255,255,255,0) 34%, rgba(255,255,255,.20) 41%, rgba(255,255,255,.03) 46%, rgba(255,255,255,0) 52%),
    radial-gradient(115% 80% at 50% 118%, rgba(255,186,88,.34) 0%, rgba(255,120,185,.10) 46%, rgba(0,0,0,0) 76%),
    radial-gradient(115% 150% at 50% 34%, #3b3159 0%, #1d1830 44%, #0b0912 100%);
  box-shadow:
    inset 0 1.5px 0 rgba(255,255,255,.8), inset 0 -12px 24px rgba(0,0,0,.7),
    inset 0 0 24px rgba(255,190,120,.14), inset 0 0 0 1px rgba(255,255,255,.10),
    0 1px 2px rgba(0,0,0,.3), 0 10px 28px -8px rgba(110,60,175,.55);
  transition:transform .15s ease, box-shadow .25s ease;
}
.btn-glass:hover{box-shadow:inset 0 1.5px 0 rgba(255,255,255,.9), inset 0 -12px 24px rgba(0,0,0,.65),
  inset 0 0 30px rgba(255,190,120,.22), inset 0 0 0 1px rgba(255,255,255,.14),
  0 1px 2px rgba(0,0,0,.3), 0 14px 34px -8px rgba(130,70,200,.7)}
.btn-glass:active{transform:scale(.985)}

/* Leaning in.

   The glass should read as having something behind it rather than a picture printed
   on it, so the layers travel different distances: the nebula is far and barely grows,
   the star dust is nearer and rushes at you, and the gloss is the surface itself so it
   hardly moves at all. Parallax is the whole trick; a uniform zoom would just look
   like the image got bigger.

   The films already carry a drift animation, and an animation's transform beats a
   hover rule. So the zoom uses the independent `scale` and `rotate` properties, which
   compose with the animation's transform instead of fighting it. */
@media (hover:hover){
  .btn-glass{transition:transform .5s cubic-bezier(.22,1,.36,1), box-shadow .25s ease}
  /* The vignette is what makes it read as looking INTO something: the rim lights and
     the centre stays deep, which is also what keeps white type legible while the
     colour fields open up behind it. */
  .btn-glass:hover{transform:scale(1.03);
    box-shadow:inset 0 1.5px 0 rgba(255,255,255,.92), inset 0 -12px 24px rgba(0,0,0,.6),
      inset 0 0 34px 12px rgba(0,0,0,.4), inset 0 0 30px rgba(255,190,120,.24),
      inset 0 0 0 1px rgba(255,255,255,.16),
      0 1px 2px rgba(0,0,0,.3), 0 16px 38px -8px rgba(130,70,200,.75)}
  .btn-glass:active{transform:scale(.99)}

  .g-film,.g-film2,.g-grit,.g-gloss{
    transition:scale .75s cubic-bezier(.22,1,.36,1), rotate .9s cubic-bezier(.22,1,.36,1),
               opacity .45s ease, filter .55s ease}
  .g-grit{filter:brightness(1)}
  .btn-glass:hover .g-film{scale:1.28;opacity:.64;filter:blur(18px) saturate(260%)}
  .btn-glass:hover .g-film2{scale:1.16;rotate:3deg;opacity:.4;filter:blur(24px) saturate(230%)}
  /* The grit twinkles on its own animation, and an animation beats a hover rule the
     same way it beat the transform. So brighten it with a filter, which nothing is
     animating, and let the twinkle itself run faster. */
  .btn-glass:hover .g-grit{scale:2.1;filter:brightness(1.7);animation-duration:2.4s}
  .btn-glass:hover .g-gloss{scale:1.03;opacity:.92}      /* the surface barely moves */
}
@media (prefers-reduced-motion:reduce){
  .btn-glass,.g-film,.g-film2,.g-grit,.g-gloss{transition-duration:.001ms}
  .btn-glass:hover{transform:none}
  .btn-glass:hover .g-film,.btn-glass:hover .g-film2,
  .btn-glass:hover .g-grit,.btn-glass:hover .g-gloss{scale:1;rotate:0deg}
}
.btn-glass > .lab{position:relative;z-index:4;text-shadow:0 1px 3px rgba(0,0,0,.6)}
/* Only the label is ever in the flow. A decorative layer that forgets to position
   itself becomes a flex item and moves the text, which is how the label drifted. */
.btn-glass > [aria-hidden="true"]{position:absolute}
.g-film{position:absolute;inset:-40%;z-index:1;pointer-events:none;
  background:
    radial-gradient(38% 54% at 20% 28%, rgba(255,198,96,.9), transparent 70%),
    radial-gradient(34% 48% at 66% 22%, rgba(255,126,192,.75), transparent 70%),
    radial-gradient(42% 58% at 80% 68%, rgba(108,190,255,.72), transparent 70%),
    radial-gradient(36% 50% at 32% 76%, rgba(124,255,208,.62), transparent 70%),
    radial-gradient(30% 44% at 52% 50%, rgba(198,150,255,.6), transparent 70%);
  filter:blur(18px) saturate(200%);opacity:.46;mix-blend-mode:overlay;
  animation:g-drift 19s ease-in-out infinite alternate}
.g-film2{position:absolute;inset:-30%;z-index:1;pointer-events:none;
  background:
    radial-gradient(40% 56% at 74% 34%, rgba(255,214,124,.8), transparent 72%),
    radial-gradient(36% 50% at 26% 62%, rgba(255,150,210,.6), transparent 72%),
    radial-gradient(44% 60% at 54% 82%, rgba(140,205,255,.55), transparent 72%);
  filter:blur(24px) saturate(180%);opacity:.28;mix-blend-mode:screen;
  animation:g-drift2 27s ease-in-out infinite alternate}
.g-gloss{position:absolute;left:0;right:0;top:0;height:58%;z-index:2;pointer-events:none;
  border-radius:inherit;
  background:linear-gradient(180deg, rgba(255,255,255,.55) 0%, rgba(255,255,255,.22) 38%, rgba(255,255,255,.06) 70%, rgba(255,255,255,0) 100%);
  -webkit-mask:radial-gradient(120% 100% at 50% 0%, #000 40%, transparent 78%);
          mask:radial-gradient(120% 100% at 50% 0%, #000 40%, transparent 78%)}
.g-gloss::after{content:"";position:absolute;left:8%;right:8%;bottom:-6%;height:34%;
  background:linear-gradient(0deg, rgba(255,225,180,.30), rgba(255,255,255,0));
  filter:blur(5px)}
/* The grit was injected as a span with no rule of its own, which made it a flex item in
   the button and pushed the label 8px off centre. It is absolute like its siblings now,
   and it finally carries the sparkle it was named for: a fine dust that catches the
   light rather than a texture you can name. */
.g-grit{position:absolute;inset:0;z-index:2;pointer-events:none;border-radius:inherit;
  background:
    radial-gradient(circle at 18% 26%, rgba(255,255,255,.9) 0, rgba(255,255,255,0) 1.1px),
    radial-gradient(circle at 62% 14%, rgba(255,236,190,.85) 0, rgba(255,255,255,0) 1px),
    radial-gradient(circle at 84% 58%, rgba(255,255,255,.75) 0, rgba(255,255,255,0) 1.2px),
    radial-gradient(circle at 34% 72%, rgba(210,235,255,.8) 0, rgba(255,255,255,0) 1px),
    radial-gradient(circle at 71% 84%, rgba(255,255,255,.7) 0, rgba(255,255,255,0) 1.1px),
    radial-gradient(circle at 46% 44%, rgba(255,214,160,.7) 0, rgba(255,255,255,0) 1px);
  background-size:19px 15px,22px 16px,16px 19px,15px 21px,21px 14px,24px 17px;
  mix-blend-mode:screen;opacity:.5;
  animation:g-grit 6.5s ease-in-out infinite}
.g-rim{position:absolute;inset:0;border-radius:inherit;padding:1.2px;pointer-events:none;z-index:3;
  background:linear-gradient(135deg,#ffe9a8 0%,#ffb0df 26%,#bda4ff 50%,#7ce3ff 72%,#a6ffdc 100%);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;opacity:.5;filter:saturate(140%)}
@keyframes g-drift{0%{transform:translate3d(-4%,-3%,0) scale(1.06)}
  50%{transform:translate3d(3%,2%,0) scale(1.14)}
  100%{transform:translate3d(-2%,4%,0) scale(1.07)}}
@keyframes g-drift2{0%{transform:translate3d(3%,2%,0) scale(1.1)}
  50%{transform:translate3d(-3%,-2%,0) scale(1.02)}
  100%{transform:translate3d(2%,-3%,0) scale(1.12)}}
@keyframes g-spin{to{transform:rotate(1turn)}}
/* Resting sparkle is a suggestion, not a texture. The reveal belongs to hover. */
@keyframes g-grit{0%,100%{opacity:.22}50%{opacity:.52}}

/* ---- Ocho himself: the pill becomes a panel and the line rises out of it ---- */
.btn.ocho{--w:196px;--h:48px;--r:980px;width:var(--w);height:var(--h);padding:0;
  font-size:16px;font-weight:500;cursor:pointer;display:block;
  transition:width .6s cubic-bezier(.22,1,.36,1), height .6s cubic-bezier(.22,1,.36,1),
             border-radius .6s cubic-bezier(.22,1,.36,1), clip-path .6s cubic-bezier(.22,1,.36,1), box-shadow .25s ease}
.btn.ocho .lab{position:absolute;inset:0;display:grid;place-items:center;
  transition:opacity .28s ease, transform .5s cubic-bezier(.22,1,.36,1)}
.btn.ocho .bustwrap{position:absolute;left:0;right:0;bottom:0;z-index:4;display:grid;place-items:end center;
  pointer-events:none;transform:translateY(102%);opacity:0;
  transition:transform .65s cubic-bezier(.22,1,.36,1), opacity .3s ease}
.btn.ocho .bust{height:132px;width:auto;display:block;overflow:visible;margin-bottom:-4px;
  filter:url(#ochoUndulate) drop-shadow(0 0 6px rgba(255,214,150,.35))}
.btn.ocho .bust path{fill:url(#ochoStroke);stroke:none}
.btn.ocho .state{position:absolute;left:0;right:0;top:12px;z-index:5;text-align:center;font-size:10.5px;
  letter-spacing:.09em;text-transform:uppercase;color:rgba(255,255,255,.6);opacity:0;transition:opacity .3s ease .35s}
.btn.ocho.on{--w:214px;--h:168px;--r:28px}
.btn.ocho.on .lab{opacity:0;transform:translateY(-16px)}
.btn.ocho.on .bustwrap{transform:translateY(0);opacity:1}
.btn.ocho.on .state{opacity:1}
@keyframes g-draw{to{stroke-dashoffset:0}}

@media (prefers-reduced-motion:reduce){
  .g-film,.g-film2,.g-rim,.g-grit{animation:none}
  .btn.ocho,.btn.ocho .lab,.btn.ocho .bustwrap{transition-duration:.001ms}
}

/* the eight jobs: labels sit on the outer arc of each lobe, never across the line */
.eight-wrap{position:relative;max-width:820px;margin:0 auto}
/* Without this the diagram keeps its intrinsic width and spills the gutter. */
.eight-wrap svg.eight{display:block;width:100%;height:auto}
.eight-list{display:none}
.eight text{font-family:var(--font);font-size:15px;font-weight:500;fill:var(--ink);
  paint-order:stroke;stroke:var(--ground);stroke-width:5px;stroke-linejoin:round}
.section.ground .eight text{stroke:var(--ground)}
.eight .node-dot{fill:var(--ink)}
.eight .leader{stroke:var(--line);stroke-width:1.5}
.eight .job-node{cursor:help}
.eight .job-node text{transition:fill .18s ease}
.eight .job-node:hover text,.eight .job-node:focus-visible text{fill:var(--accent-ink)}
.eight .job-node:hover .node-dot,.eight .job-node:focus-visible .node-dot{fill:var(--accent)}
.eight .job-node:focus{outline:none}
.eight .job-node:focus-visible .node-dot{r:6}
.job-tip{position:absolute;z-index:20;width:min(330px,84vw);background:#fff;color:var(--ink);
  border:1px solid var(--line);border-radius:16px;padding:20px 22px;
  box-shadow:0 18px 44px -12px rgba(0,0,0,.28);text-align:left}
.job-tip h4{font-size:16px;margin-bottom:8px}
.job-tip .felt{font-size:14.5px;line-height:1.5;color:var(--ink-2);margin-bottom:12px}
.job-tip .does{font-size:14.5px;line-height:1.5;color:var(--ink)}
.job-tip .does span{font-weight:600}
/* The loop becomes a list. The swap point is the width at which the diagram can run
   at its full 820px: any narrower and the viewBox scales the 15-unit labels below
   13 CSS px, where the halo stroke starts eating the letterforms. Rows are 56px so
   they take a thumb, the copy is the tip's own copy, one panel open at a time. */
@media (max-width:820px){
  .eight-wrap svg.eight{display:none}
  .job-tip{display:none!important}
  .eight-list{display:block;border-top:1px solid var(--line)}
  .eight-job{border-bottom:1px solid var(--line)}
  .eight-job > button{display:flex;align-items:center;justify-content:space-between;gap:16px;
    width:100%;min-height:56px;padding:15px 2px;margin:0;background:none;border:0;
    font:inherit;font-size:17px;font-weight:600;color:var(--ink);text-align:left;cursor:pointer}
  .eight-job > button:focus-visible{outline:3px solid var(--accent);outline-offset:-3px;border-radius:8px}
  .eight-job > button .sign{flex:0 0 auto;position:relative;width:20px;height:20px;opacity:.4}
  .eight-job > button .sign::before,.eight-job > button .sign::after{content:"";position:absolute;
    left:50%;top:50%;background:currentColor;transform:translate(-50%,-50%)}
  .eight-job > button .sign::before{width:13px;height:1.5px}
  .eight-job > button .sign::after{width:1.5px;height:13px;transition:transform .2s ease}
  .eight-job[data-open] > button{color:var(--accent-ink)}
  .eight-job[data-open] > button .sign{opacity:.75}
  .eight-job[data-open] > button .sign::after{transform:translate(-50%,-50%) scaleY(0)}
  .eight-job .panel{padding:0 2px 22px}
  .eight-job .panel .felt{font-size:15.5px;line-height:1.55;color:var(--ink-2);margin-bottom:12px}
  .eight-job .panel .does{font-size:15.5px;line-height:1.55;color:var(--ink)}
  .eight-job .panel .does span{font-weight:600}
}


/* Contrast rule: a dark surface always carries light text. An inline colour on a link
   (color:inherit on a card that is itself a link) was pulling the page's dark ink onto
   black, so these are scoped to text elements and never touch a button's own colour. */
.tile.dark,.section.black,.gate .card.dark{color:#f5f5f7}
.tile.dark h1,.tile.dark h2,.tile.dark h3,.tile.dark h4,.tile.dark p,.tile.dark li,
.section.black h1,.section.black h2,.section.black h3,.section.black h4,.section.black p,.section.black li{color:#f5f5f7}
.tile.dark .small,.tile.dark .n,.tile.dark .foot,
.section.black .small,.section.black .lede,.section.black .n,.section.black .foot{color:#a1a1a6}
.tile.dark a:not(.btn),.section.black a:not(.btn){color:#f5f5f7}

/* [hidden] must beat .btn, which wins a specificity tie on source order. */
[hidden]{display:none!important}


/* ─────────────────────────────────────────────────────────────────────────
   Touch. Measured on a 390px viewport, not assumed.

   The chrome was built for a cursor: the nav mark was 22px tall, the nav links
   17px, the footer links 15px. A finger pad is about 44px across, so every one
   of those was a guess rather than a tap. The ink stays the size it is; the box
   around it grows. That is why these set min-height and padding instead of
   font-size, and why they only apply where there is no hover to fall back on.
   ───────────────────────────────────────────────────────────────────────── */
@media (hover:none),(max-width:760px){
  .nav-in{padding:0 16px}
  .nav-mark{min-height:44px}
  .nav-links{gap:2px}
  .nav-links a{display:inline-flex;align-items:center;min-height:44px;padding:0 10px}
  .nav-links .btn{min-height:44px;padding:0 16px;font-size:14px}
  .footer ul{gap:0 18px}
  .footer a{display:inline-flex;align-items:center;min-height:44px}
  /* "Read the source" sits at the end of every search hit and is the one thing
     on that card anyone taps. */
  a.link{display:inline-flex;align-items:center;min-height:44px}
}
