/* ============================================================
   ASKN Ltd — Corporate site
   Purple design system, carried over from the ASKN one-pager.

   Display : Plus Jakarta Sans 800, -0.015em, 1.14
   Body    : Inter
   Utility : IBM Plex Mono  (eyebrows, tags, figures)

   Signature: the tick — a hairline that draws down above every
   section eyebrow, implying the sections are one continuous
   system rather than a stack of blocks.
   ============================================================ */

:root{
  --purple:#5E2C93;
  --purple-deep:#33154F;
  --purple-bright:#8B4FD4;
  --ink:#1B1230;
  --ink-soft:#5B5170;
  --ink-faint:#8B8399;
  --lilac:#CDA9EC;
  --lilac-pale:#E9DCFA;
  --paper:#FAF7FC;
  --paper-dim:#F0E9F8;
  --white:#FFFFFF;
  --line:rgba(27,18,48,0.11);
  --line-strong:rgba(27,18,48,0.2);
  --shadow-sm:0 2px 6px -2px rgba(51,21,79,0.10);
  --shadow:0 24px 50px -32px rgba(51,21,79,0.42);
  --radius:16px;
  --ease:cubic-bezier(.22,1,.36,1);
  --util:'IBM Plex Mono',ui-monospace,monospace;

  /* per-pillar accents: each brand wears its own, all clear 5:1 on white */
  /* Each pillar carries its brand's own colour, sampled from the marks.
     The crimson is Stanfords Training, the blue is Nomass.AI. Early Years
     keeps ASKN purple, since Smart Kids has no mark of its own. */
  --early:#5E2C93;   --early-tint:#E9DCFA;
  --skills:#9E1C37;  --skills-tint:#F7E9EC;
  --tech:#1B5DAA;    --tech-tint:#E4EDF9;

  /* type ladder — nothing sits off it */
  --t-2xs:0.6875rem; --t-xs:0.8125rem; --t-sm:0.875rem; --t-base:1rem;
  --t-md:1.125rem;   --t-lg:1.375rem;  --t-xl:1.75rem;
  --t-2xl:clamp(1.9rem, 3vw, 2.5rem);
  --t-3xl:clamp(2.3rem, 4vw, 3.4rem);

  --max:1180px;
  font-size:16px;
}

*{box-sizing:border-box; margin:0; padding:0;}
html{scroll-behavior:smooth; -webkit-text-size-adjust:100%; text-size-adjust:100%;}
body{background:var(--paper); color:var(--ink);
  font-family:'Inter',system-ui,-apple-system,sans-serif; line-height:1.6;
  -webkit-font-smoothing:antialiased;
  /* clip, not hidden: overflow-x:hidden turns the body into a scroll
     container, which silently kills position:sticky inside it */
  overflow-x:clip;}
a{color:inherit; text-decoration:none;}
img,svg{display:block;}
button{font:inherit; cursor:pointer;}
/* Plus Jakarta Sans over Inter, matched to the Nomass.AI site so the two
   properties read as one family of work. Jakarta is softer and a touch wider
   than the grotesque it replaces, so it wants less negative tracking and a
   little more line-height than the previous face did. */
h1,h2,h3,h4,h5,h6{font-family:'Plus Jakarta Sans',system-ui,sans-serif;
  font-weight:800; letter-spacing:-0.015em; line-height:1.14;}
:focus-visible{outline:2px solid var(--purple); outline-offset:3px; border-radius:4px;}

/* off the screen but still in the accessibility tree — for headings the
   artwork already carries, which would otherwise read twice */
.visually-hidden{position:absolute; width:1px; height:1px; margin:-1px;
  padding:0; border:0; overflow:hidden; white-space:nowrap;
  clip:rect(0 0 0 0); clip-path:inset(50%);}

.wrap{max-width:var(--max); margin:0 auto; padding:0 32px;}
section{padding:40px 0; scroll-margin-top:124px; position:relative;}
.section-alt{background:var(--white);}
.section-tight{padding:28px 0 40px;}
.center{text-align:center;}
.mt-lg{margin-top:22px;}
.rule{height:1px; background:var(--line); border:0; margin:34px 0;}

/* ---------- eyebrow ---------- */
.eyebrow{display:block; font-family:var(--util); font-size:var(--t-lg); font-weight:700;
  letter-spacing:0.06em; text-transform:uppercase; color:var(--purple);
  line-height:1.15; margin-bottom:18px;}
/* card-level and strapline eyebrows stay a label: at the section size they
   would sit level with the h3 beside them, or fight the hero h1 */
.info-card .eyebrow{font-size:var(--t-2xs); letter-spacing:0.16em; margin-bottom:10px;}
.hero-eyebrow{font-size:var(--t-2xs); letter-spacing:0.16em; margin-bottom:16px;}

.section-head{max-width:660px; margin-bottom:26px;}
.section-head h2{font-size:var(--t-2xl);}
.section-head p{color:var(--ink-soft); font-size:var(--t-base); margin-top:16px; max-width:58ch;}
.two-col{display:grid; grid-template-columns:0.9fr 1.1fr; gap:56px; align-items:start;}
.two-col p{color:var(--ink-soft); margin-bottom:16px;}
.two-col p:last-child{margin-bottom:0;}

/* ---------- header: glass pill, fixed size ---------- */
.site-header{position:fixed; top:0; left:0; right:0; z-index:50; padding:16px 32px;
  background:transparent;}
.nav{max-width:var(--max); margin:0 auto; position:relative;
  display:grid; grid-template-columns:auto 1fr auto; align-items:center; gap:22px;
  height:70px; padding:0 12px 0 26px; border-radius:999px;
  background:rgba(255,255,255,0.62);
  -webkit-backdrop-filter:blur(16px) saturate(150%); backdrop-filter:blur(16px) saturate(150%);
  border:1px solid rgba(139,79,212,0.14);
  box-shadow:0 10px 30px -16px rgba(51,21,79,0.22), 0 1px 0 rgba(255,255,255,0.9) inset;}

.logo{display:flex; align-items:center; color:var(--purple);}
.brand-logo{height:26px; width:auto; color:currentColor;
  transition:opacity .25s ease;}
a.logo:hover .brand-logo{opacity:0.72;}
.nav-links{display:flex; justify-content:center; gap:22px; list-style:none;}
.nav-links a{font-size:var(--t-sm); font-weight:500; color:var(--ink-soft); white-space:nowrap;
  position:relative; display:flex; align-items:center; min-height:44px; padding:0 2px;
  transition:color .15s ease;}
.nav-links a:hover{color:var(--purple);}
.nav-links a::after{content:""; position:absolute; left:0; right:0; bottom:9px; height:2px;
  border-radius:2px; background:linear-gradient(90deg,var(--purple-deep),var(--purple-bright));
  transform:scaleX(0); transform-origin:right; transition:transform .28s var(--ease);}
.nav-links a:hover::after, .nav-links a.active::after{transform:scaleX(1); transform-origin:left;}
.nav-links a.active{color:var(--purple);}
.nav-cta{font-weight:600; font-size:var(--t-sm); padding:12px 22px; border-radius:100px;
  background:var(--purple); color:#fff; white-space:nowrap;
  transition:background .18s ease, transform .18s var(--ease);}
.nav-cta:hover{background:var(--purple-deep); transform:translateY(-2px);}
.nav-toggle{display:none; width:44px; height:44px; border-radius:12px; flex-shrink:0;
  border:1px solid var(--line-strong); background:transparent; color:var(--ink);
  align-items:center; justify-content:center; flex-direction:column; gap:4px;}
.nav-toggle span{display:block; width:18px; height:2px; border-radius:2px; background:currentColor;
  transition:transform .3s var(--ease), opacity .2s ease;}
.nav-toggle[aria-expanded="true"] span:nth-child(1){transform:translateY(6px) rotate(45deg);}
.nav-toggle[aria-expanded="true"] span:nth-child(2){opacity:0;}
.nav-toggle[aria-expanded="true"] span:nth-child(3){transform:translateY(-6px) rotate(-45deg);}
.mobile-panel{display:none;}

/* ---------- buttons ---------- */
.btn{display:inline-flex; align-items:center; gap:9px; font-weight:600; font-size:var(--t-sm);
  padding:13px 26px; border-radius:100px; border:1px solid transparent;
  transition:background .18s ease, color .18s ease, border-color .18s ease,
             box-shadow .18s ease, transform .18s var(--ease);}
.btn:hover{transform:translateY(-2px);}
.btn:active{transform:translateY(0) scale(.985);}
.btn-primary{background:var(--purple); color:#fff;}
.btn-primary:hover{background:var(--purple-deep); box-shadow:var(--shadow-sm);}
.btn-ghost{background:transparent; color:var(--ink); border-color:var(--line-strong);}
.btn-ghost:hover{background:var(--white); border-color:var(--purple); color:var(--purple);}
.btn-outline{background:transparent; color:var(--purple); border-color:var(--lilac);}
.btn-outline:hover{background:var(--purple); color:#fff; border-color:var(--purple);}

/* ---------- hero ---------- */
.hero{padding:128px 0 46px;
  background:radial-gradient(ellipse 900px 520px at 85% -12%, rgba(139,79,212,0.15), transparent 62%), var(--paper);}
.hero .wrap{display:grid; grid-template-columns:1.06fr 0.94fr; gap:56px; align-items:center;}
.hero h1{font-size:var(--t-3xl); line-height:1.06; margin-bottom:20px;}
.hero .lede{font-size:var(--t-md); color:var(--ink); font-weight:500; margin-bottom:14px;}
.hero .sub{font-size:var(--t-base); color:var(--ink-soft); margin-bottom:32px; max-width:56ch;}
.cta-row{display:flex; gap:14px; flex-wrap:wrap;}

.page-hero{padding:128px 0 37px;
  background:radial-gradient(ellipse 760px 420px at 88% -18%, rgba(139,79,212,0.14), transparent 62%), var(--paper);}
.page-hero h1{font-size:var(--t-3xl); line-height:1.06; margin-bottom:18px; max-width:18ch;}
/* A headline long enough that the 18ch cap forces a wrap it does not need.
   Uncapped, and sized so it clears the column on one line down to tablet;
   below that it wraps, which is right for a phone. */
.page-hero h1.h1-wide{max-width:none;
  font-size:clamp(2.1rem, 3.55vw, 3.05rem); line-height:1.08;}
.page-hero p{font-size:var(--t-md); color:var(--ink-soft); max-width:62ch;}
.page-hero .lede{color:var(--ink); font-weight:500;}

/* ============================================================
   ECOSYSTEM — the three pillars are dealt out on scroll
   The section pins and the scroll position drives the whole
   sequence: heading first, then each card swings out of a stack
   at the centre into its own slot, then the connector draws.
   script.js writes one --t per card (0 on its way, 1 landed) and
   nothing else; every movement below is derived from that, so
   scrolling back up runs the whole thing in reverse.
   ============================================================ */
/* The section used to pin for 2.2 screens. That bought the animation room but
   cost two things: a 600px blank band under the heading before the first card
   arrived, and half a screen of dead scrolling once all three had landed. The
   cards deal in as the section travels up the screen instead - same motion, no
   stopping, and about 2000px less page. */
.eco-stage{position:relative; padding:40px 0; background:var(--white);}
.eco-pin{position:static;}
.eco-canvas{position:relative; width:100%; isolation:isolate;}

/* A wash of the arriving pillar's own colour, behind everything. Its own
   name, not .eco-glow: the hero ring already owns that class, and sharing
   it applied this rule's opacity to the ring and switched its glow off. */
.eco-wash{position:absolute; inset:-60% -30%; z-index:0; pointer-events:none;
  background:radial-gradient(closest-side circle at var(--gx,50%) 56%,
             var(--gc,rgba(94,44,147,0.16)) 0%,
             rgba(255,255,255,0) 78%);
  opacity:var(--go,0); transition:opacity .6s ease, background .6s ease;}


.eco-head{position:relative; z-index:2;
  opacity:var(--ht,1); transform:translateY(calc((1 - var(--ht,1)) * 26px));}
.eco-rail{position:relative; z-index:2;}

/* The standfirst sits under the three cards, so it reads as what they add up
   to rather than as a preface. It arrives last, with the connector. */
.eco-note{margin:18px auto 0; max-width:60ch; text-align:center;
  font-size:var(--t-md); color:var(--a-soft, var(--ink-soft));
  opacity:var(--nt,1); transform:translateY(calc((1 - var(--nt,1)) * 16px));}

/* the connector, drawn once the last card is home, with a bead running it */
.eco-link{position:absolute; left:0; right:0; top:calc(50% - 1px); height:2px; z-index:0;
  background:linear-gradient(90deg, var(--early), var(--skills), var(--tech));
  opacity:0.32; transform:scaleX(var(--lt,0)); transform-origin:left;}
.eco-bead{position:absolute; top:calc(50% - 5px); left:calc(var(--lt,0) * 100%);
  width:10px; height:10px; margin-left:-5px; border-radius:50%; z-index:1;
  background:var(--tech); opacity:calc(var(--lt,0) * (1 - var(--lt,0)) * 4);
  box-shadow:0 0 0 5px rgba(27,93,170,0.16);}

.eco-rail .pillars{position:relative; z-index:1;
  perspective:1500px; perspective-origin:50% 45%;}

/* Each card is identical in layout — only its arrival differs. It starts
   stacked at the centre (--dx), tipped (--ry/--rz) and set back in depth. */
.eco-stage .pillar-card{transform-origin:50% 80%;
  opacity:calc(var(--t,1) * 2.4);
  transform:
    translate3d(calc((1 - var(--t,1)) * var(--dx,0px)), calc((1 - var(--t,1)) * 26px),
                calc((1 - var(--t,1)) * -260px))
    rotateY(calc((1 - var(--t,1)) * var(--ry,0deg)))
    rotateZ(calc((1 - var(--t,1)) * var(--rz,0deg)))
    scale(calc(0.84 + 0.16 * var(--t,1)));
  box-shadow:0 calc(var(--t,1) * 18px) calc(var(--t,1) * 40px) -22px rgba(51,21,79,0.42);
  transition:none; will-change:transform, opacity;}
/* the hover lift would fight the scroll transform, so it stands down here */
.eco-stage .pillar-card:hover{transform:
    translate3d(calc((1 - var(--t,1)) * var(--dx,0px)), calc((1 - var(--t,1)) * 26px),
                calc((1 - var(--t,1)) * -260px))
    rotateY(calc((1 - var(--t,1)) * var(--ry,0deg)))
    rotateZ(calc((1 - var(--t,1)) * var(--rz,0deg)))
    scale(calc(0.84 + 0.16 * var(--t,1)));}
/* the contents surface only once the card is most of the way home */
.eco-stage .pillar-card > *{opacity:calc((var(--t,1) - 0.55) * 2.6);}

/* Below this width there is no room to pin a full screen of cards, so the
   whole thing stands down and the section behaves like any other. */
@media (max-width:900px){
  .eco-wash,.eco-link,.eco-bead{display:none;}
  .eco-head{opacity:1; transform:none;}
  .eco-rail .pillars{perspective:none;}
  .eco-stage .pillar-card,.eco-stage .pillar-card > *{opacity:1; transform:none;
    box-shadow:none;}
}

/* ============================================================
   SCROLL-LINKED ARRIVAL
   The same one-at-a-time feel as the ecosystem, without pinning:
   as a section travels up the screen its beats arrive in order,
   driven by scroll position. --t is written per beat by
   script.js; the default of 1 means that if the script never
   runs, everything is simply visible.
   ============================================================ */
[data-beat]{
  opacity:var(--t,1);
  /* --bx lets a beat come in from the side instead of straight up; it is set
     per beat by script.js and is zero everywhere except the two-column
     sections, where the two halves meet in the middle. */
  transform:translate3d(calc((1 - var(--t,1)) * var(--bx,0px)),
                        calc((1 - var(--t,1)) * var(--by,26px)), 0);
  will-change:transform, opacity;}

/* the repeating items get a touch of scale as well, so a row of them
   reads as arriving rather than just fading */
.scrub .pillar-card[data-beat],
.scrub .strength-tile[data-beat],
.scrub .news-card[data-beat],
.scrub .info-card[data-beat]{
  transform:translate3d(calc((1 - var(--t,1)) * var(--bx,0px)),
                        calc((1 - var(--t,1)) * 30px), 0)
            scale(calc(0.965 + 0.035 * var(--t,1)));}
.scrub .chip[data-beat]{
  transform:translate3d(calc((1 - var(--t,1)) * var(--bx,0px)),
                        calc((1 - var(--t,1)) * 16px), 0)
            scale(calc(0.9 + 0.1 * var(--t,1)));}

/* hover lifts would fight the scroll transform mid-arrival */
.scrub .strength-tile[data-beat]:hover,
.scrub .news-card[data-beat]:hover,
.scrub .info-card[data-beat]:hover{transform:translate3d(0,0,0) scale(1);}

/* ---------- pillar cards ---------- */
.pillars{display:grid; grid-template-columns:repeat(3,1fr); gap:24px;}
.pillar-card{--accent:var(--purple); --accent-tint:var(--lilac-pale);
  display:flex; flex-direction:column; background:var(--white);
  border:1px solid var(--line); border-top:3px solid var(--accent);
  border-radius:var(--radius); padding:30px 30px 26px;
  transition:border-color .24s ease, transform .3s var(--ease), box-shadow .3s var(--ease);}
.pillar-card:hover{border-color:var(--accent); transform:translateY(-6px); box-shadow:var(--shadow);}
.pillar-card.early {--accent:var(--early);  --accent-tint:var(--early-tint);}
.pillar-card.skills{--accent:var(--skills); --accent-tint:var(--skills-tint);}
.pillar-card.tech  {--accent:var(--tech);   --accent-tint:var(--tech-tint);}
/* Each pillar leads with its brand's own lockup, at whatever proportion that
   brand comes in - Stanfords is stacked, Nomass.AI is horizontal. They share a
   block of the same height rather than a box of the same shape, so the row
   lines up without squeezing a mark into a square it does not fit. All three
   pillars now carry their brand's own lockup. */
.pillar-logo{display:flex; align-items:center; justify-content:center;
  /* flex:none, or the card's own column layout shrinks the block and the
     three tags below stop lining up */
  height:82px; flex:none; width:100%; margin-bottom:18px;}
.pillar-logo.is-lockup img{width:auto; object-fit:contain;}
/* the new lockup is horizontal where the old one was stacked, so it is
   sized to sit at the same visual weight as the Nomass one beside it */
.pillar-card.early  .pillar-logo img{max-height:56px;}
.pillar-card.skills .pillar-logo img{max-height:46px;}
.pillar-card.tech   .pillar-logo img{max-height:30px;}
/* the chip belongs to the mark itself, so the block keeps its full height */
.pillar-logo.is-mark svg{width:23px; height:23px; padding:11px;
  box-sizing:content-box; border-radius:13px;
  background:var(--accent-tint); color:var(--accent);}
/* stays small: this one only labels a pillar card on the homepage. The
   section-level label on the ecosystem page uses .eyebrow, so it matches
   the section eyebrow on every other page. */
.pillar-tag{font-family:var(--util); font-size:var(--t-2xs); font-weight:700; letter-spacing:0.14em;
  text-transform:uppercase; color:var(--accent); margin-bottom:12px;}
.pillar-card h3{font-size:1.25rem; margin-bottom:10px;}
.pillar-delivered{font-size:var(--t-xs); color:var(--ink-faint); margin-bottom:14px;}
/* The brand's name in the "delivered through" line goes to that brand's own
   site. Named for where it lives, not for what it is: .brand-links already
   exists as the container on the contact page and the two would be easy to
   confuse. It carries the pillar's accent so it reads as a link without an
   underline, plus an outward arrow to show it leaves the site. */
.delivered-link{display:inline-flex; align-items:center; gap:3px;
  color:var(--accent); font-weight:600;
  border-bottom:1px solid transparent; transition:border-color .2s ease;}
.delivered-link svg{width:11px; height:11px; opacity:.75;
  transition:transform .2s var(--ease);}
.delivered-link:hover{border-bottom-color:currentColor;}
.delivered-link:hover svg{transform:translate(1px,-1px);}
.delivered-link:focus-visible{outline:2px solid var(--accent); outline-offset:3px;
  border-radius:2px;}
.pillar-card p{font-size:var(--t-sm); color:var(--ink-soft); margin-bottom:20px; flex-grow:1;}
.card-link{display:inline-flex; align-items:center; gap:8px; font-size:var(--t-sm);
  font-weight:600; color:var(--accent); padding-top:16px; border-top:1px solid var(--line);}
.card-link svg{width:15px; height:15px; transition:transform .24s var(--ease);}
.pillar-card:hover .card-link svg{transform:translateX(4px);}

/* ---------- chips ---------- */
.chip-row{display:flex; flex-wrap:wrap; gap:10px;}
.chip{font-size:var(--t-sm); font-weight:600; color:var(--purple); background:var(--white);
  border:1px solid var(--lilac); border-radius:100px; padding:11px 15px;
  white-space:nowrap;
  transition:background .22s ease, color .22s ease, transform .24s var(--ease);}
.chip:hover{background:var(--purple); color:var(--white); transform:translateY(-2px);}

/* ---------- chips as a marquee ----------
   The two ecosystem lists are long enough to wrap to three rows, which reads
   as a wall rather than a list. Running them as a single travelling line keeps
   them to one row and lets the eye take them a few at a time.

   The structure is built by script.js: without it, or with reduced motion
   asked for, these stay an ordinary wrapped .chip-row. Everything below only
   applies once the script has added .is-live. */
.marquee.is-live{position:relative; overflow:hidden; flex-wrap:nowrap; display:block;
  /* the line fades out at both ends rather than being cut off by the edge */
  -webkit-mask-image:linear-gradient(90deg, transparent 0, #000 5%, #000 95%, transparent 100%);
          mask-image:linear-gradient(90deg, transparent 0, #000 5%, #000 95%, transparent 100%);}
.marquee-track{display:flex; gap:10px; width:max-content;
  animation:chip-marquee var(--dur,42s) linear infinite;}
.marquee[data-marquee-reverse] .marquee-track{animation-direction:reverse;}
.marquee-group{display:flex; gap:10px; flex:none;}
.marquee.is-live .chip{flex:none; white-space:nowrap;}
/* hold it still while someone is reading a particular chip */
.marquee.is-live:hover .marquee-track,
.marquee.is-live:focus-within .marquee-track{animation-play-state:paused;}
/* the track is two identical groups, so half its width is one full cycle; the
   extra half-gap is the join between them */
@keyframes chip-marquee{
  from{transform:translate3d(0,0,0);}
  to{transform:translate3d(calc(-50% - 5px),0,0);}
}

/* ---------- split section head ---------- */
/* The heading claims three industries are one system, so the space
   beside it carries the proof rather than a decoration: one unbroken
   rule, three colours, a brand sitting under each. */
.head-split{display:grid; grid-template-columns:1.15fr 1fr; gap:56px;
  align-items:start; margin-bottom:28px;}
.head-split .section-head{max-width:none; margin-bottom:0;}
.head-aside p{color:var(--ink-soft); font-size:var(--t-md); line-height:1.6;
  margin:0 0 30px;}

.one-system{border-top:1px solid var(--line); padding-top:22px;}
.os-label{display:block; font-family:var(--util); font-size:var(--t-2xs);
  font-weight:600; letter-spacing:0.14em; text-transform:uppercase;
  color:var(--ink-faint); margin-bottom:14px;}
/* hard stops rather than a blend, so each third of the rule belongs
   to the brand named beneath it */
.os-rule{display:block; height:3px; border-radius:2px;
  background:linear-gradient(90deg,
    var(--early) 0 33.33%, var(--skills) 33.33% 66.66%, var(--tech) 66.66%);}
.os-brands{display:grid; grid-template-columns:repeat(3,1fr); gap:0;
  list-style:none; margin:12px 0 0; padding:0;}
.os-brands li{color:var(--c); font-size:var(--t-xs); font-weight:600;
  line-height:1.35; padding-right:12px;}

/* ---------- strengths ---------- */
/* 12 columns, four to a row. A short final row keeps the same tile
   width and sits left, so every tile lines up with the one above it. */
.strength-grid{display:grid; grid-template-columns:repeat(12,1fr); gap:20px;}
.strength-grid > *{grid-column:span 3;}

.strength-tile{background:var(--white); border:1px solid var(--line); border-radius:var(--radius);
  padding:26px 24px; transition:border-color .22s ease, transform .26s var(--ease), box-shadow .26s ease;}
.strength-tile:hover{border-color:var(--lilac); transform:translateY(-4px); box-shadow:var(--shadow);}
.strength-tile h4{font-size:var(--t-base); margin-bottom:8px;}
.strength-tile p{font-size:var(--t-sm); color:var(--ink-soft);}

/* ---------- info cards, values, quote ---------- */
/* same idea on 6 columns: 5 cards read as 3 + 2 across the full width */
.card-grid{display:grid; grid-template-columns:repeat(6,1fr); gap:24px;}
.card-grid > *{grid-column:span 2;}
/* Exactly four is the one count that divides evenly another way, so it
   takes two even rows of two. Every other count keeps a single column
   width and lets a short final row sit left. */
.card-grid > :first-child:nth-last-child(4),
.card-grid > :first-child:nth-last-child(4) ~ *{grid-column:span 3;}
.info-card{background:var(--white); border:1px solid var(--line); border-radius:var(--radius);
  padding:30px 28px; transition:border-color .22s ease, transform .26s var(--ease), box-shadow .26s ease;}
.info-card:hover{border-color:var(--lilac); transform:translateY(-4px); box-shadow:var(--shadow);}
.info-card h3,.info-card h4{font-size:var(--t-lg); margin-bottom:10px;}
.info-card p{font-size:var(--t-sm); color:var(--ink-soft);}
.value-list{list-style:none; display:flex; flex-direction:column; gap:14px;}
.value-list li{display:flex; gap:14px; align-items:baseline; font-size:var(--t-base); color:var(--ink-soft);}
.value-list .k{flex:none; width:104px; font-weight:800; font-size:var(--t-md);
  color:var(--purple); letter-spacing:-0.02em;}
.dot{width:7px; height:7px; border-radius:50%; background:var(--purple); flex:none; transform:translateY(-2px);}
.pull-quote{font-family:'Plus Jakarta Sans',sans-serif; font-weight:600; font-size:var(--t-xl); letter-spacing:-0.02em; line-height:1.2;
  color:var(--purple-deep); max-width:26ch; border-left:2px solid var(--lilac); padding-left:24px;}

/* ---------- about: split hero ---------- */
/* The hero ran one column of text across the full width, leaving the right
   half empty under the corner gradient. */
.page-hero-split .wrap{display:grid; grid-template-columns:1.02fr 0.98fr;
  gap:56px; align-items:center;}
.page-hero-split h1{max-width:none;}
.page-hero-split .lede{max-width:50ch;}
.hero-art{margin:0;}
.hero-art img{display:block; width:100%; height:auto;
  border-radius:var(--radius);}

/* ---------- a light wash behind a page hero ----------
   Artwork rather than a gradient, but it works the same way: the arcs are
   weighted to the right and the lower left, and the left half stays clean
   paper, which is where the eyebrow, headline and lede sit. The image is
   anchored right so that emptiness lands under the copy at every width.

   A scrim over the left insures the dark type against the crop, and the
   whole layer sits behind the content rather than tinting it. */
.has-wash{overflow:hidden;}
.has-wash > .wrap{position:relative; z-index:1;}
.hero-wash{position:absolute; inset:0; z-index:0; pointer-events:none;}
.hero-wash img{display:block; width:100%; height:100%;
  object-fit:cover; object-position:100% 50%;}
.hero-wash::after{content:""; position:absolute; inset:0;
  background:linear-gradient(90deg,
    rgba(250,247,252,0.92) 0%, rgba(250,247,252,0.66) 34%,
    rgba(250,247,252,0.12) 60%, rgba(250,247,252,0) 78%);}

/* ---------- about: the group card ----------
   The About hero asks "who we are", and the honest answer is a structure: one
   company holding three operating businesses. So the column shows that,
   rather than a photograph of a room.

   It is drawn on the site's own signature. The README describes the tick - a
   hairline that draws down above every section eyebrow, so the sections read
   as one continuous system - and this is the one place where that line has a
   literal job: it is the spine the three companies hang from, in their own
   accents. The line draws itself on load and the three names arrive along it,
   which is the whole animation on this page. */
/* Glass, so the wash behind it stays one continuous field rather than being
   interrupted by a white rectangle. Same recipe as the header pill - blur plus
   a little saturation, a hairline in purple rather than grey - so the two
   floating surfaces on the page are made of the same material. */
.group-card{position:relative; border-radius:22px;
  padding:34px 36px 30px;
  background:rgba(255,255,255,0.58);
  -webkit-backdrop-filter:blur(18px) saturate(150%);
          backdrop-filter:blur(18px) saturate(150%);
  border:1px solid rgba(139,79,212,0.16);
  box-shadow:0 24px 50px -32px rgba(51,21,79,0.34),
             0 1px 0 rgba(255,255,255,0.75) inset;}
/* without backdrop-filter the card would be a flat translucent panel over the
   arcs, so it falls back to nearly opaque instead */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .group-card{background:rgba(255,255,255,0.94);}
}
/* the hairlines inside need a touch more presence on glass than on white */
.group-card .gc-head,.group-card .gc-foot{border-color:rgba(27,18,48,0.14);}

.gc-head{display:flex; align-items:center; justify-content:space-between; gap:18px;
  padding-bottom:22px; border-bottom:1px solid var(--line);}
.gc-logo{height:30px; width:auto; color:var(--purple);}
.gc-tag{font-family:var(--util); font-size:var(--t-2xs); font-weight:600;
  letter-spacing:0.16em; text-transform:uppercase; color:var(--ink-soft);}

.gc-list{list-style:none; margin:0; padding:26px 0 4px;}
.gc-item{position:relative; padding:0 0 26px 30px;}
.gc-item:last-child{padding-bottom:6px;}
/* the spine: one continuous hairline, carried by the items themselves so it
   always spans exactly the three of them */
.gc-item::before{content:""; position:absolute; left:5px; top:9px; bottom:-9px;
  width:1px; background:var(--line-strong);}
.gc-item:last-child::before{display:none;}
.gc-node{position:absolute; left:0; top:5px; width:11px; height:11px;
  border-radius:50%; background:var(--paper);
  box-shadow:0 0 0 2px var(--accent, var(--purple));}
.gc-early{--accent:var(--early);}
.gc-skills{--accent:var(--skills);}
.gc-tech{--accent:var(--tech);}
.gc-name{display:block; font-family:'Plus Jakarta Sans',system-ui,sans-serif;
  font-weight:700; font-size:var(--t-md); letter-spacing:-0.015em; color:var(--ink);
  line-height:1.25;}
.gc-role{display:block; margin-top:3px; font-size:var(--t-sm); color:var(--ink-soft);}

.gc-foot{display:flex; justify-content:space-between; gap:22px; flex-wrap:wrap;
  padding-top:22px; border-top:1px solid var(--line);}
/* baseline pins the number to the label's first line, which reads high
   against a two-line label - centered against the whole block instead */
.gc-fact{display:flex; align-items:center; gap:9px; white-space:nowrap;}
.gc-fact b{font-family:'Plus Jakarta Sans',system-ui,sans-serif; font-weight:800;
  font-size:var(--t-lg); letter-spacing:-0.02em; color:var(--purple); line-height:1;}
.gc-fact span{font-family:var(--util); font-size:var(--t-2xs); letter-spacing:0.08em;
  text-transform:uppercase; color:var(--ink-soft); line-height:1.5;}
.gc-regions{text-align:right; margin-left:auto;}

/* the line draws, then the three names come in along it */
@media (prefers-reduced-motion: no-preference){
  .gc-item::before{transform-origin:top; animation:gc-draw .5s var(--ease) both;
    animation-delay:calc(.45s + var(--i) * .16s);}
  .gc-node,.gc-name,.gc-role{animation:gc-in .45s var(--ease) both;
    animation-delay:calc(.55s + var(--i) * .16s);}
  .gc-early{--i:0;} .gc-skills{--i:1;} .gc-tech{--i:2;}
}
@keyframes gc-draw{from{transform:scaleY(0);} to{transform:scaleY(1);}}
@keyframes gc-in{from{opacity:0; transform:translateX(-8px);} to{opacity:1; transform:none;}}

/* ---------- about: story ----------
   The poster runs the full height of the narrative beside it, so the two
   columns finish level rather than leaving the left one short. It is cropped
   from the bottom (floor and desks) and never the top, so the headline the
   artwork carries survives whatever height the copy asks for.

   The poster carries the eyebrow and headline itself, so the markup ones are
   taken off the screen rather than deleted: the section keeps a real h2 for
   search and for anyone navigating by heading. */
.story-split{align-items:stretch;}
.story-split > div:first-child{display:flex; flex-direction:column;}
.story-art{margin:0; flex:1; min-height:340px;}
.story-art img{display:block; width:100%; height:100%;
  object-fit:cover; object-position:50% 0;
  border-radius:var(--radius);}
.story-split > :last-child p{margin-bottom:16px;}
.story-split > :last-child p:last-child{margin-bottom:0;}

/* ---------- about: future, a band of its own ----------
   The third band on the site, but the only artwork whose subject sits low and
   right rather than hard right, so it is anchored to that corner and the copy
   takes the open purple above and to the left of the globe. This artwork
   carries no headline of its own, so unlike the story poster the section
   shows its real heading. */
.future-band{padding:0; overflow:hidden; background:var(--purple-deep);}
/* the artwork is composited 2:1 with its own left edge extended, so it already
   carries the calm space the copy sits on; the scrim only insures the crop */
.future-band .band-media img{object-position:64% 50%;}
.future-band .band-media::after{background:linear-gradient(90deg,
    rgba(37,15,58,0.62) 0%, rgba(37,15,58,0.34) 38%,
    rgba(37,15,58,0.06) 64%, rgba(37,15,58,0) 78%);}
.future-band .future-band-inner{position:relative; z-index:1;
  padding-top:50px; padding-bottom:50px;}
/* a wider measure here than the other bands: it lets the three paragraphs and
   the quote wrap into fewer lines, which is most of what keeps the section
   from running tall */
.future-band-copy{max-width:44rem;}
/* the heading and the quote both carry their own width caps, set for a narrow
   column; uncapped here they each drop a line rather than wrapping early */
.future-band .section-head{max-width:none; margin-bottom:18px;}
.future-band p{margin-bottom:13px;}
.future-band .pull-quote{margin-top:20px; max-width:42ch;}
.future-band .eyebrow{color:var(--lilac);}
.future-band h2{color:var(--white);}
.future-band p{color:rgba(250,247,252,0.84);}
.future-band .pull-quote{color:var(--white); border-left-color:var(--lilac);}

/* The heading column ran short beside a two-paragraph aside. The regions
   named in that aside fill it, and pair the claim with the places. */
.vision-reach{margin-top:34px; padding-top:24px; border-top:1px solid var(--line);}
.reach-label{display:block; font-family:var(--util); font-size:var(--t-2xs);
  font-weight:600; letter-spacing:0.14em; text-transform:uppercase;
  color:var(--ink-faint); margin-bottom:14px;}

/* ---------- about: vision outcomes ---------- */
/* Nine outcomes with no marker read as loose sentences, so each one now
   carries the dot the flex row was always built to hold. They are
   conditions, not steps, so a dot is right where a number would lie. */
.vision-label{font-family:var(--util); font-size:var(--t-2xs); font-weight:600;
  letter-spacing:0.14em; text-transform:uppercase; color:var(--ink-faint);
  padding-bottom:16px; margin-bottom:26px; border-bottom:1px solid var(--line);}
.value-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:20px 36px;}
.value-grid li{align-items:flex-start;}
.value-grid .dot{margin-top:8px; transform:none;}

/* ============================================================
   ECOSYSTEM PILLARS
   Each pillar reads the same way: heading, then the narrative
   beside a photograph of the setting it describes, then the
   detail list full width. Spacing comes from these classes
   rather than per-element inline styles.
   ============================================================ */
/* These sit outside .section-head, so they never picked up its size and
   fell back to the base h2 - 24px against the 40px every other page uses
   for a section heading. Matched to the rest of the site. */
.pillar-h2{font-size:var(--t-2xl); margin-top:10px;}
.pillar-delivered{margin-top:10px;}
.mt-sm{margin-top:16px;}

/* the pillar accents, previously set inline on every element */
.pt-early{color:var(--early);}
.pt-skills{color:var(--skills);}
.pt-tech{color:var(--tech);}
.pd-early{--accent:var(--early);}
.pd-skills{--accent:var(--skills);}
.pd-tech{--accent:var(--tech);}
.pq-early{margin-top:20px; border-color:var(--early);}
.dot-early{background:var(--early);}
.dot-tech{background:var(--tech);}
.card-topped{border-top:2px solid var(--accent,var(--purple));}
.ct-tech{--accent:var(--tech);}

/* the narrative column set against the setting it describes */
/* height:100% on a child of an auto-height figure resolves to auto, so the
   photo used its own aspect ratio and overshot the copy beside it. Absolute
   positioning inside a stretched figure makes it take the row height instead,
   so the two columns finish level. */
/* No floor: each photograph takes exactly the height of the copy beside
   it, so the two columns always finish level. */
.pillar-art{margin:0; align-self:stretch; position:relative;}
.pillar-art img{position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; border-radius:var(--radius);}

/* ---------- the brand plate ----------
   Each pillar is delivered by a real company, so the column beside the copy
   shows that company's own mark rather than a stock photograph. A mark is an
   identity, not a picture: it is never cropped or stretched to fill, it is
   given clear space and left alone. The three plates are identical apart from
   the hairline at the top, which carries the pillar's accent - the same one
   already on the eyebrow, the quote rule and the delivered-through link.

   The marks are three different shapes, so neither a shared width nor a
   shared height evens them out on its own: each is held on whichever
   dimension is doing the work, aiming at roughly equal area.

   The plate is centred against the copy rather than stretched to match it.
   Stretching is right for a photograph, which fills whatever height it is
   given; a mark does not fill, so a tall column would just be a small logo
   adrift in a lot of white. */
.brand-plate{margin:0; align-self:center; position:relative; min-height:296px;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:26px; padding:36px;
  background:var(--white); border:1px solid var(--line);
  border-top:2px solid var(--accent, var(--purple));
  border-radius:var(--radius); box-shadow:var(--shadow-sm);}
.bp-early{--accent:var(--early);}
.bp-skills{--accent:var(--skills);}
.bp-tech{--accent:var(--tech);}

.bp-mark{width:auto; height:auto; max-width:min(232px, 74%); max-height:96px;
  object-fit:contain;}
/* Nomass is a long single line where the other two are compact blocks, so it
   takes the shared width and they are held on height instead. */
.bp-early .bp-mark{max-height:92px;}
.bp-skills .bp-mark{max-height:74px;}

.bp-meta{display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  justify-content:center; padding-top:22px; border-top:1px solid var(--line);
  width:min(360px, 100%);}
.bp-role{font-family:var(--util); font-size:var(--t-2xs); font-weight:500;
  letter-spacing:0.14em; text-transform:uppercase; color:var(--ink-soft);}
.bp-link{display:inline-flex; align-items:center; gap:5px;
  font-size:var(--t-sm); font-weight:600; color:var(--accent, var(--purple));}
.bp-link svg{width:14px; height:14px; flex:none;}
.bp-link:hover{text-decoration:underline;}

/* a long run of body copy, kept to a readable measure */
.prose{max-width:70ch;}
.prose > p + p{margin-top:14px;}
/* a step below the pillar heading, a clear step above card titles */
.sub-head{font-size:var(--t-xl); margin-bottom:12px;}
/* a subhead that follows body copy in the same column needs air above it */
.sub-head-inline{margin-top:30px;}
.lead-claim{font-weight:600; color:var(--ink);}

/* the detail set that closes each pillar - full width, so ten or
   thirteen items no longer stretch one column far past the other */
.emphasis{margin-top:24px;}
.emphasis-label{font-family:var(--util); font-size:var(--t-2xs); font-weight:600;
  letter-spacing:0.14em; text-transform:uppercase; color:var(--ink-faint);
  padding-bottom:16px; margin-bottom:24px; border-bottom:1px solid var(--line);}

/* ---------- projects: heading meta ---------- */
/* Each heading sat alone beside three paragraphs, leaving the left
   column empty. These tags name the scope of the initiative, drawn
   from the section's own copy. */
.project-meta{display:flex; flex-wrap:wrap; gap:8px; margin-top:20px;}
/* the Riyadh skyline sits under the GESS heading, filling the column the
   copy beside it would otherwise leave empty and naming the destination */
.project-art{margin:30px 0 0;}
.project-art img{display:block; width:100%; height:auto; max-width:330px;}
.project-meta span{font-family:var(--util); font-size:var(--t-2xs);
  letter-spacing:0.12em; text-transform:uppercase; color:var(--ink-faint);
  border:1px solid var(--line); border-radius:100px; padding:5px 12px;}

/* ---------- opportunities ---------- */
/* The banner is square and used whole, so it is capped by height rather
   than width - otherwise a square filling the column would make this hero
   far taller than every other one. */
/* Fills the column width, but the post is square - left at its natural
   height it would be as tall as it is wide. Capped and cropped instead, so
   it sits in the same landscape proportion as the photographs elsewhere. */
/* The picture takes its height from the copy beside it, not from its own
   proportions - the figure stretches to the row and the image fills it, so
   the two columns are always the same height. */
/* the UK skyline, set against the section heading */
.reach-art{display:flex; align-items:flex-end; justify-content:flex-end;
  min-height:100%;}
.reach-art img{display:block; width:100%; height:auto; max-width:420px;}
/* the homepage instance is given the wider half of the row, so the same
   skyline stands taller there than it does on the Opportunities page */
.head-split-wide{grid-template-columns:1fr 1.2fr;}
.reach-art-lg img{max-width:none;}

/* ---------- typed pull quote ---------- */
/* The lines keep their height at all times and only open and close
   horizontally, so the paragraph never changes size and nothing below it
   moves while the cycle runs. Width is driven by the script; the caret is
   the only part CSS animates. Without the script, or with reduced motion
   asked for, all three lines are simply present. */
.typeset .tw-line{display:block; white-space:nowrap;}
.typeset[data-tw] .tw-line{overflow:hidden; border-right:2px solid transparent;}
.typeset[data-tw] .tw-line.is-caret{animation:tw-caret .8s step-end infinite;}
@keyframes tw-caret{0%,100%{border-right-color:var(--early);}
                    50%{border-right-color:transparent;}}

@media (prefers-reduced-motion: reduce){
  .typeset .tw-line{width:auto !important; overflow:visible !important;
    border-right-color:transparent !important; animation:none !important;}
}

/* ---------- full-bleed artwork bands ----------
   Two sections run this pattern: the opportunities teaser on the home page
   and the opportunities hero. Both use artwork composed the same way - the
   subject hard right, open purple to the left - so the image is anchored
   right and the copy sits in the space it already leaves. The scrim only has
   to carry the near edge; past ~70% the artwork is dark enough on its own,
   and fading out there keeps it reading as photography rather than as a
   tinted backdrop. */
.band-media{position:absolute; inset:0; background:var(--purple-deep);}
.band-media img{display:block; width:100%; height:100%;
  object-fit:cover; object-position:78% 50%;}
.band-media::after{content:""; position:absolute; inset:0;
  background:linear-gradient(90deg,
    rgba(37,15,58,0.94) 0%, rgba(37,15,58,0.80) 32%,
    rgba(37,15,58,0.22) 60%, rgba(37,15,58,0) 80%);}
/* the copy that sits over one */
.opp-band .eyebrow,.hero-band .eyebrow{color:var(--lilac);}
.opp-band h2,.hero-band h1{color:var(--white);}
.opp-band p,.hero-band p{color:rgba(250,247,252,0.84);}
.hero-band .lede{color:rgba(250,247,252,0.92);}

/* home: the teaser */
.opp-band{padding:0; margin:40px 0; overflow:hidden;}
.opp-band .opp-band-inner{position:relative; z-index:1; padding-top:104px; padding-bottom:104px;}
.opp-band-copy{max-width:34rem;}
.opp-band .section-head{margin-bottom:22px;}
.opp-band p{max-width:46ch; margin-bottom:26px;}
.opp-band .btn-outline{color:var(--white); border-color:rgba(233,220,250,0.55);}
.opp-band .btn-outline:hover{background:var(--white); color:var(--purple-deep);
  border-color:var(--white);}

/* opportunities: the same band carrying the page hero. The padding-top keeps
   its own value rather than the band's, because it is also what clears the
   fixed header. */
.hero-band{padding:0; overflow:hidden; background:var(--purple-deep);}
.hero-band .hero-band-inner{position:relative; z-index:1;
  padding-top:152px; padding-bottom:104px;}
.hero-band .hero-copy{max-width:34rem;}
.hero-band .lede{max-width:46ch;}

@media (max-width:1024px){
  /* the copy column is now most of the width, so the scrim has to cover it */
  .opp-band .opp-band-inner{padding-top:80px; padding-bottom:80px;}
  .hero-band .hero-band-inner{padding-top:128px; padding-bottom:80px;}
  .band-media img{object-position:72% 50%;}
  .band-media::after{background:linear-gradient(90deg,
    rgba(37,15,58,0.94) 0%, rgba(37,15,58,0.82) 50%, rgba(37,15,58,0.34) 100%);}
}

@media (max-width:767px){
  /* portrait: the arches read better below the copy than behind it, so the
     scrim turns vertical and the band grows to leave them room */
  .opp-band{margin:32px 0;}
  .opp-band .opp-band-inner{padding-top:64px; padding-bottom:260px;}
  .hero-band .hero-band-inner{padding-top:112px; padding-bottom:240px;}
  .opp-band-copy,.hero-band .hero-copy,.hero-band .lede{max-width:none;}
  .band-media img{object-position:68% 100%;}
  .band-media::after{background:linear-gradient(180deg,
    rgba(37,15,58,0.95) 0%, rgba(37,15,58,0.90) 42%, rgba(37,15,58,0.30) 78%,
    rgba(37,15,58,0.10) 100%);}
}

/* ---------- a card that carries its own graphic ---------- */
/* The campaign artwork states the same three terms the copy closes on, so
   it sits beside the text as the picture of the claim. The post's logo and
   web address bar is cropped off - it belongs on social, not inside a page
   on the same site. */
.card-split{display:grid; grid-template-columns:1fr auto; gap:40px; align-items:center;}
.card-art{margin:0;}
.card-art img{display:block; width:100%; height:auto; max-width:300px;
  border-radius:12px;}

/* ---------- campaign gallery ---------- */
/* Square social posts shown as artefacts, so they keep the logo and web
   address they were designed with. Three to a row leaves each one large
   enough to read its headline. */
.gallery-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:24px;}
.gallery-grid figure{margin:0;}
.gallery-grid img{display:block; width:100%; height:auto;
  border-radius:var(--radius); border:1px solid var(--line);
  transition:transform .3s var(--ease), box-shadow .3s ease;}
.gallery-grid figure:hover img{transform:translateY(-4px); box-shadow:var(--shadow);}

@media (prefers-reduced-motion: reduce){
  .gallery-grid img{transition:none;}
  .gallery-grid figure:hover img{transform:none;}
}

/* ---------- news ---------- */
.filter-row{display:flex; flex-wrap:wrap; gap:10px; margin-bottom:32px;}
.filter-btn{font-family:var(--util); font-size:var(--t-2xs); letter-spacing:0.12em;
  text-transform:uppercase; color:var(--ink-soft); background:transparent;
  border:1px solid var(--line-strong); border-radius:100px; padding:9px 16px;
  transition:background .2s ease, color .2s ease, border-color .2s ease;}
.filter-btn:hover,.filter-btn.active{background:var(--purple); color:#fff; border-color:var(--purple);}
.news-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:24px;}
.news-card{display:flex; flex-direction:column; background:var(--white); border:1px solid var(--line);
  border-radius:var(--radius); overflow:hidden;
  transition:border-color .22s ease, transform .26s var(--ease), box-shadow .26s ease;}
.news-card:hover{border-color:var(--lilac); transform:translateY(-5px); box-shadow:var(--shadow);}
.news-thumb{height:132px; display:flex; align-items:flex-end; padding:16px;
  background:linear-gradient(135deg, var(--lilac-pale), var(--paper-dim));}
/* An item that belongs to one of the brands shows that brand's own artwork,
   supplied by the client. Everything else - events, the ecosystem as a whole,
   Smart Kids, which has no mark - keeps its category tint. */
.news-thumb.tag-technology{background:#0A1520 url('../img/news/news-technology.jpg') center/cover;}
/* the Stanfords lockup is a mark, not a photograph: contained rather than
   cropped, so it stays whole and centred at any card width, on the white the
   mark is drawn for */
.news-thumb.tag-training{background:#FFFFFF url('../img/news/news-training.jpg') center/contain no-repeat;}
.news-thumb.tag-events{background:linear-gradient(135deg,#EFE0C9,#FBF1DF);}
.news-thumb.tag-education{background:linear-gradient(135deg,#DCEEE7,#EAF5F0);}
.thumb-label{font-family:var(--util); font-size:var(--t-2xs); font-weight:500; letter-spacing:0.14em;
  text-transform:uppercase; color:var(--purple-deep); background:rgba(255,255,255,0.94);
  border:1px solid rgba(27,18,48,0.08);
  padding:5px 11px; border-radius:100px;}
.news-body{padding:24px; display:flex; flex-direction:column; flex-grow:1;}
.news-cat{display:block; font-family:var(--util); font-size:var(--t-2xs); font-weight:700; letter-spacing:0.12em;
  text-transform:uppercase; color:var(--purple); margin-bottom:10px;}
.news-body h4{font-size:var(--t-base); margin-bottom:9px;}
.news-body p{font-size:var(--t-sm); color:var(--ink-soft);}

/* ---------- contact ---------- */
/* ---------- contact ----------
   One band rather than two: the invitation, the direct details and the form
   all sit on the same screen, with the form level with the headline so the
   thing the page is for is visible without scrolling. */
/* Three blocks, two columns: the invitation and the direct details stack down
   the left, the form holds the right across both rows so it stays level with
   the headline. It is placed explicitly rather than by source order, so the
   markup can run invitation, form, details - which is both the reading order
   on a wide screen and the right stacking order on a phone, where the copy
   must not push the thing the page is for below a screen of detail. */
.contact-split{display:grid; grid-template-columns:1.06fr 0.94fr;
  gap:0 56px; align-items:start;}
.contact-lead{grid-column:1; grid-row:1;}
.contact-direct{grid-column:1; grid-row:2;}
.form-card{grid-column:2; grid-row:1 / span 2;}
.contact-lead .lede{max-width:52ch;}
.contact-h2{font-size:var(--t-xl); margin-bottom:20px;}
.contact-direct .thread-divider{margin:38px 0 30px;}
.brands-block{margin-top:32px;}

.contact-detail{display:flex; gap:14px; align-items:baseline; padding:14px 0;
  border-bottom:1px solid var(--line); font-size:var(--t-base); color:var(--ink-soft);}
/* the label was written as .k in the markup but styled here as <strong>, so it
   had been rendering as plain body text; it is keyed to the markup now */
.contact-detail .k{font-family:var(--util); font-size:var(--t-2xs); letter-spacing:0.14em;
  text-transform:uppercase; color:var(--purple); font-weight:500; flex:none; width:152px;
  line-height:1.4;}
.contact-detail .v{min-width:0;}
.contact-detail a{color:var(--purple); font-weight:600;}
.contact-detail a:hover{text-decoration:underline;}

/* the form is the page's one job, so it is the only raised surface on it */
.form-card{background:var(--white); border:1px solid var(--line);
  border-radius:var(--radius); padding:32px; box-shadow:var(--shadow);}
.form-row{display:grid; grid-template-columns:1fr 1fr; gap:0 16px;}
.form-foot{display:flex; align-items:center; gap:16px; flex-wrap:wrap; margin-top:4px;}
.req{color:var(--skills);}

.form-field{margin-bottom:18px;}
.form-field label{display:block; font-size:var(--t-xs); font-weight:500; color:var(--ink); margin-bottom:7px;}
.form-field input,.form-field select,.form-field textarea{width:100%; padding:12px 14px;
  border-radius:10px; border:1px solid var(--line-strong); background:var(--paper); color:var(--ink);
  min-height:46px;
  font-family:inherit; font-size:var(--t-sm); transition:border-color .15s ease, box-shadow .15s ease;}
.form-field input:hover,.form-field select:hover,.form-field textarea:hover{border-color:var(--lilac);}
.form-field input:focus,.form-field select:focus,.form-field textarea:focus{outline:none;
  border-color:var(--purple); box-shadow:0 0 0 3px rgba(139,79,212,0.14);}
.form-field textarea{resize:vertical; min-height:104px;}
.form-note{font-size:var(--t-xs); color:var(--ink-soft); margin:0; max-width:34ch;}

/* ---------- CTA banner ---------- */
.cta-banner{display:flex; align-items:center; justify-content:space-between; gap:36px;
  flex-wrap:wrap; padding:44px 48px; border-radius:22px; color:var(--white);
  background:linear-gradient(120deg, var(--purple-deep), var(--purple)); box-shadow:var(--shadow);}
.cta-banner h2{font-size:var(--t-xl); margin-bottom:10px; max-width:24ch;}
.cta-banner p{font-size:var(--t-sm); color:rgba(250,247,252,0.82); max-width:56ch;}
.cta-banner .btn-primary{background:var(--white); color:var(--purple-deep);}
.cta-banner .btn-primary:hover{background:var(--lilac-pale);}

/* the tick device, laid horizontally between blocks */
.thread-divider{position:relative; height:1px; background:var(--line); margin:44px 0;}
.thread-divider::after{content:""; position:absolute; left:0; top:-4px; width:9px; height:9px;
  border-radius:50%; background:var(--white); border:2px solid var(--purple);}

/* ---------- footer ---------- */
.site-footer{background:var(--white); border-top:1px solid var(--line); padding:64px 0 34px;}
.footer-top{display:grid; grid-template-columns:1.6fr 1fr 1fr 1fr 1fr; gap:28px; margin-bottom:44px;}
.footer-brand .logo{margin-bottom:14px;}
.footer-brand .brand-logo{height:30px;}
.footer-tagline{font-size:var(--t-sm); color:var(--ink-soft); max-width:30ch;}
.footer-col h5{font-family:var(--util); font-size:var(--t-2xs); font-weight:700; letter-spacing:0.16em;
  text-transform:uppercase; color:var(--purple); margin-bottom:16px;}
.footer-col ul{list-style:none;}
.footer-col li{margin-bottom:4px;}
.footer-col a{display:block; font-size:var(--t-sm); color:var(--ink-soft); padding:5px 0;
  transition:color .18s ease, transform .22s var(--ease);}
.footer-col a:hover{color:var(--purple); transform:translateX(4px);}
.footer-bottom{display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:12px;
  padding-top:22px; border-top:1px solid var(--line); font-size:var(--t-xs); color:var(--ink-soft);}
.region-row{display:flex; gap:10px; flex-wrap:wrap;}
.region-row span{font-family:var(--util); font-size:var(--t-2xs); letter-spacing:0.12em;
  text-transform:uppercase; color:var(--ink-faint); border:1px solid var(--line);
  border-radius:100px; padding:5px 12px;}
.brand-links{display:flex; gap:12px; flex-wrap:wrap;}

/* ============================================================
   HERO DIAGRAM — the ecosystem ring
   Layers sit at different translateZ, so rotating the parent
   gives true perspective rather than faked offsets. The three
   nodes orbit; .eco-spin counter-rotates so labels stay upright.
   ============================================================ */
.eco{position:relative; width:100%; max-width:520px; margin-left:auto;
  height:0; padding-top:82.7%; perspective:1100px;}
.eco-scene{position:absolute; top:0; left:0; right:0; bottom:0; transform-style:preserve-3d;
  transition:transform .5s var(--ease); will-change:transform;}
.eco-layer{position:absolute; top:0; left:0; right:0; bottom:0; transform-style:preserve-3d;}
.eco-glow{transform:translateZ(-55px);
  background:radial-gradient(ellipse 58% 58% at 50% 54%, transparent 34%, rgba(139,79,212,0.20) 56%, transparent 76%);}
.eco-ring svg{position:absolute; top:0; left:0; width:100%; height:100%;}
.eco-core{position:absolute; left:50%; top:54.4%; transform:translate(-50%,-50%) translateZ(26px);
  text-align:center; width:200px;}
.eco-logo{display:block; height:38px; width:auto; margin:0 auto; color:var(--purple);}

.eco-carousel{position:absolute; top:0; left:0; right:0; bottom:0; transform-style:preserve-3d;
  animation:eco-revolve 46s linear infinite;}
.eco-fix{position:absolute; top:0; left:0; right:0; bottom:0;}
.eco-spin{position:absolute; top:0; left:0; right:0; bottom:0; animation:eco-counter 46s linear infinite;}
@keyframes eco-revolve{from{transform:rotate(0deg);} to{transform:rotate(360deg);}}
@keyframes eco-counter{from{transform:rotate(0deg);} to{transform:rotate(-360deg);}}

.eco-node{position:absolute; left:50%; top:50%; width:22%; height:0; padding-top:22%;}
.eco-node-in{position:absolute; top:0; left:0; right:0; bottom:0; animation:eco-drift 7s ease-in-out infinite;}
.eco-halo{position:absolute; left:-22%; top:-22%; right:-22%; bottom:-22%; border-radius:50%;
  background:radial-gradient(circle, rgba(139,79,212,0.22), transparent 62%);
  filter:blur(8px); opacity:.75; transition:opacity .3s ease;}
.eco-node-card{position:absolute; top:0; left:0; right:0; bottom:0; border-radius:50%;
  background:linear-gradient(158deg,#FFFFFF 0%,#FCFAFE 45%,#F4ECFC 100%);
  border:1.5px solid var(--lilac);
  box-shadow:0 18px 36px -18px rgba(51,21,79,0.34), inset 0 1px 0 rgba(255,255,255,0.9);
  display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center;
  transition:transform .32s var(--ease), box-shadow .32s ease, border-color .32s ease;}
.eco-node:hover .eco-node-card{transform:translateY(-6px) scale(1.045); border-color:var(--purple-bright);}
.eco-node:hover .eco-halo{opacity:1;}
.eco-node-icon{width:34px; height:34px; border-radius:50%; background:var(--lilac-pale);
  color:var(--purple); display:flex; align-items:center; justify-content:center; margin-bottom:8px;}
/* Smart Kids has no separate icon mark, only the wordmark, so this node shows
   the lockup alone rather than an icon-plus-caption pair - the name is
   already in the image, so a repeated text label under it would be redundant.
   Sized to the circle's own chord at that height, so it never touches the
   ring at any width. */
.eco-node-mark{width:auto; height:auto; max-width:80px; object-fit:contain;}
.eco-node b{font-size:var(--t-xs); font-weight:600; color:var(--ink); line-height:1.18;
  padding:0 10px; letter-spacing:-0.005em; text-wrap:balance;}
.eco-node i{font-style:normal; font-size:var(--t-2xs); color:var(--ink-soft); margin-top:3px;}
.eco-n1{transform:translate(-50%,-50%) rotate(0deg)   translateY(-153.8%) translateZ(72px);}
.eco-n2{transform:translate(-50%,-50%) rotate(240deg) translateY(-153.8%) translateZ(52px);}
.eco-n3{transform:translate(-50%,-50%) rotate(120deg) translateY(-153.8%) translateZ(88px);}
.eco-n1 .eco-fix{transform:rotate(0deg);}
.eco-n2 .eco-fix{transform:rotate(-240deg);}
.eco-n3 .eco-fix{transform:rotate(-120deg);}
.eco-n2 .eco-node-in{animation-duration:8.5s; animation-delay:-2.5s;}
.eco-n3 .eco-node-in{animation-duration:9.5s; animation-delay:-5s;}
@keyframes eco-drift{0%,100%{transform:translateY(0);} 50%{transform:translateY(-5px);}}
.eco-orbit2{animation:eco-dash 70s linear infinite;}
@keyframes eco-dash{to{stroke-dashoffset:-220;}}

/* ---------- scroll reveal ---------- */
.reveal{opacity:1;}                       /* default state is visible */
.js-reveal .reveal{opacity:0; transform:translateY(18px);
  transition:opacity .72s var(--ease) var(--d,0ms), transform .72s var(--ease) var(--d,0ms);}
.js-reveal .reveal.in{opacity:1; transform:none;}

/* ---------- floating actions, bottom right ----------
   WhatsApp is always there; back to top only appears once there is something
   to go back up to, and stacks above it so the two never share a spot. */
.wa-float{position:fixed; right:24px; bottom:24px; z-index:60; width:54px; height:54px;
  border-radius:50%; background:#25D366; color:#fff;
  display:flex; align-items:center; justify-content:center;
  box-shadow:0 12px 26px -10px rgba(18,140,63,0.55);
  transition:transform .22s var(--ease), box-shadow .22s ease;}
.wa-float:hover{transform:translateY(-3px); box-shadow:0 16px 30px -10px rgba(18,140,63,0.62);}
.wa-float svg{width:28px; height:28px;}

.totop{position:fixed; right:24px; bottom:90px; z-index:60; width:46px; height:46px;
  border-radius:50%; background:var(--purple); color:#fff; border:none;
  display:flex; align-items:center; justify-content:center;
  box-shadow:0 12px 26px -12px rgba(51,21,79,0.6);
  opacity:0; visibility:hidden; transform:translateY(10px) scale(.9);
  transition:opacity .28s ease, transform .28s var(--ease), visibility .28s, background .2s ease;}
.totop.show{opacity:1; visibility:visible; transform:none;}
.totop:hover{background:var(--purple-deep); transform:translateY(-3px);}

/* ============================================================
   RESPONSIVE — 1024 tablet, 767 phone, 479 small phone
   ============================================================ */
@media (max-width:1024px){
  .nav{grid-template-columns:1fr auto auto; height:64px; padding:0 12px 0 18px; border-radius:20px;}
  .nav-links,.desktop-only{display:none;}
  .nav-toggle{display:flex;}
  .mobile-panel{display:flex; flex-direction:column; gap:2px;
    position:absolute; top:calc(100% + 10px); left:0; right:0; z-index:5;
    background:var(--white); border:1px solid var(--line-strong); border-radius:18px; padding:10px;
    box-shadow:0 20px 44px -18px rgba(51,21,79,0.34);
    opacity:0; visibility:hidden; transform:translateY(-8px);
    transition:opacity .25s ease, transform .25s cubic-bezier(.16,.8,.3,1), visibility .25s;}
  .mobile-panel[data-open="true"]{opacity:1; visibility:visible; transform:translateY(0);}
  .mobile-panel a{display:flex; align-items:center; min-height:44px; padding:0 14px;
    border-radius:10px; font-size:var(--t-sm); color:var(--ink-soft);}
  .mobile-panel a:hover{background:var(--paper-dim); color:var(--purple);}
  .mobile-panel .nav-cta{justify-content:center; color:#fff; margin-top:6px;}
  .hero .wrap,.two-col{grid-template-columns:1fr; gap:44px;}
  .contact-split{grid-template-columns:1fr; gap:40px;}
  /* source order is already invitation, form, details - stacking needs no
     reordering, which keeps tab order matching what is on screen */
  .contact-lead,.contact-direct,.form-card{grid-column:1; grid-row:auto;}
  .contact-direct .thread-divider{margin:0 0 30px;}
  /* stacked, there is no second column to match, so the posters go back to
     their own proportions rather than being cropped to a height they now own */
  .story-art{flex:none; min-height:0; max-width:420px;}
  .story-art img{position:static; height:auto; object-fit:fill;}
  .future-band .future-band-inner{padding-top:48px; padding-bottom:190px;}
  .future-band .band-media img{object-position:78% 100%;}
  .future-band .band-media::after{background:linear-gradient(180deg,
    rgba(37,15,58,0.93) 0%, rgba(37,15,58,0.87) 58%, rgba(37,15,58,0.22) 85%,
    rgba(37,15,58,0.02) 100%);}
  /* stacked, the figure has no column to take its height from, so it is
     given one - without it the absolutely positioned photo collapses */
  .pillar-art{height:340px;}
  .brand-plate{min-height:240px;}
  .emphasis{margin-top:32px;}
  .head-split{grid-template-columns:1fr; gap:28px; margin-bottom:36px;}
  .page-hero-split .wrap{grid-template-columns:1fr; gap:40px;}
  .page-hero-split .lede{max-width:62ch;}
  .hero-art{max-width:560px;}
  .group-card{max-width:560px;}
  .hero-wash img{object-position:88% 50%;}
  .hero-wash::after{background:linear-gradient(180deg,
    rgba(250,247,252,0.90) 0%, rgba(250,247,252,0.72) 46%,
    rgba(250,247,252,0.30) 78%, rgba(250,247,252,0.10) 100%);}
  /* stacked, there is no second column to match, so the poster goes back to
     its own proportions rather than being cropped to a height it now owns */
  .value-grid{grid-template-columns:1fr 1fr; gap:18px 30px;}
  .eco{margin:0 auto; max-width:480px;}
  .gallery-grid{grid-template-columns:1fr 1fr;}
  .pillars,.card-grid,.news-grid{grid-template-columns:1fr;}
  .card-grid > *{grid-column:auto;}
  .strength-grid{grid-template-columns:1fr 1fr;}
  .strength-grid > *{grid-column:auto;}
}
@media (max-width:767px){
  .pillar-art{height:260px;}
  .brand-plate{min-height:200px; padding:28px 22px; gap:20px;}
  /* the role and the address stop fitting on one line at this width */
  .bp-meta{flex-direction:column; gap:9px;}
  .wrap{padding:0 20px;}
  section{padding:30px 0; scroll-margin-top:96px;}
  .site-header{padding:12px 16px;}
  .hero{padding:104px 0 34px;}
  .page-hero{padding:104px 0 29px;}
  .cta-row .btn{flex:1 1 100%; justify-content:center;}
  .cta-banner{padding:32px 26px;}
  .cta-banner .btn{width:100%; justify-content:center;}
  .footer-top{grid-template-columns:1fr 1fr; gap:26px;}
  .form-field input,.form-field select,.form-field textarea{font-size:16px;}
  .wa-float{right:16px; bottom:calc(16px + env(safe-area-inset-bottom,0px));
    width:48px; height:48px;}
  .wa-float svg{width:25px; height:25px;}
  .totop{right:16px; bottom:calc(74px + env(safe-area-inset-bottom,0px)); width:42px; height:42px;}
  .eco{max-width:400px;}
  .eyebrow{font-size:var(--t-md); letter-spacing:0.05em;}
  .brand-logo{height:22px;}
  .eco-core{width:150px;}
  .eco-logo{height:28px;}
  .footer-brand .brand-logo{height:26px;}
  .eco-node-icon{width:26px; height:26px; margin-bottom:6px;}
  .eco-node-icon svg{width:14px; height:14px;}
  .eco-node-mark{max-width:68px;}
  .eco-node b{font-size:var(--t-2xs);}
  .eco-node i{display:none;}
  .contact-detail{flex-direction:column; gap:4px;}
  .contact-detail .k{width:auto;}
  .form-card{padding:24px 20px;}
  .group-card{padding:26px 22px 22px; border-radius:18px;}
  .gc-foot{grid-template-columns:1fr 1fr; gap:16px 20px;}
  .gc-regions{grid-column:1 / -1; justify-content:flex-start; text-align:left;}
  .form-row{grid-template-columns:1fr;}
}
@media (max-width:479px){
  .card-split{grid-template-columns:1fr; gap:24px;}
  .card-art img{max-width:260px;}
  .gallery-grid{grid-template-columns:1fr; gap:18px;}
  .value-grid{grid-template-columns:1fr;}
  .strength-grid{grid-template-columns:1fr;}
  .strength-grid > *{grid-column:auto;}
  .footer-top{grid-template-columns:1fr; gap:22px;}
  .footer-bottom{flex-direction:column; align-items:flex-start;}
  .eco{max-width:330px;}
  /* the circles drop to ~78px here, and a three-word name needs three
     lines - shrink the type and the gap so it stays inside the disc */
  .eco-node b{font-size:10px; line-height:1.14; padding:0 6px;}
  .eco-node-icon{margin-bottom:5px;}
  .eco-node-mark{max-width:54px;}
  .pull-quote{font-size:var(--t-lg); padding-left:18px;}
}
@media (prefers-reduced-motion: reduce){
  *{transition-duration:.001ms !important; scroll-behavior:auto !important;}
  .reveal,.reveal.in{opacity:1 !important; transform:none !important;}
  .eco-scene{transform:none !important;}
  .eco-node-in,.eco-carousel,.eco-spin,.eco-orbit2{animation:none;}
  .eco-orbit{display:none;}
}

/* ============================================================
   Paragraph rhythm.
   The reset zeroes every margin, so prose sitting in a plain
   container had none at all and ran together as one block.
   Component rules (.pillar-card p, .hero .sub and so on) carry
   higher specificity and keep their own spacing.
   ============================================================ */
section p{margin-bottom:16px;}
section p:last-child{margin-bottom:0;}
section li{margin-bottom:0;}
.page-hero .chip-row{margin-top:24px;}

/* ============================================================
   HERO HEADLINE — typewriter
   Education / Skills / Technology type and delete in the same
   place, in brand purple, with "Connected." fixed beneath.

   The h1 carries an aria-label with the whole phrase and the
   moving parts are aria-hidden, so assistive tech reads it once
   and in full rather than announcing every keystroke.
   ============================================================ */
.rotator{display:inline-block;}
.rot-type{color:var(--purple);}
.rot-caret{display:inline-block; width:3px; height:0.78em; margin-left:6px;
  background:var(--purple); vertical-align:baseline; border-radius:1px;
  animation:caret 1s step-end infinite;}
@keyframes caret{0%,100%{opacity:1;} 50%{opacity:0;}}
.rot-fallback{display:none; color:var(--purple);}   /* used only without motion */

@media (prefers-reduced-motion: reduce){
  /* nothing types: show the three words as an ordinary line */
  .rot-type,.rot-caret{display:none;}
  .rot-fallback{display:inline;}
}

/* brand logos in the ring: no lilac chip behind them, since each logo
   carries its own colour and the tint would fight it */
.eco-node-icon.is-logo{background:transparent;}
.eco-node-icon img{width:30px; height:30px; object-fit:contain;}
@media (max-width:767px){
  .eco-node-icon img{width:22px; height:22px;}
}

/* ============================================================
   MOTION PASS
   Entrances vary by what the content is, rather than one fade-up
   everywhere. Grids cascade their own children. All of it is
   transform and opacity only, and all of it stops under
   prefers-reduced-motion at the foot of this file.
   ============================================================ */

/* entrance variants — the .reveal base handles opacity and timing */
.js-reveal .reveal.rv-left  {transform:translateX(-26px);}
.js-reveal .reveal.rv-right {transform:translateX(26px);}
.js-reveal .reveal.rv-scale {transform:scale(.965);}
.js-reveal .reveal.rv-pop   {transform:scale(.86);}
.js-reveal .reveal.rv-tilt  {transform:perspective(1000px) rotateX(8deg) translateY(22px); transform-origin:50% 100%;}
.js-reveal .reveal.in{transform:none;}   /* last, so it beats the variants */

/* page load: the hero arrives rather than appearing */
.hero-in{opacity:0; transform:translateY(16px);
  animation:hero-rise .8s var(--ease) forwards;}
.hero-in:nth-child(2){animation-delay:.08s;}
@keyframes hero-rise{to{opacity:1; transform:none;}}

/* scroll progress, sitting just under the header */
.scroll-progress{position:fixed; top:0; left:0; right:0; height:2px; z-index:60;
  background:transparent; pointer-events:none;}
.scroll-progress span{display:block; height:100%; width:0;
  background:linear-gradient(90deg, var(--purple-bright), var(--purple));
  transition:width .1s linear;}

/* ---- hover: a little more life on the cards ---- */
.news-thumb{transition:transform .5s var(--ease);}
.news-card:hover .news-thumb{transform:scale(1.05);}
.news-card{position:relative;}

.strength-tile{position:relative; overflow:hidden;}
.strength-tile::after{content:""; position:absolute; left:0; top:0; bottom:0; width:3px;
  background:var(--purple); transform:scaleY(0); transform-origin:top;
  transition:transform .34s var(--ease);}
.strength-tile:hover::after{transform:scaleY(1);}

.info-card{position:relative; overflow:hidden;}
.info-card::after{content:""; position:absolute; left:0; right:0; bottom:0; height:3px;
  background:var(--purple); transform:scaleX(0); transform-origin:left;
  transition:transform .38s var(--ease);}
.info-card:hover::after{transform:scaleX(1);}

.value-list li{border-radius:8px; padding:6px 10px; margin-left:-10px;
  transition:background .24s ease, transform .24s var(--ease);}
.value-list li:hover{background:var(--paper-dim); transform:translateX(4px);}

.pillar-card .pillar-tag{transition:letter-spacing .3s var(--ease);}
.pillar-card:hover .pillar-tag{letter-spacing:0.2em;}

.contact-detail{transition:background .24s ease;}
.contact-detail:hover{background:var(--paper-dim);}

@media (prefers-reduced-motion: reduce){
  .eco-wash,.eco-bead{display:none;}
  .eco-link{transform:scaleX(1);}
  .eco-head,.eco-note,.eco-stage .pillar-card,.eco-stage .pillar-card > *{
    opacity:1 !important; transform:none !important;}
  [data-beat]{opacity:1 !important; transform:none !important;}
  .hero-in{animation:none; opacity:1; transform:none;}
  .scroll-progress{display:none;}
  .news-card:hover .news-thumb{transform:none;}
  .strength-tile::after,.info-card::after{transition:none;}
}
