/* ============================================================
   SpotAcademy - spotacademy.co.il
   Same design language as SpotGroup and SpotNet ("Leo" edition):
   black canvas, huge light typography, orange gradient emphasis,
   rounded media cards, clip-path reveals.
   Bi-directional: English (LTR, default) + Hebrew (RTL).
   The shared parts are SpotNet's, verbatim; what the academy adds
   sits in the SPOTACADEMY section at the foot of the file.
   ============================================================ */

:root {
  /* Brand */
  --orange: #F37021;
  --orange-bright: #FF8A3D;
  --orange-deep: #FF9A52;
  --orange-glow: rgba(243, 112, 33, 0.35);
  --orange-soft: rgba(243, 112, 33, 0.16);
  --orange-50: rgba(243, 112, 33, 0.13);
  /* the swipe hint's arrow, inlined so the mask needs no second request */
  --swipe-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 5l7 7-7 7'/%3E%3C/svg%3E");

  /* Emphasis gradient - saturated to cream, flipped for RTL below */
  --grad-word: linear-gradient(to right, #FF7A1E 0%, #FFB26B 55%, #FFE3C4 100%);

  /* Dark scale - warm charcoal, no blue cast */
  --bg: #000000;
  --bg-soft: #0C0A08;
  --card: #12100D;
  --card-2: #191512;
  --line: rgba(255, 255, 255, 0.10);
  --line-soft: rgba(255, 255, 255, 0.06);

  /* Text */
  --text-1: #FFFFFF;
  --text-2: rgba(255, 255, 255, 0.75);
  --text-3: rgba(255, 255, 255, 0.55);
  --muted: rgba(255, 255, 255, 0.60);

  /* Effects */
  --shadow-md: 0 10px 30px -10px rgba(0,0,0,0.6);
  --shadow-lg: 0 30px 80px -20px rgba(0,0,0,0.75);
  --shadow-orange: 0 16px 44px -12px rgba(243,112,33,0.5);

  /* Radii */
  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 24px;
  --r-xl: 32px;
  --r-pill: 999px;

  /* Type */
  --font-display: 'Rubik', system-ui, sans-serif;
  --font-body: 'Inter', 'Rubik', system-ui, sans-serif;

  /* Motion - the Leo curve */
  --ease-leo: cubic-bezier(0.165, 0.84, 0.44, 1);
  --dur-leo: 1.2s;

  /* pointer position, written by the effects engine */
  --mx: 50%;
  --my: 50%;
}

[dir="rtl"] {
  --grad-word: linear-gradient(to left, #FF7A1E 0%, #FFB26B 55%, #FFE3C4 100%);
  --font-body: 'Assistant', 'Rubik', system-ui, sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }

html, body {
  font-family: var(--font-body);
  background: var(--bg);
  color: var(--text-2);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  line-height: 1.6;
  overflow-x: clip;
}

::selection { background: rgba(243,112,33,0.35); color: #fff; }

a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; border: none; background: none; color: inherit; }
img { display: block; max-width: 100%; }

/* language visibility - JS sets the html[data-lang] attribute */
[data-lang="en"] .only-he { display: none !important; }
[data-lang="he"] .only-en { display: none !important; }

/* ============================================================
   Layout
   ============================================================ */
.container { width: min(1320px, 92%); margin-inline: auto; }
.container-narrow { width: min(1040px, 92%); margin-inline: auto; }

section { padding: 130px 0; position: relative; }
@media (max-width: 768px) { section { padding: 84px 0; } }

.glow-spot {
  position: absolute;
  width: 70vw; height: 70vw;
  max-width: 900px; max-height: 900px;
  border-radius: 50%;
  background: radial-gradient(circle at center, rgba(243,112,33,0.16) 0%, rgba(243,112,33,0.05) 40%, transparent 70%);
  filter: blur(40px);
  pointer-events: none;
  z-index: 0;
}

/* ============================================================
   Eyebrows
   ============================================================ */
/* Kept only where a label genuinely earns its place - a partner
   status, a section that needs naming. Never above every heading. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0.01em;
  color: var(--orange-bright);
}
.eyebrow::before {
  content: "";
  width: 24px; height: 1px;
  background: var(--orange);
  opacity: .7;
}
.eyebrow.on-dark { color: var(--orange-bright); }

/* ============================================================
   Typography - huge & light
   ============================================================ */
.display-1 {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(44px, 7vw, 104px);
  line-height: 1.04;
  letter-spacing: -0.01em;
  color: var(--text-1);
}
.display-2 {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(36px, 5vw, 76px);
  line-height: 1.08;
  letter-spacing: -0.005em;
  color: var(--text-1);
}
.display-3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(26px, 3vw, 42px);
  line-height: 1.15;
  color: var(--text-1);
}

.gradient-text,
.display-1 strong, .display-2 strong, .display-3 strong,
h1 strong, h2 strong {
  font-weight: inherit;
  background: var(--grad-word);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.lede {
  font-size: clamp(16.5px, 1.35vw, 20px);
  line-height: 1.75;
  color: var(--text-3);
  font-weight: 300;
  max-width: 62ch;
}
.lede.on-dark { color: var(--text-2); }

/* ============================================================
   Buttons
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 30px;
  border-radius: var(--r-pill);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 15.5px;
  letter-spacing: 0.01em;
  transition: transform .45s var(--ease-leo), box-shadow .45s var(--ease-leo),
              background .3s, color .3s, border-color .3s;
  white-space: nowrap;
}
.btn-primary {
  /* bright to base, the same way round as the group's pill */
  background: linear-gradient(135deg, var(--orange-bright), var(--orange));
  color: #fff;
  box-shadow: var(--shadow-orange);
}
.btn-primary:hover { transform: translateY(-3px); box-shadow: 0 24px 60px -12px rgba(243,112,33,0.65); }

.btn-ghost {
  border: 1px solid rgba(255,255,255,0.25);
  color: #fff;
  background: transparent;
}
.btn-ghost:hover { background: #fff; color: #000; border-color: #fff; }
.btn-ghost.on-dark { color: #fff; border-color: rgba(255,255,255,0.25); background: transparent; }
.btn-ghost.on-dark:hover { background: #fff; color: #000; border-color: #fff; }

.btn-light { background: #fff; color: #000; }
.btn-light:hover { transform: translateY(-3px); }

.btn .arrow { width: 18px; height: 18px; transition: transform .45s var(--ease-leo); flex-shrink: 0; }
.btn:hover .arrow { transform: translateX(4px); }
[dir="rtl"] .btn .arrow { transform: scaleX(-1); }
[dir="rtl"] .btn:hover .arrow { transform: scaleX(-1) translateX(4px); }

/* ============================================================
   Header - floating white card (Leo nav)
   Every rule here is the group's rule, verbatim: the pill, the nav,
   the language chip and the drawer are one component shared by
   spot-group.co.il, spotnet.co.il and spotacademy.co.il. Only the
   logo width differs.
   ============================================================ */
.site-header {
  position: fixed;
  inset-inline: 0;
  top: 22px;
  z-index: 900;
  pointer-events: none;
  transition: top .5s var(--ease-leo);
}
.site-header.scrolled { top: 12px; }

/* The unified group header: glass pill, 72px tall */
.header-pill {
  pointer-events: auto;
  width: min(1320px, 94%);
  margin-inline: auto;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 20px;
  background: rgba(255,255,255,0.94);
  backdrop-filter: blur(22px);
  -webkit-backdrop-filter: blur(22px);
  color: #0A0A0E;
  border: 1px solid rgba(0,0,0,0.06);
  border-radius: 999px;
  min-height: 72px;
  padding: 0 18px;
  box-shadow: 0 10px 40px -14px rgba(0,0,0,0.5);
  transition: box-shadow .5s var(--ease-leo), min-height .5s var(--ease-leo), background .5s var(--ease-leo);
}
.site-header.scrolled .header-pill {
  background: rgba(255,255,255,0.98);
  box-shadow: 0 14px 50px -14px rgba(0,0,0,0.55);
  min-height: 64px;
}

.brand-link {
  display: flex;
  align-items: center;
  /* No horizontal padding.

     The pill pads its own edges, so the brand box and the call to action
     both start 19px in - but the button's padding sits inside its coloured
     background, and the brand's sat outside the ink. The button's visible
     edge landed at 19px and the wordmark's at 33px, and the eye compares
     the two things it can see, not the two boxes. Vertical padding stays:
     that is the tap target, and it costs nothing across. */
  padding: 10px 0;
}
/* The academy mark is a 7.34:1 lockup (1953x266): a shield with the
   mortarboard, then a longer wordmark. SpotNet's is 4.47:1 (1525x341)
   and sits at 168px wide, which makes it 37.6px tall. Copying that
   width would put this one at 22.9px - visibly the smaller brand in the
   same pill - so the two are matched on height instead, and on the
   height that is actually read: the wordmark's capitals. Measured from
   the files' own ink, SPOTNET runs 115px of a 341px box and SPOTACADEMY
   98px of a 266px box. At 168px wide SpotNet's capitals are 12.7px
   tall; the academy's reach 12.7px at 34.4px of box height, which is
   252px wide. Matching the whole box instead (37.6px, 276px wide) would
   set the academy's type 16% larger than SpotNet's, because its shield
   takes less of the height. The pill has the room: at 1181px, the
   narrowest width the nav is still shown at, 252px leaves the six
   English items about 60px to spare. Written as a width so the phone
   rule below can clamp it the same way it clamps SpotNet's. */
.brand-link img { width: 252px; height: auto; max-width: none; display: block; flex-shrink: 0; }

.primary-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-width: 0;
}
.primary-nav a {
  padding: 10px 15px;
  border-radius: var(--r-pill);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 15px;
  color: #26262E;
  white-space: nowrap;
  transition: background .25s, color .25s;
}
.primary-nav a:hover { background: rgba(243,112,33,0.10); color: #C2570E; }
.primary-nav a.active {
  background: #0A0A0E;
  color: #fff;
}

/* ---- Services, as a disclosure ------------------------------
   Open on hover for a pointer, on :focus-within for a keyboard (no
   script needed for either), and on the caret for a touch screen.
   The panel is adjacent to the item and the whole item stays hovered
   while the pointer travels into it, which is what 1.4.13 asks for. */
.nav-item { position: relative; display: flex; align-items: center; }
.nav-item > a { padding-inline-end: 8px; }
/* On a service page the pill has to hold the caret too. With the
   background on the link, the pill stopped at the word and the caret
   floated beside it as a second, unrelated thing. */
.nav-item.active-branch {
  background: #0A0A0E;
  border-radius: var(--r-pill);
  padding-inline-end: 9px;
}
.nav-item.active-branch > a.active { background: none; }
.nav-item.active-branch .sub-toggle { color: #fff; opacity: .7; }
.nav-item.active-branch:hover .sub-toggle,
.nav-item.active-branch:focus-within .sub-toggle { color: #fff; opacity: 1; }
.sub-toggle {
  display: flex; align-items: center; justify-content: center;
  width: 22px; height: 26px;
  margin-inline-start: -6px;
  border-radius: var(--r-pill);
  color: #26262E;
  opacity: .65;
  transition: transform .3s var(--ease-leo), opacity .25s, color .25s;
}
.nav-item:hover .sub-toggle,
.nav-item:focus-within .sub-toggle { opacity: 1; color: #C2570E; }
.sub-toggle[aria-expanded="true"] { transform: rotate(180deg); }

.subnav {
  position: absolute;
  top: calc(100% + 14px);
  inset-inline-start: 50%;
  transform: translateX(-50%) translateY(-6px);
  min-width: 232px;
  padding: 8px;
  list-style: none;
  border-radius: var(--r-md);
  border: 1px solid rgba(0,0,0,0.07);
  background: rgba(255,255,255,0.98);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  box-shadow: 0 18px 50px -16px rgba(0,0,0,0.35);
  opacity: 0;
  visibility: hidden;
  transition: opacity .28s var(--ease-leo), transform .28s var(--ease-leo), visibility .28s;
}
/* the gap between the pill and the panel would drop the hover, so the
   item's own hitbox is extended across it */
.nav-item.has-sub::after {
  content: "";
  position: absolute;
  top: 100%; inset-inline: -10px;
  height: 16px;
}
.nav-item:hover .subnav,
.nav-item:focus-within .subnav,
.subnav.open {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}
[dir="rtl"] .nav-item:hover .subnav,
[dir="rtl"] .nav-item:focus-within .subnav,
[dir="rtl"] .subnav.open { transform: translateX(50%) translateY(0); }

[dir="rtl"] .subnav { transform: translateX(50%) translateY(-6px); }

.subnav a {
  display: block;
  padding: 9px 13px;
  border-radius: var(--r-sm);
  font-family: var(--font-display);
  font-size: 14.5px;
  font-weight: 400;
  color: #26262E;
  white-space: nowrap;
  transition: background .2s, color .2s;
}
.subnav a:hover { background: rgba(243,112,33,0.10); color: #C2570E; }
/* Where you are, not a second black pill. A filled slab inside a white
   card is the heaviest thing on the panel and it repeats the treatment
   the nav item above is already using - two of them, stacked, for one
   piece of information. This is the accent doing the job it does
   everywhere else on the site: a warm ground, the brand colour at a
   weight that passes AA on it, and a mark down the leading edge. */
.subnav a.here {
  background: rgba(243,112,33,0.13);
  color: #B04E0A;
  font-weight: 500;
}
.subnav a.here::before {
  content: "";
  position: absolute;
  inset-inline-start: 8px;
  top: 50%;
  width: 3px;
  height: 17px;
  border-radius: 2px;
  background: var(--orange);
  transform: translateY(-50%);
}
.subnav li { position: relative; }
.subnav a.here:hover { background: rgba(243,112,33,0.18); color: #B04E0A; }
.subnav-all { margin-top: 6px; padding-top: 6px; border-top: 1px solid rgba(0,0,0,0.07); }
.subnav-all a { color: var(--orange); font-weight: 500; }

/* dismissed with Escape - held shut until the pointer or the focus leaves,
   so returning focus to the caret cannot re-open it through :focus-within */
.nav-item.hushed .subnav { opacity: 0 !important; visibility: hidden !important; }

/* a coarse pointer has no hover to open it with, so only the caret does */
@media (hover: none), (pointer: coarse) {
  .nav-item:hover .subnav { opacity: 0; visibility: hidden; }
  .subnav.open { opacity: 1 !important; visibility: visible !important; }
}

/* the drawer folds them behind a caret, indented under Services */
.mobile-drawer .drawer-sub {
  font-size: 17px;
  opacity: .72;
  padding-inline-start: 22px;
}
.mobile-drawer .drawer-head { display: flex; align-items: center; }
.mobile-drawer .drawer-head > a { flex: 1; min-width: 0; }

/* the caret is its own control, so the label beside it can stay a link.
   It takes the drawer link's padding rather than the header caret's,
   which makes it a 45px target - a finger, not a pointer. */
.mobile-drawer .drawer-toggle {
  padding: 15px 16px;
  border-radius: 14px;
  color: #0A0A0E;
  transition: background .25s, color .25s;
}
.mobile-drawer .drawer-toggle svg {
  width: 15px; height: 15px;
  transition: transform .38s var(--ease-leo);
}
.mobile-drawer .drawer-toggle:hover { background: rgba(243,112,33,0.10); color: #C2570E; }
.mobile-drawer .drawer-group.open .drawer-toggle svg { transform: rotate(180deg); }

/* Folded by height rather than by display, so it slides rather than
   jumps - 0fr to 1fr, which needs no measuring in script. The inner
   wrapper carries the overflow (which is also what lets the row
   collapse past its content) and the visibility, so the seven links
   leave the tab order while they are folded away: a link you cannot
   see but can still tab into is a trap for the one person who has no
   way of telling where the focus went. */
.mobile-drawer .drawer-subs {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .38s var(--ease-leo);
}
.mobile-drawer .drawer-subs > div {
  overflow: hidden;
  visibility: hidden;
  display: flex;
  flex-direction: column;
  gap: 2px;
  transition: visibility .38s;
}
.mobile-drawer .drawer-group.open .drawer-subs { grid-template-rows: 1fr; }
.mobile-drawer .drawer-group.open .drawer-subs > div { visibility: visible; }

@media (prefers-reduced-motion: reduce) {
  .mobile-drawer .drawer-subs,
  .mobile-drawer .drawer-subs > div,
  .mobile-drawer .drawer-toggle svg { transition: none; }
}

.header-cta { display: flex; gap: 10px; align-items: center; justify-self: end; min-width: 0; }
.header-cta .btn { padding: 11px 22px; font-size: 14.5px; white-space: nowrap; }

/* language switch (en <-> he) - lives in the header pill and in the drawer */
.lang-switch {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--font-display);
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: .02em;
  color: #12100D;
  white-space: nowrap;
  transition: border-color .25s, color .25s, background .25s;
}
.lang-switch:hover {
  color: #000;
  border-color: rgba(243,112,33,0.55);
  background: rgba(243,112,33,0.08);
}
.lang-switch svg { flex-shrink: 0; opacity: .75; }
.lang-switch:hover svg { opacity: 1; }

.menu-toggle { display: none; color: #0A0A0E; padding: 10px; border-radius: 12px; }
.menu-toggle:hover { background: rgba(0,0,0,0.06); }

/* the nav needs a little more room before it hands over to the drawer */
@media (max-width: 1400px) {
  .primary-nav { gap: 0; }
  .primary-nav a { padding-inline: 11px; font-size: 14.5px; }
}
@media (max-width: 1260px) {
  .primary-nav a { padding-inline: 9px; font-size: 14px; }
  .header-pill { gap: 12px; }
}
/* Seven items now that Contact is one of them, and the English strings
   are the long ones: at 1190px "Contact" was being clipped by 2px
   against the language switch. The nav hands over to the drawer 60px
   earlier rather than shaving another pixel off the padding. */
@media (max-width: 1320px) {
  .primary-nav { display: none; }
  .menu-toggle { display: inline-flex; }
}
@media (max-width: 1100px) {
  /* Between 560 and 1100 the drawer carries it; below 560 the header
     takes it back. That rule sits earlier in this file, so the range is
     closed here - same specificity means the last one wins. */
  .header-cta .lang-switch { display: none; }
@media (max-width: 560px) {
  .header-cta .lang-switch { display: inline-flex; }
}   /* drawer carries it below this */
}
@media (max-width: 560px) {
  .header-cta .btn-primary { display: none; }
  .site-header { top: 12px; }

  /* On a phone the pill holds the mark and the burger and nothing else.
     Laid out as "mark, then everything else" the mark sits hard against
     the reading edge while the burger drifts to the far side, and the
     gap between them grows with the screen - two items sharing a bar
     rather than a header. Centred, it reads as one.

     Three columns, mark in the middle, burger in the last, and the two
     outer columns take an equal share of what is left - so the mark is
     centred on the pill rather than on whatever happens to sit beside
     it. RTL flows the grid the other way and the burger stays on the
     far side, which is where it already was in both languages.

     The mark keeps its full 252px down to about 420px of viewport and
     gives back only what a narrower screen cannot spare: the width left
     for it is the pill less its 36px of padding, less the language chip
     and the burger at 42px each, less the two 12px gaps. The gap is 12
     because a max-width:1260px rule above sets it - matching that is
     steadier than racing it. The brand's own side padding goes on a
     phone: the 7.34:1 lockup is the widest mark in the group, and the
     pill's width, not the mark's proportions, is what sets its height
     here - at 390px it gets 222px, which is 30px tall, against the 34px
     it has on a desktop. Every pixel of width is 0.14px of height, and
     the gaps already keep it clear of its neighbours. */
  .header-pill { grid-template-columns: 1fr auto 1fr; }
  .brand-link { grid-column: 2; padding-inline: 0; }
  .brand-link img { width: min(252px, calc(94vw - 144px)); }
  /* The mark is centred, and it did not look it: the two side columns
     were the same width, but one held the menu button and the other
     held nothing, and the eye weighs ink rather than columns. So the
     pair is split, one to each side, matched in size.

     display:contents dissolves the wrapper so its children become grid
     items and can take a column each. Each names its row as well: auto
     placement only moves forward, so an item asking for column 1 after
     the mark has taken column 2 opens a second row instead, and the
     pill grows to twice its height. */
  .header-cta { display: contents; }
  .header-pill .brand-link { grid-row: 1; grid-column: 2; }
  .header-cta .lang-switch { display: inline-flex; grid-row: 1; grid-column: 1; justify-self: start; }
  .header-cta .menu-toggle { grid-row: 1; grid-column: 3; justify-self: end; }

  /* Matched to the menu button so the two sides carry the same weight.
     The globe goes - at this size it is a smudge, and the label already
     says the whole thing. */
  .header-cta .lang-switch {
    width: 42px; height: 42px; padding: 0;
    justify-content: center; gap: 0;
    font-size: 12.5px; letter-spacing: .04em;
  }
  .header-cta .lang-switch svg { display: none; }
}

/* Mobile drawer - white card, Leo-style */
.mobile-drawer {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.6);
  backdrop-filter: blur(8px);
  z-index: 999;
  opacity: 0;
  pointer-events: none;
  transition: opacity .4s var(--ease-leo);
}
.mobile-drawer.open { opacity: 1; pointer-events: auto; }
.mobile-drawer .panel {
  position: absolute;
  top: 12px; inset-inline: 3%;
  background: #fff;
  color: #0A0A0E;
  border-radius: 22px;
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  transform: translateY(-16px) scale(0.98);
  opacity: 0;
  transition: transform .5s var(--ease-leo), opacity .4s var(--ease-leo);
  box-shadow: 0 30px 80px -20px rgba(0,0,0,0.8);
  /* the drawer carries more links than the group's - let a short screen scroll */
  max-height: calc(100dvh - 24px);
  overflow-y: auto;
}
.mobile-drawer.open .panel { transform: translateY(0) scale(1); opacity: 1; }
.mobile-drawer .panel a {
  padding: 15px 16px;
  border-radius: 14px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 19px;
  color: #0A0A0E;
}
.mobile-drawer .panel a:hover { background: rgba(243,112,33,0.10); color: #C2570E; }
.mobile-drawer .close { align-self: flex-end; padding: 10px; border-radius: 12px; color: #0A0A0E; }
.mobile-drawer .close:hover { background: rgba(0,0,0,0.06); }
.mobile-drawer .drawer-sep { height: 1px; background: rgba(0,0,0,0.08); margin: 10px 8px; }

/* the language chip sits in the drawer below 1100px. On the group it is an
   <a>, so it inherits the drawer's link styling; here it is a <button> and
   has to be told the same numbers to land in the same place. */
.mobile-drawer .lang-switch {
  margin-top: 18px;
  padding: 15px 16px;
  border-radius: 14px;
  border-color: var(--line-soft);
  font-size: 19px;
  font-weight: 400;
  color: #0A0A0E;
}
.mobile-drawer .lang-switch:hover { background: rgba(243,112,33,0.10); color: #C2570E; border-color: var(--line-soft); }

/* ============================================================
   Reveal engine
   ============================================================ */
.reveal, .fade-up, .lv {
  opacity: 0;
  transform: translateY(30px);
  transition: opacity var(--dur-leo) var(--ease-leo), transform var(--dur-leo) var(--ease-leo);
}
.reveal.in, .fade-up.in, .lv.in { opacity: 1; transform: none; }

/* transform is in the list for the element that carries .reveal as
   well - the lab figure does - so its rise runs with the unclipping
   instead of snapping the moment .in lands */
.lv-card {
  clip-path: inset(14% 8% 14% 8% round var(--r-xl));
  opacity: 0;
  transition: clip-path 1.4s var(--ease-leo), opacity .9s var(--ease-leo), transform var(--dur-leo) var(--ease-leo);
}
.lv-card.in { clip-path: inset(0% 0% 0% 0% round var(--r-xl)); opacity: 1; }

.lv-words .w {
  display: inline-block;
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .9s var(--ease-leo), transform .9s var(--ease-leo);
  transition-delay: calc(var(--wi) * 45ms);
}
.lv-words.in .w { opacity: 1; transform: none; }

.d1 { transition-delay: .12s; }
.d2 { transition-delay: .24s; }
.d3 { transition-delay: .38s; }
.d4 { transition-delay: .52s; }
.d5 { transition-delay: .66s; }

@media (prefers-reduced-motion: reduce) {
  .reveal, .fade-up, .lv, .lv-card, .lv-words .w {
    opacity: 1 !important; transform: none !important; clip-path: none !important;
    transition: none !important;
  }
  html { scroll-behavior: auto; }
}

/* ============================================================
   Hero
   ============================================================ */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  overflow: hidden;
  padding: 160px 0 120px;
}
.hero-media {
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: .92;
}
.hero-media video, .hero-media img {
  width: 100%; height: 100%;
  object-fit: cover;
  filter: brightness(0.4) saturate(0.6) contrast(1.18);
}
.hero::after {
  content: "";
  position: absolute; inset: 0;
  background:
    radial-gradient(ellipse at 50% 45%, transparent 20%, rgba(0,0,0,0.55) 78%),
    linear-gradient(to bottom, rgba(0,0,0,0.55) 0%, transparent 28%, transparent 55%, #000 100%);
  z-index: 1;
  pointer-events: none;
}
.hero-content {
  position: relative;
  z-index: 2;
  width: min(1000px, 92%);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 26px;
}
.hero-content .eyebrow { justify-content: center; }
.hero-sub { color: var(--text-2); font-size: clamp(16.5px, 1.35vw, 20px); font-weight: 300; max-width: 64ch; }
.hero-ctas { display: flex; gap: 14px; flex-wrap: wrap; justify-content: center; }

.scroll-cue {
  position: absolute;
  bottom: 34px;
  inset-inline: 0;
  z-index: 3;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  color: var(--text-3);
  font-size: 13px;
  font-family: var(--font-display);
  font-weight: 400;
}
/* The line used to draw itself in and wipe itself out every 2.4s,
   which at one pixel wide reads as a flicker rather than as a hint.
   It is a standing line now, with the light easing down it. */
.scroll-cue .line {
  width: 1px; height: 46px;
  background: linear-gradient(to bottom, rgba(255,255,255,0.28), rgba(255,255,255,0.06));
  position: relative;
  overflow: hidden;
}
.scroll-cue .line::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: -40%;
  height: 40%;
  background: linear-gradient(to bottom, transparent, rgba(255,255,255,0.75));
  animation: cueFall 3.6s var(--ease-leo) infinite;
}
@keyframes cueFall {
  0% { transform: translateY(0); opacity: 0; }
  18% { opacity: 1; }
  75% { transform: translateY(350%); opacity: 0; }
  100% { transform: translateY(350%); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .scroll-cue .line::after { animation: none; opacity: 0; } }

/* group ribbon above the hero headline */
.group-tag {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px 8px 10px;
  border-radius: var(--r-pill);
  border: 1px solid rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.05);
  backdrop-filter: blur(10px);
  color: var(--text-2);
  font-size: 13.5px;
  transition: all .4s var(--ease-leo);
}
[dir="rtl"] .group-tag { padding: 8px 10px 8px 16px; }
.group-tag:hover { border-color: rgba(243,112,33,0.5); background: rgba(243,112,33,0.10); color: #fff; }
.group-tag img { height: 13px; width: auto; filter: brightness(0) invert(1); opacity: .9; }
.group-tag .gt-sep { width: 1px; height: 15px; background: rgba(255,255,255,0.22); }

@media (max-width: 560px) {
  .hero { padding: 140px 0 100px; }
  .group-tag { font-size: 12px; padding: 7px 13px; gap: 8px; }
  .group-tag img { height: 10px; }
  .group-tag .gt-sep { height: 12px; }
  .hero .display-1 { font-size: clamp(34px, 9vw, 46px); }
  .hero-ctas { width: 100%; flex-direction: column; align-items: stretch; }
  .hero-ctas .btn { justify-content: center; }
}

/* The Hebrew headline is two lines by design - the offer on the first,
   "תחת קורת גג אחת" on the second - and the <br /> in the markup only
   ever guaranteed the second. The first had to fit the column on its
   own, and it stopped doing that at both ends: from 1440px up the type
   sits at its 104px ceiling while the column is capped at 1000px, and at
   440px the column is 92vw with nothing spare. Both broke "סייבר" onto a
   line of its own and made a two-line headline into three.

   Measured in this face the line runs 10.58 times the font size, and the
   column is min(1000px, 92vw), so the size that always fits it is
   min(94.5px, 8.7vw). Taken a little under that, and written as a
   ceiling rather than as the size, so it only bites where the line would
   otherwise break and the middle widths keep the curve they had.

   English is deliberately not given the same ceiling. "Connectivity,
   cloud and cyber security" runs 18.85 times its size - holding it on
   one line would mean 53px where the Hebrew gets 93px, which is a
   different headline rather than a translated one. English wraps and
   keeps the scale; the <br /> still starts "under one roof" on its own
   line, which is the part that carries the meaning. */
[dir="rtl"] .hero .display-1 { font-size: min(clamp(44px, 7vw, 104px), 8.6vw, 93px); }
@media (max-width: 560px) {
  [dir="rtl"] .hero .display-1 { font-size: min(clamp(34px, 9vw, 46px), 8.6vw, 93px); }
}

/* ============================================================
   Sub-page hero
   ============================================================ */
.subpage-hero {
  position: relative;
  padding: 210px 0 110px;
  overflow: hidden;
  background: var(--bg);
}
/* A page header with no film gets the same drawn horizon as the home
   hero, at a smaller scale - so the site never depends on footage. */
.subpage-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(50% 22% at 50% 100%, rgba(255,214,166,0.14) 0%, transparent 72%),
    radial-gradient(120% 52% at 50% 104%, rgba(243,112,33,0.28) 0%, rgba(243,112,33,0.06) 44%, transparent 74%);
}
.subpage-hero:not(.has-media)::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 1px;
  background: linear-gradient(to right, transparent, rgba(255,178,107,0.35) 26%, rgba(255,214,166,0.5) 50%, rgba(255,178,107,0.35) 74%, transparent);
  pointer-events: none;
}
.subpage-hero.has-media::before { display: none; }
.subpage-hero .container { position: relative; z-index: 1; }
.subpage-hero-grid { display: grid; grid-template-columns: 1.15fr .85fr; gap: 60px; align-items: center; }
@media (max-width: 900px) { .subpage-hero-grid { grid-template-columns: 1fr; } }
.subpage-hero .display-1 { margin: 22px 0; font-size: clamp(38px, 5.4vw, 80px); }

.page-hero-media { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.page-hero-media video, .page-hero-media img {
  width: 100%; height: 100%; object-fit: cover;
  filter: brightness(0.42) saturate(0.7) contrast(1.1);
}
/* two scrims: one down the page so the header clears, one across the
   reading side so a bright frame never swallows the headline */
.page-hero-media::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(to right, rgba(0,0,0,0.86) 0%, rgba(0,0,0,0.62) 42%, rgba(0,0,0,0.25) 78%),
    linear-gradient(to bottom, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.35) 40%, #000 100%);
}
[dir="rtl"] .page-hero-media::after {
  background:
    linear-gradient(to left, rgba(0,0,0,0.86) 0%, rgba(0,0,0,0.62) 42%, rgba(0,0,0,0.25) 78%),
    linear-gradient(to bottom, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.35) 40%, #000 100%);
}
.subpage-hero.has-media { padding: 250px 0 130px; }
.subpage-hero.has-media .subpage-hero-grid { grid-template-columns: 1fr; max-width: 880px; }

.brand-logo-large { height: 40px; width: auto; margin-bottom: 22px; display: block; }

.breadcrumbs {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 14px;
  color: var(--text-3); margin-bottom: 22px;
}
.breadcrumbs .sep { color: rgba(255,255,255,0.22); }
.breadcrumbs .crumb-here { color: var(--orange-bright); }
.breadcrumbs a:hover { color: var(--orange-bright); }

/* ============================================================
   Chips
   ============================================================ */
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  padding: 8px 16px;
  border-radius: var(--r-pill);
  border: 1px solid rgba(255,255,255,0.14);
  background: rgba(255,255,255,0.03);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 13.5px;
  color: var(--text-2);
  transition: all .35s var(--ease-leo);
}
.chip:hover { border-color: rgba(243,112,33,0.45); color: #fff; }

/* ============================================================
   Stats
   ============================================================ */
.stats-strip { padding: 84px 0; background: var(--card); border-block: 1px solid var(--line); }
.stats-strip .grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; }
@media (max-width: 860px) { .stats-strip .grid { grid-template-columns: repeat(2, 1fr); gap: 40px 24px; } }
.stat { text-align: center; }
.stat .num {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(40px, 4.4vw, 58px);
  line-height: 1;
  letter-spacing: -0.02em;
  background: linear-gradient(135deg, var(--orange), var(--orange-bright));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.stat .label { color: var(--text-3); font-size: 14.5px; margin-top: 14px; line-height: 1.55; }

/* ============================================================
   Section head
   ============================================================ */
.section-head { max-width: 780px; }
.section-head .display-2 { margin-top: 22px; }
.section-head .lede { margin-top: 24px; }
.section-head.center { margin-inline: auto; text-align: center; }
.section-head.center .lede { margin-inline: auto; }
.section-head.center .eyebrow { justify-content: center; }

/* ============================================================
   Service rail - numbered rows
   ============================================================ */
.service-rail { margin-top: 64px; border-top: 1px solid var(--line); }
.service-row {
  position: relative;
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  align-items: center;
  gap: 28px;
  padding: 32px 20px;
  border-bottom: 1px solid var(--line);
  transition: all .5s var(--ease-leo);
}
.service-row::before {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to right, rgba(243,112,33,0.08), transparent 62%);
  opacity: 0;
  transition: opacity .5s var(--ease-leo);
  pointer-events: none;
}
[dir="rtl"] .service-row::before { background: linear-gradient(to left, rgba(243,112,33,0.08), transparent 62%); }
.service-row:hover::before { opacity: 1; }
.service-row .idx {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 14px;
  color: var(--text-3);
  min-width: 30px;
  transition: color .4s var(--ease-leo);
}
.service-row:hover .idx { color: var(--orange-bright); }
.service-row .sr-tile {
  width: 78px; height: 78px;
  border-radius: 18px;
  overflow: hidden;
  flex-shrink: 0;
  border: 1px solid var(--line);
  background: var(--card-2);
  transition: transform .5s var(--ease-leo);
}
.service-row .sr-tile img { width: 100%; height: 100%; object-fit: cover; }
.service-row:hover .sr-tile { transform: translateY(-4px) scale(1.04); }
.service-row h3 { font-family: var(--font-display); font-size: clamp(20px, 2vw, 27px); font-weight: 400; color: var(--text-1); margin-bottom: 8px; }
.service-row p { color: var(--text-3); font-size: 15.5px; line-height: 1.7; max-width: 66ch; }
.service-row .sr-go {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--orange-bright);
  font-family: var(--font-display); font-weight: 500; font-size: 15px;
  white-space: nowrap;
  opacity: .75;
  transition: all .4s var(--ease-leo);
}
.service-row:hover .sr-go { opacity: 1; gap: 12px; }
.service-row .sr-go svg { width: 16px; height: 16px; }
[dir="rtl"] .service-row .sr-go svg { transform: scaleX(-1); }
@media (max-width: 860px) {
  .service-row { grid-template-columns: auto auto 1fr; gap: 16px; padding: 26px 8px; }
  .service-row .sr-tile { width: 58px; height: 58px; border-radius: 14px; }
  .service-row .sr-go { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .service-row { grid-template-columns: auto 1fr; }
  .service-row .sr-tile { display: none; }
}
.rail-cta {
  margin-top: 46px;
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; flex-wrap: wrap;
}
.rail-cta p { color: var(--text-3); font-size: 17px; font-weight: 300; }

/* ============================================================
   Feature / why cards
   ============================================================ */
.feature-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; margin-top: 64px; }
@media (max-width: 900px) { .feature-grid { grid-template-columns: 1fr; } }
.feature-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 34px 32px 38px;
  transition: all .5s var(--ease-leo);
}
.feature-card:hover { transform: translateY(-6px); border-color: rgba(243,112,33,0.3); }
.feature-card h3 { font-family: var(--font-display); font-size: 21px; font-weight: 500; margin: 22px 0 12px; color: var(--text-1); }
.feature-card p { color: var(--text-3); font-size: 15.5px; line-height: 1.75; }
.icon-wrap {
  width: 50px; height: 50px;
  border-radius: 14px;
  background: linear-gradient(135deg, var(--orange-bright), var(--orange));
  display: flex; align-items: center; justify-content: center;
  color: #fff;
}
.icon-wrap svg { width: 23px; height: 23px; }

.pillar-tile {
  width: 62px; height: 62px;
  border-radius: 16px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--card-2);
}
.pillar-tile img { width: 100%; height: 100%; object-fit: cover; transition: transform .6s var(--ease-leo); }
.feature-card:hover .pillar-tile img { transform: scale(1.08); }

/* ============================================================
   Media band - full-bleed film with content
   ============================================================ */
.media-band-wrap { padding: 0; }
/* The band runs the full width of the page. Inside a rounded 1320px card the
   film was cropped twice over - once by the card, once by the -6% overscan -
   and it read as a still photograph someone had trimmed. Full-bleed at the
   film's own 16:9 means the frame plays whole on a desktop screen, and the
   only crop left is the one the aspect ratio forces on a narrow phone. */
.media-band {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  min-height: 620px;
  max-height: 88vh;
  display: flex;
  align-items: center;
  overflow: hidden;
  border-radius: 0;
}
.band-media { position: absolute; inset: 0; z-index: 0; }
.band-media video, .band-media img {
  width: 100%; height: 100%; object-fit: cover;
  filter: brightness(0.55) saturate(0.8) contrast(1.1);
  /* the film dissolves into the page instead of ending on a cut edge */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 13%, #000 84%, transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0%, #000 13%, #000 84%, transparent 100%);
}
.media-band::after {
  content: "";
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(to right, rgba(0,0,0,0.84) 0%, rgba(0,0,0,0.48) 46%, transparent 82%),
    linear-gradient(to bottom, rgba(0,0,0,0.5) 0%, transparent 22%, transparent 74%, rgba(0,0,0,0.72) 100%);
  pointer-events: none;
}
[dir="rtl"] .media-band::after {
  background:
    linear-gradient(to left, rgba(0,0,0,0.84) 0%, rgba(0,0,0,0.48) 46%, transparent 82%),
    linear-gradient(to bottom, rgba(0,0,0,0.5) 0%, transparent 22%, transparent 74%, rgba(0,0,0,0.72) 100%);
}
/* the copy keeps the page's own column so it lines up with every other
   section, even though the film behind it no longer does */
.media-band-content {
  position: relative; z-index: 2;
  width: min(1320px, 92%);
  margin-inline: auto;
  padding: 0;
  display: flex; flex-direction: column; gap: 20px;
  align-items: flex-start;
}
.media-band-content > * { max-width: 640px; }
.media-band-content h2 {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(32px, 4vw, 58px);
  line-height: 1.1;
  color: #fff;
}
.media-band-content p { color: var(--text-2); font-weight: 300; line-height: 1.75; font-size: 16.5px; }
@media (max-width: 768px) {
  .media-band { min-height: 560px; max-height: none; }
  .media-band-content { padding: 0; }
}

/* the maker's mark under the headline: white on a dark band, small
   enough to be an attribution rather than a partnership badge */
.band-mark { height: 17px; width: auto; opacity: .5; margin-top: 16px; display: block; }
@media (max-width: 560px) { .band-mark { height: 15px; margin-top: 13px; } }

/* ============================================================
   Partner wall - gradient frames
   ============================================================ */
.partners-logo-grid {
  --logo-cols: 4;
  display: grid;
  grid-template-columns: repeat(var(--logo-cols), 1fr);
  gap: 18px;
  margin-top: 56px;
}
@media (max-width: 1180px) { .partners-logo-grid { --logo-cols: 3; } }
@media (max-width: 760px)  {
  .partners-logo-grid { --logo-cols: 2; }
  /* At two columns the cell is 135px of usable width, and a 8.6:1
     wordmark can only ever be 16px tall inside it. Nothing gives a wide
     mark more area there, so the square ones come down to meet it -
     otherwise Cisco covers half its cell and Fortinet a seventh. */
  .partners-logo-grid { --lh-scale: 0.62; }
}

.partner-logo-cell {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--card);
  display: flex; align-items: center; justify-content: center;
  /* the cell halves in width on a phone; a fixed 26px inset left the
     mark almost no room inside it */
  padding: clamp(13px, 8%, 26px);
  overflow: hidden;
  transition: all .5s var(--ease-leo);
}

.partner-logo-cell:hover { transform: translateY(-5px); border-color: rgba(255,255,255,0.2); background: var(--card-2); }
/* --lh is written per logo by build/blocks.js from the mark's own
   proportions, so every mark covers the same optical area whatever its
   shape. min(...,100%) keeps a tall mark inside the cell once the grid
   drops to two columns and the cell is wider than it is high. */
.partner-logo-cell img {
  max-height: min(calc(var(--lh, 46px) * var(--lh-scale, 1)), 100%);
  max-width: 100%;
  width: auto;
  object-fit: contain;
}

/* ============================================================
   Vendor rows (service detail pages)
   ============================================================ */
.vendor-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-top: 56px; }
@media (max-width: 900px) { .vendor-grid { grid-template-columns: 1fr; } }
.vendor-card {
  display: grid;
  grid-template-columns: 128px 1fr;
  align-items: center;
  gap: 26px;
  padding: 26px 30px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--card);
  transition: all .5s var(--ease-leo);
}
.vendor-card:hover { transform: translateY(-5px); border-color: rgba(243,112,33,0.32); background: var(--card-2); }
.vendor-card .v-logo {
  height: 48px;
  display: flex; align-items: center; justify-content: center;
}
/* the same derived cap as the wall, scaled to this smaller band */
.vendor-card .v-logo img {
  max-height: min(calc(var(--lh, 46px) * 0.62), 100%);
  max-width: 150px;
  width: auto;
  object-fit: contain;
}
.vendor-card p { color: var(--text-3); font-size: 14.8px; line-height: 1.7; }
@media (max-width: 560px) {
  .vendor-card { grid-template-columns: 1fr; gap: 16px; }
  .vendor-card .v-logo { justify-content: flex-start; }
}

/* ============================================================
   Split feature (why-us quad)
   ============================================================ */
.split-grid { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: 64px; align-items: center; }
@media (max-width: 900px) { .split-grid { grid-template-columns: 1fr; gap: 48px; } }
.quad { display: grid; grid-template-columns: 1fr 1fr; gap: 30px 26px; }
@media (max-width: 520px) { .quad { grid-template-columns: 1fr; } }
.quad h3, .quad h4 { font-family: var(--font-display); font-size: 19px; font-weight: 500; margin: 18px 0 8px; color: var(--text-1); }
.quad p { color: var(--muted); font-size: 14.5px; line-height: 1.65; }

/* ============================================================
   FAQ
   ============================================================ */
.faq-grid { display: grid; grid-template-columns: .8fr 1.2fr; gap: 60px; align-items: start; }
@media (max-width: 900px) { .faq-grid { grid-template-columns: 1fr; gap: 40px; } }
.faq-list { display: grid; gap: 0; border-top: 1px solid var(--line); }
.faq-item {
  border-bottom: 1px solid var(--line);
  padding: 24px 18px;
  transition: background .4s var(--ease-leo);
}
.faq-item:hover { background: linear-gradient(to right, rgba(243,112,33,0.06), transparent 60%); }
[dir="rtl"] .faq-item:hover { background: linear-gradient(to left, rgba(243,112,33,0.06), transparent 60%); }
.faq-item summary {
  font-family: var(--font-display);
  font-size: 17.5px;
  font-weight: 400;
  color: var(--text-1);
  cursor: pointer;
  list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: "+";
  font-weight: 300;
  font-size: 24px;
  color: var(--orange-bright);
  transition: transform .4s var(--ease-leo);
  line-height: 1;
}
.faq-item[open] summary::after { transform: rotate(45deg); }
.faq-item .answer { color: var(--text-3); font-size: 15.5px; line-height: 1.75; margin-top: 14px; max-width: 70ch; }

.faq-cats { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 44px; }
.filter-btn {
  padding: 10px 20px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: 14.5px;
  font-weight: 500;
  transition: all .35s var(--ease-leo);
}
.filter-btn:hover { color: #fff; border-color: rgba(255,255,255,0.35); }
/* .active is what the scripts toggle; .is-on and aria-pressed are the
   state the catalogue's markup carries before any script has run */
.filter-btn.active,
.filter-btn.is-on,
.filter-btn[aria-pressed="true"] { background: linear-gradient(135deg, var(--orange), var(--orange-bright)); color: #fff; border-color: transparent; }

/* ============================================================
   News cards
   ============================================================ */
/* Three fixed columns held while there were exactly three updates. A
   fourth left one card alone on a second row, so the track count follows
   the item count instead: auto-fit collapses the tracks it does not
   need, which keeps three across at three items and puts four across at
   four, both filling the row. */
.blog-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(268px, 1fr)); gap: 28px; margin-top: 60px; }
@media (max-width: 900px) { .blog-grid { grid-template-columns: 1fr; } }
.blog-card {
  display: flex; flex-direction: column;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  transition: all .5s var(--ease-leo);
}
.blog-card:hover { transform: translateY(-6px); border-color: rgba(243,112,33,0.3); }
.blog-card .thumb {
  aspect-ratio: 16/9;
  overflow: hidden;
  background: radial-gradient(120% 100% at 50% 0%, rgba(243,112,33,0.14), transparent 62%), var(--card-2);
  display: flex; align-items: center; justify-content: center;
  padding: 34px;
}
.blog-card .thumb img { max-height: 54px; max-width: 62%; width: auto; object-fit: contain; }
.blog-card:hover .thumb img { transform: scale(1.06); }
.blog-card .body { padding: 26px 28px 30px; display: flex; flex-direction: column; gap: 12px; flex: 1; }
.blog-card .meta { display: flex; gap: 8px; font-size: 13.5px; color: var(--text-3); }
.blog-card h3 { font-family: var(--font-display); font-size: 19px; font-weight: 500; line-height: 1.4; color: var(--text-1); }
.blog-card p { color: var(--text-3); font-size: 14.5px; line-height: 1.65; flex: 1; }
.read-more { display: inline-flex; align-items: center; gap: 8px; color: var(--orange-bright); font-family: var(--font-display); font-weight: 500; font-size: 15px; }
.read-more svg { width: 15px; height: 15px; }
[dir="rtl"] .read-more svg { transform: scaleX(-1); }

/* ============================================================
   CTA banner
   ============================================================ */
.cta-banner {
  display: grid;
  grid-template-columns: 1.1fr .9fr;
  gap: 56px;
  align-items: center;
  background:
    radial-gradient(90% 130% at 0% 0%, rgba(243,112,33,0.18) 0%, transparent 58%),
    var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  padding: 64px 60px;
}
@media (max-width: 900px) { .cta-banner { grid-template-columns: 1fr; padding: 44px 30px; gap: 36px; } }
.cta-banner h2 { color: #fff; }
.cta-banner p { color: var(--text-2); margin: 20px 0 28px; max-width: 48ch; font-weight: 300; }

/* Visually hidden, still announced. Not display:none and not
   visibility:hidden - both of those take the element out of the
   accessibility tree, which is the opposite of what a hidden label is
   for. Absolute, so it takes no cell in the form's grid. */
.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.cta-form { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.cta-form .full { grid-column: 1 / -1; }
.cta-form input, .cta-form textarea, .cta-form select {
  width: 100%;
  padding: 14px 18px;
  border-radius: 14px;
  /* 0.14 composited to rgb(36,36,36) on the black page - 1.35:1, a box
     you cannot see. 0.36 is rgb(92,92,92), which clears 3:1 for a
     non-text control, and the fill at 0.10 gives the field a shape. */
  border: 1px solid rgba(255,255,255,0.36);
  background: rgba(255,255,255,0.10);
  color: #fff;
  font-family: inherit;
  font-size: 15px;
  transition: all .35s var(--ease-leo);
}
.cta-form textarea { min-height: 110px; resize: vertical; }
/* the placeholder is the only name of the field a sighted reader sees,
   so it is held above 4.5:1 rather than at the 4.08:1 that 0.42 gave */
.cta-form input::placeholder, .cta-form textarea::placeholder { color: rgba(255,255,255,0.50); }
.cta-form input:focus, .cta-form textarea:focus, .cta-form select:focus {
  outline: none;
  border-color: rgba(243,112,33,0.6);
  background: rgba(243,112,33,0.07);
}
.cta-form button { grid-column: 1 / -1; justify-content: center; }

/* ------------------------------------------------------------------
   Autofilled fields.

   Chromium - and Edge, which is Chromium - paints a field it has filled
   with its own opaque light blue and dark text. On a white form that
   reads as a helpful highlight. On these forms, which are near-black
   with white type, it is a bright block, and it appears before the
   visitor has touched anything, because the fill happens on load. It was
   reported from Edge on a phone, across several pages: name, email and
   phone are exactly the fields a browser has saved.

   The colour cannot be replaced with background-color - the UA paints it
   below that. A large inset shadow is what actually covers it, and
   -webkit-text-fill-color is what keeps the text white on top. The
   absurd transition delay is the other half of the trick: the UA
   re-applies its own colour through an internal transition, and
   outrunning it is what stops the field flashing blue a moment after
   load.

   The two colours are the field's own translucent backgrounds resolved
   against the page: rgba(255,255,255,0.05) over #000 at rest, and rgba(243,112,33,0.07) on focus.
   ------------------------------------------------------------------ */
.cta-form :where(input, textarea, select):-webkit-autofill,
.cta-form :where(input, textarea, select):-webkit-autofill:hover {
  -webkit-text-fill-color: #fff;
  caret-color: #fff;
  -webkit-box-shadow: inset 0 0 0 1000px #0D0D0D;
  box-shadow: inset 0 0 0 1000px #0D0D0D;
  transition: background-color 100000s ease-in-out 0s;
}
/* the unprefixed selector in a rule of its own: an engine that does not
   know it would otherwise drop the prefixed one with it. */
.cta-form :where(input:autofill,
textarea:autofill,
select):autofill {
  -webkit-text-fill-color: #fff;
  caret-color: #fff;
  -webkit-box-shadow: inset 0 0 0 1000px #0D0D0D;
  box-shadow: inset 0 0 0 1000px #0D0D0D;
  transition: background-color 100000s ease-in-out 0s;
}

.cta-form :where(input, textarea, select):-webkit-autofill:focus {
  -webkit-box-shadow: inset 0 0 0 1000px #110802;
  box-shadow: inset 0 0 0 1000px #110802;
}

@media (max-width: 560px) { .cta-form { grid-template-columns: 1fr; } }

/* ============================================================
   Contact
   ============================================================ */
.contact-grid { display: grid; grid-template-columns: .9fr 1.1fr; gap: 56px; align-items: start; }
@media (max-width: 900px) { .contact-grid { grid-template-columns: 1fr; } }
.contact-pill {
  display: flex; align-items: center; gap: 16px;
  padding: 18px 22px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--card);
  transition: all .4s var(--ease-leo);
}
.contact-pill:hover { border-color: rgba(243,112,33,0.35); transform: translateY(-3px); }
.contact-pill .icon {
  width: 44px; height: 44px; flex-shrink: 0;
  border-radius: 13px;
  background: linear-gradient(135deg, var(--orange-bright), var(--orange));
  display: flex; align-items: center; justify-content: center;
  color: #fff;
}
.contact-pill .icon svg { width: 20px; height: 20px; }
.contact-pill .ct-label { display: block; font-size: 13.5px; color: var(--text-3); }
.contact-pill .ct-val { display: block; color: var(--text-1); font-family: var(--font-display); font-size: 17px; font-weight: 400; margin-top: 3px; }
.map-card { border-radius: var(--r-lg); overflow: hidden; border: 1px solid var(--line); margin-top: 24px; }
.map-card iframe { width: 100%; height: 300px; border: 0; display: block; filter: grayscale(1) invert(0.92) contrast(0.85); }

/* The embed answers where; this answers how to get there. It sits on the
   map's own bottom edge rather than beside it, so the pair reads as one
   object, and it is a 44px row on a phone because that is where it will
   actually be tapped. */
.map-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 46px;
  padding: 0 18px;
  border-top: 1px solid var(--line);
  background: var(--card);
  color: var(--text-2);
  font-size: 14.5px;
  text-decoration: none;
  transition: background .4s var(--ease-leo), color .4s var(--ease-leo);
}
.map-nav svg { width: 17px; height: 17px; color: var(--orange); flex: 0 0 auto; }
.map-nav:hover { background: var(--card-2); color: var(--text-1); }

/* ============================================================
   Footer
   ============================================================ */
.site-footer { background: #050403; border-top: 1px solid var(--line); padding: 84px 0 34px; }
.footer-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: 44px; }
@media (max-width: 900px) { .footer-grid { grid-template-columns: 1fr 1fr; gap: 40px 24px; } }
@media (max-width: 560px) { .footer-grid { grid-template-columns: 1fr; } }
.footer-brand img { height: 30px; width: auto; }
.footer-brand p { margin-top: 18px; color: #767683; font-size: 15px; max-width: 36ch; line-height: 1.7; }
.site-footer h3, .site-footer h4 { font-family: var(--font-display); font-size: 17px; font-weight: 500; color: var(--text-1); letter-spacing: -0.005em; margin-bottom: 20px; }
.site-footer ul { list-style: none; display: flex; flex-direction: column; gap: 11px; }
.site-footer ul a, .site-footer ul li { color: #767683; font-size: 15px; }
.site-footer ul a:hover { color: var(--orange-bright); }
.socials { display: flex; gap: 10px; margin-top: 24px; }
.socials a {
  width: 38px; height: 38px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.12);
  display: flex; align-items: center; justify-content: center;
  color: #767683;
  transition: all .4s var(--ease-leo);
}
.socials a:hover { background: var(--orange); color: #fff; border-color: transparent; }

/* the group ribbon in the footer */
.footer-group {
  margin-top: 56px;
  padding: 26px 30px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: radial-gradient(90% 140% at 0% 0%, rgba(243,112,33,0.10) 0%, transparent 60%), var(--card);
  display: flex; align-items: center; justify-content: space-between;
  gap: 22px; flex-wrap: wrap;
}
.footer-group .fg-text { color: var(--text-3); font-size: 15px; }
.footer-group .fg-brands { display: flex; align-items: center; gap: 26px; flex-wrap: wrap; }
.footer-group .fg-brands img { height: 19px; width: auto; }

.footer-bottom {
  margin-top: 44px;
  padding-top: 26px;
  border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  color: #767683; font-size: 14px;
}
.footer-bottom a:hover { color: var(--orange-bright); }

/* The legal row on a phone.

   It was a space-between pair that wrapped once it ran out of width, so
   whether the links landed under the copyright or out at the opposite
   edge depended on how wide the copyright string happened to render -
   and Hebrew and English disagree about that, as do two phones with
   different font fallbacks. With three links here rather than two it
   runs out sooner.

   Below the width where the footer's columns stack, this stacks too:
   one column, both lines starting at the same reading edge the rest of
   the footer already uses, and spacing set once instead of being
   whatever the tap padding adds to the gap. */
/* The legal links row.

   This used to carry style="display:flex; gap:24px" inline on every page.
   An inline declaration outranks any selector, so the stylesheet's attempt
   to tighten the gap on a phone was inert - the rule looked live, and half
   of it (flex-wrap) took effect while the other half silently did not.
   The row is a class now, and the base has to sit ABOVE the media query
   that narrows it: same specificity means source order decides. */
.footer-legal { display: flex; gap: 24px; }

@media (max-width: 560px) {
  .footer-bottom {
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    row-gap: 0;
  }
  .footer-bottom > :first-child { margin-bottom: 3px; }
  .footer-legal { gap: 20px; flex-wrap: wrap; }
}

/* ============================================================
   Misc
   ============================================================ */
.dark-section { background: var(--bg); }
.card-section { background: var(--card); }

/* skip link */
.skip-link {
  position: absolute;
  inset-inline-start: -9999px;
  top: 0;
  z-index: 1000;
  background: #fff; color: #000;
  padding: 12px 20px; border-radius: 0 0 12px 0;
}
.skip-link:focus { inset-inline-start: 0; }

:focus-visible { outline: 2px solid var(--orange-bright); outline-offset: 3px; border-radius: 4px; }
/* the bright orange is drawn for the black page; on the two white
   panels - the drawer and the header's course menu - it measures
   2.35:1 against the ground, so those get the darker orange at 4.5:1 */
.mobile-drawer :focus-visible, .subnav :focus-visible, .subnav-courses :focus-visible { outline-color: #C2570E; }

/* ============================================================
   INSTRUMENTATION LAYER
   The parts that make the site read as an engineering company:
   a live network canvas, pointer-lit surfaces, fiber hairlines,
   scroll-drawn routes and monospace readouts.
   ============================================================ */

/* ---- film grain -------------------------------------------
   A single fixed layer at very low opacity. Kills the flatness
   of large black areas and stops gradients from banding.       */
.grain {
  position: fixed;
  inset: -50%;
  z-index: 1;
  pointer-events: none;
  opacity: 0.035;
  background-image: var(--grain-src);
  background-size: 180px 180px;
  will-change: transform;
  animation: grainShift 6s steps(6) infinite;
}
@keyframes grainShift {
  0%   { transform: translate(0, 0); }
  16%  { transform: translate(-2%, -3%); }
  33%  { transform: translate(3%, 1%); }
  50%  { transform: translate(-1%, 2%); }
  66%  { transform: translate(2%, -2%); }
  83%  { transform: translate(-3%, 1%); }
  100% { transform: translate(0, 0); }
}

/* ---- hero network canvas ----------------------------------
   Nodes and links drawn over the film, with packets running the
   edges. Sits under the copy, above the video.                 */
.scene-canvas {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  transition: opacity 2.2s var(--ease-leo) .25s;
}
.scene-canvas.lit { opacity: 1; }
.subpage-hero .scene-canvas { opacity: 0; }
.subpage-hero .scene-canvas.lit { opacity: .85; }
.hero .hero-content { z-index: 3; }
.hero::after { z-index: 2; }

/* ---- pointer-lit surfaces ---------------------------------
   Each card writes its own --mx/--my, so the highlight tracks
   the cursor across the surface rather than the whole page.    */
.lit-surface { position: relative; isolation: isolate; }
.lit-surface::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(340px circle at var(--mx) var(--my), rgba(243,112,33,0.13), transparent 62%);
  opacity: 0;
  transition: opacity .55s var(--ease-leo);
  pointer-events: none;
  z-index: 0;
}
.lit-surface:hover::before { opacity: 1; }
.lit-surface > * { position: relative; z-index: 1; }

/* the border catches the light too - a hairline that brightens
   only where the cursor is */
.lit-edge::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: radial-gradient(260px circle at var(--mx) var(--my), rgba(255,178,107,0.65), transparent 60%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0;
  transition: opacity .55s var(--ease-leo);
  pointer-events: none;
  z-index: 2;
}
.lit-edge:hover::after { opacity: 1; }

/* ---- fiber hairline ---------------------------------------
   A section divider with a light packet running down it.       */
.fiber-rule {
  position: relative;
  height: 1px;
  background: var(--line-soft);
  overflow: hidden;
}
.fiber-rule::after {
  content: "";
  position: absolute;
  top: 0;
  inset-inline-start: -22%;
  width: 22%;
  height: 100%;
  background: linear-gradient(to right, transparent, var(--orange-bright), transparent);
  animation: fiberRun 5.5s linear infinite;
}
[dir="rtl"] .fiber-rule::after { animation-name: fiberRunRtl; }
@keyframes fiberRun { to { transform: translateX(555%); } }
@keyframes fiberRunRtl { to { transform: translateX(-555%); } }

/* ---- scroll-drawn route -----------------------------------
   An SVG spine down a section that draws itself as you pass.   */
.route {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 50%;
  width: 2px;
  transform: translateX(-50%);
  pointer-events: none;
  z-index: 0;
}
.route svg { width: 100%; height: 100%; overflow: visible; }
/* the stroke is a per-instance gradient set on the element itself */
.route path {
  fill: none;
  stroke-width: 1;
  stroke-dasharray: var(--len);
  stroke-dashoffset: var(--len);
  vector-effect: non-scaling-stroke;
}
@media (max-width: 1180px) { .route { display: none; } }

/* ---- monospace readout ------------------------------------ */
.readout {
  font-family: var(--font-display);
  font-size: 13.5px;
  color: var(--text-3);
}
.readout .val { color: var(--orange-bright); }

/* ---- service row technical tag ----------------------------- */
.service-row .sr-spec { display: none; }

/* ---- magnetic buttons -------------------------------------- */
.btn.mag { will-change: transform; }

/* ---- decode-on-reveal for mono labels ---------------------- */
.decode { white-space: pre-wrap; }

/* ---- hairline grid backdrop -------------------------------- */
.grid-bg::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(255,255,255,0.02) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255,255,255,0.02) 1px, transparent 1px);
  background-size: 148px 148px;
  -webkit-mask-image: radial-gradient(ellipse 62% 48% at 50% 40%, #000 0%, transparent 72%);
  mask-image: radial-gradient(ellipse 62% 48% at 50% 40%, #000 0%, transparent 72%);
  /* sits with the network canvas: over the film, under the scrim */
  z-index: 1;
}

/* ---- reduced motion ---------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .grain, .eyebrow::before, .fiber-rule::after, .tag .live { animation: none; }
  .net-canvas { opacity: .5; transition: none; }
  .route path { stroke-dashoffset: 0 !important; }
}

/* ---- staggered reveals ------------------------------------
   Grids come in cell by cell rather than as one block, so the
   eye tracks across the wall instead of being handed all of it. */
.partners-logo-grid .reveal:nth-child(1)  { transition-delay: .00s; }
.partners-logo-grid .reveal:nth-child(2)  { transition-delay: .05s; }
.partners-logo-grid .reveal:nth-child(3)  { transition-delay: .10s; }
.partners-logo-grid .reveal:nth-child(4)  { transition-delay: .15s; }
.partners-logo-grid .reveal:nth-child(5)  { transition-delay: .08s; }
.partners-logo-grid .reveal:nth-child(6)  { transition-delay: .13s; }
.partners-logo-grid .reveal:nth-child(7)  { transition-delay: .18s; }
.partners-logo-grid .reveal:nth-child(8)  { transition-delay: .23s; }
.partners-logo-grid .reveal:nth-child(9)  { transition-delay: .16s; }
.partners-logo-grid .reveal:nth-child(10) { transition-delay: .21s; }
.partners-logo-grid .reveal:nth-child(11) { transition-delay: .26s; }
.partners-logo-grid .reveal:nth-child(12) { transition-delay: .31s; }
.partners-logo-grid .reveal:nth-child(n+13) { transition-delay: .3s; }

.service-rail .service-row:nth-child(1) { transition-delay: .00s; }
.service-rail .service-row:nth-child(2) { transition-delay: .06s; }
.service-rail .service-row:nth-child(3) { transition-delay: .12s; }
.service-rail .service-row:nth-child(4) { transition-delay: .18s; }
.service-rail .service-row:nth-child(n+5) { transition-delay: .24s; }

/* ---- section seams ----------------------------------------
   Instead of a hard colour change between sections, a lit
   hairline the packets run along.                             */
.seam {
  position: relative;
  height: 1px;
  margin: 0;
  background: linear-gradient(to right, transparent, var(--line), transparent);
  overflow: hidden;
}
.seam::after {
  content: "";
  position: absolute;
  top: 0;
  inset-inline-start: 0;
  width: 18%;
  height: 100%;
  background: linear-gradient(to right, transparent, var(--orange-bright), transparent);
  opacity: .8;
  animation: seamRun 9s linear infinite;
}
@keyframes seamRun {
  0%   { transform: translateX(-120%); }
  100% { transform: translateX(680%); }
}
[dir="rtl"] .seam::after { animation-name: seamRunRtl; }
@keyframes seamRunRtl {
  0%   { transform: translateX(120%); }
  100% { transform: translateX(-680%); }
}
@media (prefers-reduced-motion: reduce) { .seam::after { animation: none; opacity: 0; } }

/* ---- cursor ------------------------------------------------
   Two parts moving at different rates: a dot that keeps up with
   the pointer, and a frame that lags behind it. Over anything
   interactive the frame stops following the pointer and takes the
   shape of the element instead - so the page appears to
   acknowledge what you are about to click.
   ------------------------------------------------------------ */
.cur-dot, .cur-frame {
  position: fixed;
  top: 0; left: 0;
  pointer-events: none;
  z-index: 9999;
  opacity: 0;
  transition: opacity .35s var(--ease-leo);
  will-change: transform;
}
.cur-dot {
  width: 5px; height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: 50%;
  background: rgba(255,255,255,0.85);
}
.cur-frame {
  width: 34px; height: 34px;
  margin: -17px 0 0 -17px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.28);
  transition: opacity .35s var(--ease-leo),
              width .5s var(--ease-leo), height .5s var(--ease-leo),
              margin .5s var(--ease-leo), border-radius .5s var(--ease-leo),
              border-color .5s var(--ease-leo), background-color .5s var(--ease-leo);
}
.cur-on .cur-dot, .cur-on .cur-frame { opacity: 1; }

/* locked on to a target: the frame becomes the target's outline */
.cur-frame.locked {
  border-color: rgba(255,178,107,0.55);
  background: rgba(243,112,33,0.05);
}
.cur-lock-dot .cur-dot { opacity: 0; }
.cur-press .cur-frame { border-color: rgba(255,178,107,0.9); }

@media (hover: none), (prefers-reduced-motion: reduce) {
  .cur-dot, .cur-frame { display: none; }
}

/* ---- page transition ---------------------------------------
   A short black wipe between pages, so a static multi-page site
   moves like one application.                                  */
.page-veil {
  position: fixed;
  inset: 0;
  z-index: 9998;
  background: #000;
  pointer-events: none;
  opacity: 1;
  transition: opacity .5s var(--ease-leo);
}
.page-veil.clear { opacity: 0; }
.page-veil.leaving { opacity: 1; transition-duration: .26s; }
@media (prefers-reduced-motion: reduce) { .page-veil { display: none; } }


/* ============================================================
   Icon marks
   One drawn set, framed the same way everywhere. Restrained by
   default; the accent element lights when the card is engaged.
   ============================================================ */
.ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 62px; height: 62px;
  flex-shrink: 0;
  border-radius: 17px;
  border: 1px solid rgba(255,255,255,0.10);
  background: linear-gradient(160deg, rgba(255,255,255,0.055), rgba(255,255,255,0.012));
  color: rgba(255,255,255,0.82);
  transition: border-color .5s var(--ease-leo), background .5s var(--ease-leo), color .5s var(--ease-leo);
}
.ico svg { width: 30px; height: 30px; display: block; }
.ico .ic-hot { color: var(--orange-bright); stroke: var(--orange-bright); transition: opacity .5s var(--ease-leo); }

:is(.feature-card, .service-row, .quad-item, .aud-card, .course-card, .delivery-card, .step):hover .ico {
  border-color: rgba(255,255,255,0.2);
  background: linear-gradient(160deg, rgba(255,255,255,0.09), rgba(255,255,255,0.02));
  color: #fff;
}

/* larger mark for the service rail */
.service-row .ico { width: 68px; height: 68px; border-radius: 19px; }
.service-row .ico svg { width: 33px; height: 33px; }
@media (max-width: 860px) {
  .service-row .ico { width: 54px; height: 54px; border-radius: 15px; }
  .service-row .ico svg { width: 27px; height: 27px; }
}

/* small mark, used inside prose columns */
.ico.sm { width: 50px; height: 50px; border-radius: 14px; }
.ico.sm svg { width: 25px; height: 25px; }

/* the old orange square and photo tile are retired */
.icon-wrap, .pillar-tile, .sr-tile { display: none !important; }

/* ============================================================
   Phone numbers keep Latin order inside Hebrew text
   ============================================================ */
.ltr-num { direction: ltr; unicode-bidi: embed; display: inline-block; }


/* ============================================================
   Hero as a reel
   Films that dissolve into one another - the classroom, the rack,
   the NOC, fibre into a transceiver. The drawn network still runs
   over them, at half strength, so the third element is drawn rather
   than filmed and stays quiet. js/academy.js drives the
   cross-dissolve.
   ============================================================ */
.hero.hero-reel { background: var(--bg); }
.hero.hero-reel .hero-film { position: absolute; inset: 0; z-index: 0; opacity: .94; }
/* Which clip is showing is decided at runtime, as an inline opacity set
   by setupReel(). Until that happens nothing decided it at all: eight
   clips painted at full opacity, stacked, and the last one in the markup
   won - so the page opened on the reel's CLOSING shot. It was invisible
   while the clips had no poster, because eight blank rectangles stack to
   the same black; giving them stills is what made it show.

   Two visitors never get that inline value: one whose script has not run
   yet, and one who has asked for reduced motion, for whom the reel never
   starts at all. Both should see the opening shot, so the opening shot is
   the resting state. The inline value still wins once it lands, which is
   what lets the reel play. */
.hero.hero-reel .hero-film video { opacity: 0; }
.hero.hero-reel .hero-film video:first-of-type { opacity: 1; }

.hero.hero-reel .hero-film video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  /* The one grade every clip shares - this is what makes six separately
     generated shots read as one film.

     No contrast term here, deliberately. A contrast() above 1 pivots
     around mid-grey, so on footage this dark it drags the shadows below
     zero and clips them: measured on the page, brightness(.68) with
     contrast(1.14) rendered the aisle shot at a mean luminance of 4.8
     out of 255 and the NOC shot at 6.6 - it was both crushing the reel
     and pulling the clips apart again after they had been matched frame
     by frame at encode time. Brightness and saturation only; each clip
     was already balanced to the same luminance in ffmpeg. */
  /* A little under the group's grade, because this reel opens on a lit
     hexagon wall and the headline sits over it. Measured on the opening
     frame, in the box the headline occupies: at 0.72 with a clear
     centre the brightest of the wall came back at 0.196 relative
     luminance, so white type held 4.3:1 - passing, and visibly sitting
     on the brightest part of the picture. The film only comes down to
     0.62 here; the veil below does the rest, and only where the copy
     is, so the room is still a room. */
  filter: brightness(0.62) saturate(0.82);
}

/* the warm horizon stays, softened: the film carries the light now */
.hero.hero-reel .hero-glow {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    radial-gradient(58% 24% at 50% 100%, rgba(255,214,166,0.11) 0%, transparent 70%),
    radial-gradient(130% 56% at 50% 104%, rgba(243,112,33,0.20) 0%, rgba(243,112,33,0.05) 42%, transparent 72%);
}
.hero.hero-reel .scene-canvas.lit { opacity: .5; }
/* The stock hero scrim ramps to solid #000 across the bottom 45% of the
   frame, which is fine over a drawn gradient but throws away real footage:
   the operator and his screens sit low in the NOC shot and were being
   crushed to nothing. The page underneath is already black, so the scrim
   only has to reach near-black to blend - it does not have to reach it
   early, and it does not have to get all the way there. */
.hero.hero-reel::after {
  background:
    /* the reading band. The old scrim was clear through the middle 26%,
       which is exactly where the copy is - it darkened the corners and
       left the headline sitting on the brightest part of the frame. */
    radial-gradient(ellipse 82% 54% at 50% 46%, rgba(0,0,0,0.40) 0%, rgba(0,0,0,0.18) 58%, transparent 84%),
    linear-gradient(to bottom, rgba(0,0,0,0.55) 0%, transparent 30%, transparent 66%, rgba(0,0,0,0.9) 100%);
}

/* ============================================================
   Hero, without borrowed footage
   A drawn horizon instead of a film: black, one warm band low in
   the frame, and the network laid over it. Nothing to license,
   nothing to download, and it never competes with the headline.
   ============================================================ */
.hero.hero-drawn { background: var(--bg); }
.hero.hero-drawn .hero-glow {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(58% 26% at 50% 100%, rgba(255,214,166,0.22) 0%, transparent 70%),
    radial-gradient(130% 58% at 50% 104%, rgba(243,112,33,0.42) 0%, rgba(243,112,33,0.10) 42%, transparent 72%),
    radial-gradient(90% 46% at 50% -6%, rgba(255,255,255,0.05) 0%, transparent 64%);
}
/* a single hairline horizon, the only hard edge in the composition */
.hero.hero-drawn .hero-glow::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 21%;
  height: 1px;
  background: linear-gradient(to right, transparent, rgba(255,178,107,0.4) 22%, rgba(255,214,166,0.6) 50%, rgba(255,178,107,0.4) 78%, transparent);
}
.hero.hero-drawn::after {
  /* leave the low band alone - that warm horizon is the composition */
  background: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%, transparent 24%, transparent 88%, rgba(0,0,0,0.55) 100%);
}

/* ============================================================
   Credential badge - replaces the small caption above headings
   ============================================================ */
.cred-badge {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 9px 18px;
  margin-bottom: 26px;
  border-radius: var(--r-pill);
  border: 1px solid rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.04);
  backdrop-filter: blur(10px);
  color: var(--text-2);
  font-size: 14.5px;
}
.cred-badge img { height: 17px; width: auto; filter: brightness(0) invert(1); opacity: .92; }

/* ============================================================
   Quad - the four-up value grid, drawn marks and a hairline
   ============================================================ */
.quad-item { padding-top: 26px; border-top: 1px solid var(--line); }
.quad-item .ico { margin-bottom: 20px; }


/* ============================================================
   PANEL LAYOUT
   Sections all sit on the same black ground. What separates them
   is a bordered slab, the way a rack separates equipment - so the
   page reads as assembled hardware rather than striped bands.
   ============================================================ */
:root { --panel: #0A0908; --panel-2: #100E0C; }

.dark-section, .card-section, .stats-strip { background: var(--bg); border: 0; }
section { padding: 58px 0; }
@media (max-width: 768px) { section { padding: 34px 0; } }

.card-section > .container,
.card-section > .container-narrow,
.stats-strip > .container {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 30px;
  padding: 76px 60px;
  position: relative;
}
@media (max-width: 768px) {
  .card-section > .container,
  .card-section > .container-narrow,
  .stats-strip > .container { padding: 48px 26px; border-radius: 22px; }
}
/* cards inside a panel step up one tone, never down */
.card-section .feature-card,
.card-section .vendor-card,
.card-section .blog-card { background: var(--panel-2); }

/* the seam is redundant once every section has an edge */
.seam { display: none; }

/* The hero owns its own spacing; page headers must keep theirs, or the
   floating header pill lands on the H1. */
main > section.hero:first-child { padding-top: 0; }

/* That last line holds while the viewport is tall. The hero centres its
   content in 100svh, and with no top padding the centring has no floor -
   so as the viewport gets shorter the block rises until the group tag is
   behind the header pill. It is not a phone-only fault: the tag is under
   the pill at 1440x800 as surely as at 390x700, because a laptop with
   browser chrome has the same height a phone does. English reaches it
   first, its strings running to more lines than the Hebrew.

   Reserving the pill's room gives the centring the floor it was missing.
   The reserve only appears where the height is short enough to need it,
   so the tall-screen composition is untouched, and the seam is quiet:
   just above the query the natural gap is around 39px, just below it the
   reserved one is 42px.

   The scroll cue goes with it. Between pill and cue a 756px viewport has
   about 53px of slack for the whole hero, so room taken at the top comes
   out of the bottom - and the cue is the piece that can be spared when
   the screen is already too short to need telling there is more below. */
@media (max-height: 1000px) {
  /* The floor the centring was missing. It is the pill's own bottom edge
     - 22px down plus 72px tall - and then a gap, rather than a round
     number that happened to clear it: at 104px the reserve cleared the
     pill by 10px, which is not a gap, it is a near miss, and it read as
     the tag being stuck to the menu. 136px puts 42px of air under the
     pill, which is what the note under this rule always claimed it did.

     1000px rather than 820px, because 820 was measured against the
     Hebrew and English is the taller of the two - three lines to the
     Hebrew's two. Below 820 the reserve caught it; between 840 and 900 it
     did not apply at all, the centring had no floor again, and the tag
     sat 25px INSIDE the pill at 840x1440. English is clear on its own
     from about 950 up, so the reserve runs to 1000 and hands over with
     the gap still growing. */
  main > section.hero:first-child { padding-top: 136px; }
  /* auto margins centre while there is room and collapse to the padding
     edge when there is not, so an overflow spills down, never up. The
     floor therefore only bites where the hero is genuinely out of room -
     a tall window centres exactly as it did. */
  .hero > .hero-content { margin-block: auto; }
}

/* The cue is a separate question from the reserve, and a lower bar. Room
   taken at the top comes out of the bottom, so the cue goes when the
   screen is already too short to need telling there is more below - but
   a 900px laptop has the room, and dropping its cue to buy clearance it
   never needed would be paying twice. */
@media (max-height: 820px) {
  .hero > .scroll-cue { display: none; }
}
main > section:last-child { padding-bottom: 96px; }
.subpage-hero { padding: 200px 0 96px; }
.subpage-hero.has-media { padding: 230px 0 120px; }
@media (max-width: 768px) {
  .subpage-hero { padding: 150px 0 64px; }
  .subpage-hero.has-media { padding: 170px 0 80px; }
}

/* ============================================================
   LOGOS IN THEIR OWN COLOURS
   Muted at rest so the wall stays quiet, full brand colour on
   approach. Nothing is ever tinted orange - a vendor mark is not
   ours to repaint.
   ============================================================ */
.partner-logo-cell img,
.vendor-card .v-logo img,
.blog-card .thumb img,
.footer-group .fg-brands img {
  filter: grayscale(1) brightness(1.9) contrast(0.92);
  opacity: .48;
  transition: filter .55s var(--ease-leo), opacity .55s var(--ease-leo), transform .55s var(--ease-leo);
}
.partner-logo-cell:hover img,
.vendor-card:hover .v-logo img,
.blog-card:hover .thumb img,
.footer-group .fg-brands a:hover img {
  filter: none;
  opacity: 1;
}
.partner-logo-cell:hover img { transform: scale(1.05); }
/* ------------------------------------------------------------
   ...and on a touch screen, where there is no approach to detect.
   js/glow.js decides when a mark has been reached; everything below
   is what that means. A mark that has been reached stays lit - the
   wall a visitor has scrolled past is a wall they can read.
   ------------------------------------------------------------ */
@media (hover: none), (pointer: coarse) {
  .partner-logo-cell,
  .vendor-card { --lit: var(--near, 0); }
  /* a deliberate press still lights a card outright */
  .partner-logo-cell:active,
  .vendor-card:active { --lit: 1; }
  .partner-logo-cell img,
  .vendor-card .v-logo img {
    filter:
      grayscale(calc(1 - var(--lit)))
      brightness(calc(1 + 0.9 * (1 - var(--lit))))
      contrast(calc(1 - 0.08 * (1 - var(--lit))));
    opacity: calc(0.44 + 0.56 * var(--lit));
  }
  /* all of it is written per frame from where the light is */
  .partner-logo-cell img,
  .vendor-card .v-logo img { transition: none; }

  /* the card comes with it, so the light reads as landing on the card
     and not as the logo changing its mind. The lift stays off the cell
     itself: .reveal.in already owns its transform, and a second rule
     for the same property is a fight one of them has to lose. */
  .partner-logo-cell img {
    position: relative;
    z-index: 1;
    transform: scale(calc(1 + 0.045 * var(--lit)));
  }
  .partner-logo-cell {
    border-color: rgba(255, 255, 255, calc(0.10 + 0.16 * var(--lit)));
    transition: none;
  }
  /* the light itself. Taking the grey out of a mark is a change in the
     mark; a warm bloom landing on the card is light arriving on it, and
     that is the half the eye actually reads. */
  .partner-logo-cell::after {
    content: "";
    position: absolute;
    inset: -24%;
    z-index: 0;
    pointer-events: none;
    opacity: var(--lit);
    background: radial-gradient(
      50% 50% at 50% 50%,
      rgba(255, 178, 107, 0.17) 0%,
      rgba(243, 112, 33, 0.07) 46%,
      transparent 72%);
  }
  .vendor-card {
    border-color: rgba(243, 112, 33, calc(0.12 + 0.22 * var(--lit)));
    transition: none;
  }

  /* the group's own marks are not a hover state - they arrive, in
     order, and they stay */
  .footer-group .fg-brands a img { transition: filter .7s var(--ease-leo), opacity .7s var(--ease-leo); }
  .footer-group .fg-brands.lit a img { filter: none; opacity: 1; }
  .footer-group .fg-brands.lit a:nth-child(2) img { transition-delay: .16s; }
  .footer-group .fg-brands.lit a:nth-child(3) img { transition-delay: .32s; }
}

/* ============================================================
   ICON MOTION
   Each mark animates the one element that means something, and
   only while the card is engaged. At rest the accent breathes so
   slowly it reads as a state light rather than an animation.
   ============================================================ */
.ico svg { overflow: visible; }
.ico .ic-hot { transform-box: fill-box; transform-origin: center; }

/* resting state - a slow, near-invisible breath on the accent */
.ico .ic-hot { animation: icoBreathe 5.2s var(--ease-leo) infinite; }
@keyframes icoBreathe { 0%,100% { opacity: .82; } 50% { opacity: 1; } }

/* engaged: the card or row is hovered. The list of surfaces that count
   as engaged is written once, here, and repeated per animation. */
:is(.feature-card, .service-row, .quad-item, .aud-card, .course-card, .delivery-card, .step):hover .ico .a-pulse { animation: icoPulse 1.5s var(--ease-leo) infinite; }
@keyframes icoPulse {
  0%, 100% { transform: scale(1); opacity: .85; }
  45%      { transform: scale(1.18); opacity: 1; }
}

:is(.feature-card, .service-row, .quad-item, .aud-card, .course-card, .delivery-card, .step):hover .ico .a-travel { animation: icoTravel 1.9s cubic-bezier(.5,0,.5,1) infinite; }
@keyframes icoTravel {
  0%   { transform: translateX(-7px); opacity: 0; }
  22%  { opacity: 1; }
  78%  { opacity: 1; }
  100% { transform: translateX(7px); opacity: 0; }
}

:is(.feature-card, .service-row, .quad-item, .aud-card, .course-card, .delivery-card, .step):hover .ico .a-fall { animation: icoFall 1.7s cubic-bezier(.5,0,.5,1) infinite; }
@keyframes icoFall {
  0%   { transform: translateY(-6px); opacity: 0; }
  30%  { opacity: 1; }
  75%  { opacity: 1; }
  100% { transform: translateY(5px); opacity: 0; }
}

:is(.feature-card, .service-row, .quad-item, .aud-card, .course-card, .delivery-card, .step):hover .ico .a-rise { animation: icoRise 1.8s var(--ease-leo) infinite; }
@keyframes icoRise {
  0%   { transform: translateY(5px) scaleY(.86); opacity: 0; }
  35%  { opacity: 1; }
  100% { transform: translateY(-3px) scaleY(1); opacity: 0; }
}

:is(.feature-card, .service-row, .quad-item, .aud-card, .course-card, .delivery-card, .step):hover .ico .a-emit { animation: icoEmit 1.8s var(--ease-leo) infinite; }
@keyframes icoEmit {
  0%   { transform: scale(.72); opacity: 0; }
  35%  { opacity: 1; }
  100% { transform: scale(1.12); opacity: 0; }
}

:is(.feature-card, .service-row, .quad-item, .aud-card, .course-card, .delivery-card, .step):hover .ico .a-blink { animation: icoBlink 1.6s steps(1) infinite; }
@keyframes icoBlink { 0%,55% { opacity: 1; } 62%,72% { opacity: .25; } 79%,100% { opacity: 1; } }

:is(.feature-card, .service-row, .quad-item, .aud-card, .course-card, .delivery-card, .step):hover .ico .a-sweep { animation: icoSweep 3.2s linear infinite; transform-origin: 20px 20px; }
@keyframes icoSweep { to { transform: rotate(360deg); } }

:is(.feature-card, .service-row, .quad-item, .aud-card, .course-card, .delivery-card, .step):hover .ico .a-close { animation: icoClose 1.9s var(--ease-leo) infinite; }
@keyframes icoClose {
  0%, 100% { transform: translateY(0); }
  40%      { transform: translateY(-2.2px); }
  70%      { transform: translateY(0); }
}

/* draw-on: the stroke redraws itself */
.ico .a-draw { stroke-dasharray: 42; stroke-dashoffset: 0; }
:is(.feature-card, .service-row, .quad-item, .aud-card, .course-card, .delivery-card, .step):hover .ico .a-draw { animation: icoDraw 1.9s var(--ease-leo) infinite; }
@keyframes icoDraw {
  0%   { stroke-dashoffset: 42; opacity: .3; }
  35%  { opacity: 1; }
  70%, 100% { stroke-dashoffset: 0; opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .ico .ic-hot, .ico .a-draw { animation: none !important; stroke-dashoffset: 0 !important; }
}

/* ============================================================
   Modal frame - the dialog the enquiry form opens in
   ============================================================ */
.pmodal {
  position: fixed;
  inset: 0;
  z-index: 9990;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 28px;
  background: rgba(0,0,0,0.78);
  backdrop-filter: blur(14px);
  opacity: 0;
  pointer-events: none;
  transition: opacity .4s var(--ease-leo);
}
.pmodal.open { opacity: 1; pointer-events: auto; }
.pmodal-panel {
  width: min(1000px, 100%);
  max-height: 100%;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--panel);
  transform: translateY(18px) scale(.985);
  transition: transform .5s var(--ease-leo);
}
.pmodal.open .pmodal-panel { transform: none; }
.pmodal-close {
  position: sticky;
  top: 0;
  float: inline-end;
  margin: 14px 14px 0;
  width: 42px; height: 42px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(0,0,0,0.5);
  color: var(--text-2);
  display: flex; align-items: center; justify-content: center;
  z-index: 3;
  transition: all .3s var(--ease-leo);
}
.pmodal-close:hover { background: #fff; color: #000; border-color: #fff; }
.pmodal-close svg { width: 18px; height: 18px; }

/* ============================================================
   Cinematic scene hero
   A page header whose subject fills the frame and whose copy
   sits over it: the drawing runs full-bleed at full strength,
   with the same scrim and the same single-column copy block a
   filmed header gets.
   ============================================================ */
.subpage-hero .container { z-index: 2; }
.subpage-hero.has-scene { padding: 235px 0 135px; }
.subpage-hero.has-scene .subpage-hero-grid { grid-template-columns: 1fr; max-width: 880px; }
.subpage-hero.has-scene .scene-canvas { opacity: 0; z-index: 0; }
.subpage-hero.has-scene .scene-canvas.lit {
  opacity: 1;
  /* the motifs are painted at background strength - as the subject
     of the frame they are lifted, not repainted */
  filter: brightness(2.05) saturate(1.15);
}
.subpage-hero.has-scene::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 1;
  background: linear-gradient(to bottom, rgba(0,0,0,0.4) 0%, transparent 30%, transparent 76%, #000 100%);
}
@media (max-width: 768px) { .subpage-hero.has-scene { padding: 170px 0 90px; } }

/* the home hero gets the same lift */
.hero .scene-canvas.lit { filter: brightness(1.7) saturate(1.12); }

/* ============================================================
   Enquiry dialog - a service-scoped form instead of a bare link
   ============================================================ */
.emodal .pmodal-panel { width: min(620px, 100%); }
.enq-head { padding: 44px 42px 6px; display: flex; flex-direction: column; gap: 14px; }
.enq-head img { height: 24px; width: auto; align-self: flex-start; }
.enq-head h2 { font-family: var(--font-display); font-size: 27px; font-weight: 400; color: var(--text-1); }
.enq-topic {
  display: inline-block;
  align-self: flex-start;
  padding: 6px 14px;
  border-radius: 9px;
  border: 1px solid rgba(243,112,33,0.3);
  background: rgba(243,112,33,0.08);
  color: var(--orange-bright);
  font-size: 13.5px;
}
.emodal form { padding: 24px 42px 44px; }
@media (max-width: 640px) {
  .enq-head { padding: 34px 26px 4px; }
  .emodal form { padding: 20px 26px 34px; }
}

/* scene-hero finish: a hairline horizon at the base and a quiet
   contrast bed under the copy on the reading side */
.subpage-hero.has-scene .subpage-hero-grid { position: relative; }
.subpage-hero.has-scene::before { opacity: .8; }
.subpage-hero.has-scene .container::before {
  content: "";
  position: absolute;
  inset: -60px -80px;
  pointer-events: none;
  z-index: -1;
  background: radial-gradient(58% 68% at 26% 50%, rgba(0,0,0,0.5) 0%, transparent 72%);
}
[dir="rtl"] .subpage-hero.has-scene .container::before {
  background: radial-gradient(58% 68% at 74% 50%, rgba(0,0,0,0.5) 0%, transparent 72%);
}
.subpage-hero.has-scene .container { position: relative; }


/* ============================================================
   The page subject
   Every page header carries something opposite the copy: the
   page's drawn object - dark glass, warm core - hanging in the
   scene with a halo behind it, drifting slowly. The copy column
   stays untouched.
   ============================================================ */
.hero-subject {
  position: absolute;
  top: 50%;
  inset-inline-end: max(4vw, calc((100% - 1240px) / 2 - 40px));
  z-index: 1;
  width: clamp(300px, 29vw, 450px);
  aspect-ratio: 1;
  transform: translateY(-46%);
  pointer-events: none;
}
/* the halo blooms behind the object, and doubles as the seam-hider
   for the tile's square plate */
.hero-subject .hs-halo {
  position: absolute;
  inset: -34%;
  background:
    radial-gradient(50% 50% at 50% 50%, rgba(243,112,33,0.20) 0%, rgba(243,112,33,0.07) 46%, transparent 72%);
  opacity: 0;
  animation: hsBloom 2.2s var(--ease-leo) 0.7s forwards;
}
.hero-subject .hs-obj {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* one-axis dissolve, per the house rule: the plate melts top and
     bottom and the halo carries the sides */
  -webkit-mask-image: linear-gradient(to bottom, transparent 2%, #000 26%, #000 78%, transparent 98%);
  mask-image: linear-gradient(to bottom, transparent 2%, #000 26%, #000 78%, transparent 98%);
  filter: brightness(1.12) saturate(1.06) drop-shadow(0 30px 60px rgba(0,0,0,0.55));
  opacity: 0;
  transform: translateY(30px) scale(0.96);
  animation:
    hsEnter 1.5s var(--ease-leo) 0.4s forwards,
    hsFloat 9s ease-in-out 2.4s infinite alternate;
}
@keyframes hsEnter {
  to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes hsBloom {
  to { opacity: 1; }
}
@keyframes hsFloat {
  from { transform: translateY(0) scale(1); }
  to   { transform: translateY(-14px) scale(1.015); }
}
/* pointer parallax writes these */
.hero-subject { --px: 0px; --py: 0px; }
.hero-subject .hs-halo { translate: calc(var(--px) * 0.4) calc(var(--py) * 0.4); }
.hero-subject .hs-obj  { translate: var(--px) var(--py); }

/* the subject shares the frame with a single-column copy block, so pull
   the copy to the start edge instead of centering it */
.subpage-hero.has-subject .subpage-hero-grid { margin-inline-start: 0; }

@media (max-width: 900px) {
  /* on a phone the object steps behind the copy, quiet */
  .hero-subject {
    width: min(72vw, 360px);
    inset-inline-end: -14%;
    top: 46%;
    opacity: 0.4;
  }
}
@media (prefers-reduced-motion: reduce) {
  .hero-subject .hs-obj { animation: hsEnter 0.01s forwards; }
  .hero-subject .hs-halo { animation: hsBloom 0.01s forwards; }
}

/* ============================================================
   The forge - a hero subject that assembles itself
   ------------------------------------------------------------
   js/forge.js measures the mark in .forge-src and animates a
   network of particles into it. The source <svg> has to stay
   rendered for getPointAtLength() to return geometry, so it is
   made invisible with opacity rather than display:none.
   ============================================================ */
.hero-forge .forge-src {
  position: absolute;
  top: 0;
  inset-inline-start: 0;
  width: 40px;
  height: 40px;
  opacity: 0;
  pointer-events: none;
  color: transparent;
}
.hero-forge .forge-src svg { width: 40px; height: 40px; display: block; }

.hero-forge .forge-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 1.4s var(--ease-leo);
}
.hero-forge .forge-canvas.lit { opacity: 1; }

/* the halo is now lighting a drawn mark, not hiding a plate's edge,
   so it sits tighter and cooler than it did under the render */
.hero-forge .hs-halo {
  inset: -22%;
  background:
    radial-gradient(50% 50% at 50% 50%, rgba(243,112,33,0.16) 0%, rgba(243,112,33,0.05) 48%, transparent 74%);
}

/* the pointer parallax in js/academy.js writes --px/--py on .hero-subject;
   it used to move the render plate, so hand it the canvas instead */
.hero-forge .forge-canvas { translate: var(--px) var(--py); }

/* On a phone the copy sits directly over the subject. A solid render
   plate could take that at low opacity - a line drawing cannot, its
   strokes cut straight through the paragraph. The mark stands down and
   the page's scene carries the backdrop alone. */
@media (max-width: 900px) {
  .hero-forge { display: none; }
}

/* ============================================================
   Accessibility toolbar + display modes (see js/a11y.js)
   ------------------------------------------------------------
   The group site carries the same component. Everything here is
   injected at runtime, so no page markup has to know about it.
   ============================================================ */

/* skip link - present always, visible once it takes focus */
.a11y-skip {
  position: fixed;
  inset-inline-start: 50%;
  top: -120px;
  transform: translateX(-50%);
  z-index: 10000;
  background: var(--orange);
  color: #fff;
  padding: 14px 26px;
  border-radius: 0 0 14px 14px;
  font-family: var(--font-display);
  font-size: 15px;
  text-decoration: none;
  transition: top .25s var(--ease-leo);
}
[dir="rtl"] .a11y-skip { transform: translateX(50%); }
.a11y-skip:focus { top: 0; }

.a11y-fab {
  position: fixed;
  inset-inline-start: 20px;
  bottom: 20px;
  z-index: 9990;
  width: 52px; height: 52px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--orange-bright), var(--orange));
  color: #fff;
  box-shadow: var(--shadow-orange);
  transition: transform .45s var(--ease-leo), box-shadow .45s var(--ease-leo);
}
.a11y-fab:hover { transform: translateY(-3px); }

.a11y-panel {
  position: fixed;
  inset-inline-start: 20px;
  bottom: 84px;
  z-index: 9991;
  width: min(320px, calc(100vw - 40px));
  padding: 18px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: rgba(18, 16, 13, 0.97);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  box-shadow: var(--shadow-lg);
}
.a11y-panel[hidden] { display: none; }
.a11y-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.a11y-head h2 { font-family: var(--font-display); font-weight: 500; font-size: 17px; color: var(--text-1); }
.a11y-close { width: 30px; height: 30px; border-radius: 50%; color: var(--text-3); font-size: 15px; }
.a11y-close:hover { color: #fff; background: rgba(255,255,255,0.08); }

.a11y-fs {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; margin-bottom: 14px;
  border: 1px solid var(--line-soft); border-radius: var(--r-sm);
}
.a11y-fs-label { flex: 1; font-size: 14px; color: var(--text-2); }
.a11y-step {
  width: 30px; height: 30px; border-radius: 8px;
  background: rgba(255,255,255,0.06); color: var(--text-1);
  font-size: 17px; line-height: 1;
}
.a11y-step:hover:not(:disabled) { background: var(--orange-soft); }
.a11y-step:disabled { opacity: .35; cursor: default; }
.a11y-fs-val { min-width: 44px; text-align: center; font-size: 13.5px; color: var(--text-3); }

.a11y-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.a11y-opt {
  display: flex; align-items: center; gap: 9px;
  padding: 11px 10px;
  border: 1px solid var(--line-soft); border-radius: var(--r-sm);
  font-size: 13px; color: var(--text-2); text-align: start;
  transition: border-color .3s, background .3s, color .3s;
}
.a11y-opt:hover { border-color: rgba(255,255,255,0.2); color: #fff; }
.a11y-opt[aria-pressed="true"] {
  border-color: rgba(243,112,33,0.55);
  background: var(--orange-50);
  color: #fff;
}
.a11y-ico { font-size: 14px; opacity: .85; flex-shrink: 0; }
.a11y-reset {
  width: 100%; margin-top: 12px; padding: 11px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font-size: 13.5px; color: var(--text-2);
}
.a11y-reset:hover { color: #fff; border-color: rgba(255,255,255,0.24); }
.a11y-note { margin-top: 12px; font-size: 12px; line-height: 1.6; color: var(--text-3); }
.a11y-note a { color: var(--orange-bright); text-decoration: underline; text-underline-offset: 2px; }

/* ---- the modes ---- */
.a11y-zoomed { zoom: var(--a11y-zoom, 1); }
.a11y-grayscale body { filter: grayscale(1); }

.a11y-contrast body { background: #000; }
.a11y-contrast :where(p, li, span, td, th, label, dd, dt, .lede) { color: #fff !important; }
.a11y-contrast :where(h1, h2, h3, h4, h5, h6, strong) { color: #fff !important; }
.a11y-contrast :where(h1, h2, h3) strong,
.a11y-contrast .gradient-text {
  background: none !important;
  -webkit-text-fill-color: #fff !important;
  color: #fff !important;
}
.a11y-contrast a:not(.btn) { color: #ffd39b !important; }
.a11y-contrast :where(section, footer, .card-section, .dark-section, .vendor-card, .partner-logo-cell) {
  background-color: #000 !important;
}
/* the films and the drawn scenes are decoration; hold them right down
   so nothing competes with the text */
.a11y-contrast :where(.page-hero-media, .band-media, .hero-media, canvas, .forge-canvas, .hs-halo) {
  opacity: .12 !important;
}
.a11y-contrast .cta-form :where(input, textarea, select) {
  background: #000 !important; color: #fff !important; border-color: #fff !important;
}

.a11y-links a { text-decoration: underline !important; text-underline-offset: 3px; }
.a11y-links a:not(.btn) { color: #ffd39b !important; background: rgba(243,112,33,0.14); }

.a11y-readable, .a11y-readable :where(h1, h2, h3, h4, h5, h6, p, li, span, a, button, input, textarea, label) {
  font-family: Arial, "Helvetica Neue", Helvetica, sans-serif !important;
  letter-spacing: normal !important;
}

.a11y-nomotion *,
.a11y-nomotion *::before,
.a11y-nomotion *::after {
  animation: none !important;
  transition: none !important;
  scroll-behavior: auto !important;
}
/* WCAG 2.2.2 is satisfied by hiding it. Hiding also parks the work:
   every engine gates its frame on an IntersectionObserver, and a
   display:none canvas reports as not intersecting, so the loops stop
   on their own rather than drawing to something nobody can see. */
:root[data-motion="off"] :where(canvas, .forge-canvas, .scene-canvas, video) { display: none !important; }

.a11y-bigcursor, .a11y-bigcursor * {
  cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 48 48'><path d='M8 4l26 17-11 2 6 13-5 2-6-13-8 8z' fill='%23fff' stroke='%23000' stroke-width='2'/></svg>") 4 4, auto !important;
}

@media (max-width: 560px) {
  .a11y-fab { width: 46px; height: 46px; bottom: 14px; inset-inline-start: 14px; }
  .a11y-panel { bottom: 70px; inset-inline-start: 14px; }
}

/* ============================================================
   The accordion
   One item open at a time, folded by grid rows so it slides. The
   syllabus on a course page is one of these; js/academy.js drives
   the aria-expanded state and the .open class.
   ============================================================ */
.acc { display: grid; gap: 12px; margin-top: 48px; }
.acc-item {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--card);
  overflow: hidden;
  transition: border-color .45s var(--ease-leo), background .45s var(--ease-leo);
}
.acc-item.open { border-color: rgba(243,112,33,0.32); background: var(--card-2); }
.acc-h { margin: 0; }
.acc-h button {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 19px 24px;
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 500;
  color: var(--text-2);
  text-align: start;
  transition: color .3s;
}
.acc-h button:hover, .acc-item.open .acc-h button { color: var(--text-1); }
.acc-x { position: relative; width: 16px; height: 16px; flex-shrink: 0; }
.acc-x::before, .acc-x::after {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 50%;
  width: 100%;
  height: 1.6px;
  border-radius: 1px;
  background: var(--orange-bright);
  transition: transform .45s var(--ease-leo);
}
.acc-x::after { transform: rotate(90deg); }
.acc-item.open .acc-x::after { transform: rotate(0deg); }
.acc-body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .55s var(--ease-leo);
}
.acc-item.open .acc-body { grid-template-rows: 1fr; }
.acc-clip { overflow: hidden; }
/* ------------------------------------------------------------
   The enquiry honeypot.

   Moved off-screen rather than hidden: a bot worth catching skips a
   field declared display:none, and one that does not skip it fills
   everything it finds. aria-hidden and tabindex="-1" in the markup
   keep it away from a keyboard and off the accessibility tree, so it
   is invisible to every person and present only to something reading
   the HTML.
   ------------------------------------------------------------ */
.cta-form .hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ============================================================
   Touch ergonomics

   This site had no equivalent of the pass the group site already
   carries, and it shows on a phone: footer links 18px tall, the legal
   row 22, an FAQ question 28, and the icon buttons between 38 and 42 -
   all under the 44px both Apple's HIG and WCAG 2.5.8 ask for. Measured
   across eight pages in both languages before writing any of this, and
   none of the small links turned out to be inline in prose, so growing
   them cannot break a sentence.

   Two techniques, chosen per control. Text links and pills get real
   padding, because their box is the target and it should look like it.
   Icon buttons keep their drawn size and get a centred pseudo-element
   instead, so the hit area grows and the design does not.

   Keyed to pointer:coarse rather than a width, because it is the input
   that needs this, not the screen - the same key the group site uses.
   ============================================================ */
@media (pointer: coarse) {
  /* text links: the box is the target */
  .site-footer ul a,
  .footer-bottom a,
  .fg-brands a,
  .breadcrumbs a {
    display: inline-block;
    padding-block: 13px;
    line-height: 1.35;
  }
  .site-footer ul li { margin-bottom: 0; }

  /* the FAQ question is the row, not the line of text sitting in it */
  .faq-item { padding-block: 0; }
  .faq-item summary { padding-block: 20px; }
  .faq-item .answer { padding-bottom: 22px; }

  /* pills: grow the box, leave the type alone */
  .filter-btn,
  .group-tag {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  /* The accessibility button floats at the reading-start corner, 52px
     tall and 20px up - the same corner the legal row starts from. At the
     bottom of the page the row sits under it and the first link cannot
     be tapped at its own centre. (The group site does not have this: its
     button is on the reading-end edge, where the short legal row has
     nothing.) Enough room below the row to clear the button's band. */
  .footer-bottom { padding-bottom: 84px; }

  /* icon buttons: the mark keeps its drawn size, only the hit area grows */
  .socials a,
  .menu-toggle,
  .pmodal-close,
  .mobile-drawer .close { position: relative; }

  .socials a::after,
  .menu-toggle::after,
  .pmodal-close::after,
  .mobile-drawer .close::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
  }
}


/* ============================================================
   SPOTACADEMY
   The components the academy adds to the shared language. Each
   one is built from the same parts as everything above it: a dark
   card on var(--card), a 1px var(--line) edge, var(--r-lg) corners,
   the Leo ease, and orange on one element per component - the
   thing it is there to make you do. Logical properties throughout,
   so a rule written once holds in both directions.
   ============================================================ */

/* ---- shared: the go-cue on a card ----------------------------
   The service rail carries one under .service-row. The audience
   and course cards are links too, and they carry the same cue. */
.aud-card .sr-go,
.course-card .sr-go {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: auto;
  padding-top: 6px;
  color: var(--orange-bright);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 15px;
  white-space: nowrap;
  opacity: .8;
  transition: opacity .4s var(--ease-leo), gap .4s var(--ease-leo);
}
.aud-card:hover .sr-go,
.course-card:hover .sr-go { opacity: 1; gap: 12px; }
.aud-card .sr-go svg,
.course-card .sr-go svg { width: 16px; height: 16px; flex-shrink: 0; }
[dir="rtl"] .aud-card .sr-go svg,
[dir="rtl"] .course-card .sr-go svg { transform: scaleX(-1); }

/* cards inside a panel step up one tone, as the feature cards do */
.card-section :is(.aud-card, .course-card, .delivery-card, .step, .outcomes li, .lab-figure, .enq-dock) {
  background: var(--panel-2);
}

/* ---- a small labelled line ------------------------------------
   A caption with a state light in front of it - the NOC head used
   to carry one. Kept generic: a figure caption, a live count. */
.tag {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--font-display);
  font-size: 13.5px;
  color: var(--text-3);
}
.tag .live {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--orange-bright);
  box-shadow: 0 0 0 0 rgba(255,138,61,0.6);
  animation: livePing 2.6s var(--ease-leo) infinite;
}
@keyframes livePing {
  0% { box-shadow: 0 0 0 0 rgba(255,138,61,0.55); }
  70%, 100% { box-shadow: 0 0 0 9px rgba(255,138,61,0); }
}

/* ---- the audience split ---------------------------------------
   Two doors on the home page: individuals and organisations. The
   corporate card carries the larger sale, so it is the one that
   warms on approach - a faint orange edge and a bloom in the far
   corner, nothing more. */
.audience-split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 22px;
  margin-top: 56px;
}
@media (max-width: 820px) {
  .audience-split { grid-template-columns: 1fr; gap: 16px; margin-top: 40px; }
}
.aud-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
  padding: 36px 34px 32px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  transition: transform .5s var(--ease-leo), border-color .5s var(--ease-leo), box-shadow .5s var(--ease-leo);
}
.aud-card:hover { transform: translateY(-6px); border-color: rgba(255,255,255,0.22); }
.aud-card > * { position: relative; }
.aud-card h3 {
  font-family: var(--font-display);
  font-size: clamp(22px, 2.1vw, 28px);
  font-weight: 400;
  line-height: 1.2;
  color: var(--text-1);
  margin-top: 6px;
}
.aud-card p { color: var(--text-3); font-size: 15.5px; line-height: 1.75; max-width: 54ch; }
.aud-card .chips { margin-top: 2px; }
/* a chip inside a link is a label, not a second target */
.aud-card .chip { pointer-events: none; }
.aud-card[data-aud="corporate"]::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(70% 60% at 100% 0%, rgba(243,112,33,0.12), transparent 60%);
  opacity: 0;
  transition: opacity .5s var(--ease-leo);
  pointer-events: none;
}
[dir="rtl"] .aud-card[data-aud="corporate"]::before {
  background: radial-gradient(70% 60% at 0% 0%, rgba(243,112,33,0.12), transparent 60%);
}
.aud-card[data-aud="corporate"]:hover {
  border-color: rgba(243,112,33,0.42);
  box-shadow: 0 0 0 1px rgba(243,112,33,0.10), 0 30px 70px -34px rgba(243,112,33,0.55);
}
.aud-card[data-aud="corporate"]:hover::before { opacity: 1; }
@media (max-width: 560px) { .aud-card { padding: 28px 24px 26px; } }

/* ---- course cards ----------------------------------------------
   The catalogue and the rails on the track pages. Three across,
   two under 1100px, one under 700px; the grid stretches every card
   in a row to the tallest, and the sentence inside takes the slack
   so the meta row and the cue sit level across the row. */
.course-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 22px;
  margin-top: 48px;
}
@media (max-width: 1100px) { .course-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 700px)  { .course-grid { grid-template-columns: 1fr; gap: 14px; margin-top: 36px; } }

.course-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
  padding: 26px 26px 24px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  transition: transform .5s var(--ease-leo), border-color .5s var(--ease-leo);
}
.course-card:hover { transform: translateY(-5px); border-color: rgba(255,255,255,0.22); }
/* the catalogue filter hides with the attribute; the flex above
   would otherwise outrank the browser's own [hidden] rule */
.course-card[hidden] { display: none; }

/* the vendor's mark, quiet at rest and in its own colours on
   approach - the partner wall's treatment, at card size. --lh is the
   wall's optical-area cap when blocks.js writes it; without it a
   wordmark is held by the width cap and a square mark by the height. */
.cc-vendor {
  display: flex;
  align-items: center;
  height: 40px;
  /* room for the level pill in the far corner */
  max-width: calc(100% - 120px);
}
.cc-vendor img {
  height: min(calc(var(--lh, 46px) * 0.7), 34px);
  max-width: 140px;
  width: auto;
  object-fit: contain;
  object-position: left center;
  filter: grayscale(1) brightness(1.9) contrast(0.92);
  opacity: .48;
  transition: filter .55s var(--ease-leo), opacity .55s var(--ease-leo);
}
[dir="rtl"] .cc-vendor img { object-position: right center; }
.course-card:hover .cc-vendor img { filter: none; opacity: 1; }
/* no vendor: the track's own drawn mark stands in */
.cc-vendor.none .ico { width: 40px; height: 40px; border-radius: 12px; }
.cc-vendor.none .ico svg { width: 21px; height: 21px; }

.cc-level {
  position: absolute;
  top: 24px;
  inset-inline-end: 24px;
  padding: 5px 12px;
  border-radius: var(--r-pill);
  border: 1px solid rgba(255,255,255,0.14);
  background: rgba(255,255,255,0.03);
  font-family: var(--font-display);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: .02em;
  line-height: 1.3;
  color: var(--text-2);
  white-space: nowrap;
}
.course-card h3 {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 500;
  line-height: 1.3;
  color: var(--text-1);
  margin-top: 4px;
}
/* the vendor's old name for the same course, under the current one */
.cc-formerly {
  display: block;
  margin-top: 4px;
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 400;
  color: var(--text-3);
}
.course-card > p { color: var(--text-3); font-size: 14.8px; line-height: 1.7; flex: 1; }
.cc-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  padding-top: 12px;
  border-top: 1px solid var(--line-soft);
  font-size: 13.5px;
  color: var(--text-3);
}
.cc-meta span { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
@media (max-width: 560px) {
  .course-card { padding: 22px 20px 20px; }
  .cc-level { top: 20px; inset-inline-end: 18px; }
}

/* ---- the catalogue filter bar -----------------------------------
   Four groups of pills, one per key, wrapping freely - nothing here
   is a track that cannot shrink. The count line is aria-live, and
   reserves its own height so the grid does not jump when it fills. */
.cat-filters {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 44px;
}
.cat-group,
.cat-filters > div,
.cat-filters > fieldset {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  min-inline-size: 0;
  border: 0;
  padding: 0;
  margin: 0;
}
.cat-label,
.cat-filters legend {
  float: inline-start;
  padding: 0;
  margin-inline-end: 6px;
  min-width: 64px;
  font-family: var(--font-display);
  font-size: 13.5px;
  color: var(--text-3);
}
.cat-filters .filter-btn { padding: 9px 16px; font-size: 14px; }
.cat-count {
  min-height: 1.6em;
  margin-top: 8px;
  font-size: 14px;
  color: var(--text-3);
}
.cat-count .n, .cat-count b, .cat-count strong { font-weight: 500; color: var(--text-1); }
@media (max-width: 560px) {
  .cat-filters { margin-top: 32px; gap: 10px; }
  .cat-label, .cat-filters legend { min-width: 100%; margin: 0 0 2px; }
}

/* ---- the course facts ---------------------------------------------
   A definition list, one fact per row, set inside the hero's aside
   card opposite the copy. Rows may be bare dt/dd pairs or wrapped in
   a div each - display:contents lets both shapes land on the grid. */
.course-facts {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  margin: 0;
}
.course-facts > div { display: contents; }
.course-facts dt,
.course-facts dd {
  padding: 12px 0;
  border-top: 1px solid var(--line-soft);
  margin: 0;
}
.course-facts > dt:first-child,
.course-facts > dt:first-child + dd,
.course-facts > div:first-child > * { border-top: 0; padding-top: 0; }
.course-facts > dt:last-of-type,
.course-facts > dd:last-of-type,
.course-facts > div:last-child > * { padding-bottom: 0; }
.course-facts dt {
  font-family: var(--font-display);
  font-size: 13.5px;
  color: var(--text-3);
  padding-inline-end: 22px;
  white-space: nowrap;
}
.course-facts dd {
  color: var(--text-1);
  font-size: 15px;
  line-height: 1.55;
  min-width: 0;
}
.course-facts dd .chips { gap: 6px; }
.course-facts dd .chip { padding: 5px 12px; font-size: 12.5px; }
/* exam codes and product names are Latin with digits - isolate them so
   RTL never reorders "FCP_FGT_AD-7.6" */
.course-facts dd code {
  font-family: var(--font-display);
  font-size: 14px;
  direction: ltr;
  unicode-bidi: isolate;
}

/* ---- the hero with an aside -----------------------------------
   The course hero: copy on the reading side, the facts card on the
   other. The forged subject still hangs where it always does; the
   card is glass, so the mark glows through behind the facts rather
   than being pushed off the page. Stacked under 1000px. */
.subpage-hero.has-aside .subpage-hero-grid {
  grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
  gap: 56px;
  align-items: center;
  max-width: none;
}
.subpage-hero.has-aside .hero-subject { z-index: 0; opacity: .7; }
.hero-aside {
  position: relative;
  z-index: 2;
  min-width: 0;
  padding: 28px 30px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  /* Thinner than the other glass on the site, and 10px of blur rather
     than the site's usual 14px, because the vendor's mark used to sit
     behind this panel and had to read through it.

     It does not any more - it hangs below the panel now, see "The
     vendor's mark, behind a course hero" further down - so the reason
     for both numbers has gone. They are left alone deliberately: the
     panel's contrast was measured on them and comes out better than
     before rather than worse (5.85:1 for the labels and 16.35:1 for
     the values at rest, 5.50:1 and 14.67:1 at the brightest frame of
     the mark's arrival, against 5.71:1 and 15.65:1 with the mark
     behind the glass). Putting the glass back to the site's usual is a
     separate decision about how this panel should look. */
  background: rgba(10,9,8,0.56);
  backdrop-filter: blur(10px) saturate(1.2);
  -webkit-backdrop-filter: blur(10px) saturate(1.2);
  box-shadow: var(--shadow-lg);
}
.hero-aside .aside-title,
.hero-aside > h2 {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 500;
  color: var(--text-1);
  margin-bottom: 14px;
}
@media (max-width: 1000px) {
  .subpage-hero.has-aside .subpage-hero-grid { grid-template-columns: 1fr; gap: 34px; }
  .hero-aside { padding: 22px 22px 24px; }
}

/* ---- outcomes -----------------------------------------------------
   "What you will be able to do": one card per line, a small check
   mark in front of each. The mark is the verified glyph's own tick,
   cropped to itself (blocks.js writes it as svg.oc-check); it draws
   itself once as the row arrives, the way the icon set's hot element
   draws on a card. Framed as .ico, small, is also accepted. */
.outcomes {
  list-style: none;
  margin: 40px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px 22px;
}
@media (max-width: 760px) { .outcomes { grid-template-columns: 1fr; gap: 10px; margin-top: 32px; } }
.outcomes li {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  min-width: 0;
  padding: 16px 18px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  color: var(--text-2);
  font-size: 15.5px;
  line-height: 1.6;
}
.outcomes li > span { min-width: 0; }
.outcomes .ico { width: 36px; height: 36px; border-radius: 11px; margin-top: -2px; }
.outcomes .ico svg { width: 19px; height: 19px; }
.outcomes .oc-check {
  width: 22px; height: 22px;
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--orange-bright);
  overflow: visible;
}
/* drawn by default, so a list with no reveal classes, or a visitor who
   has switched motion off, sees a finished tick; only a row that is
   still waiting to be revealed holds it back, and only its arrival
   draws it */
.outcomes .oc-check .a-draw { stroke-dasharray: 42; }
.outcomes li.reveal:not(.in) .oc-check .a-draw { stroke-dashoffset: 42; }
.outcomes li.reveal.in .oc-check .a-draw { animation: icoDraw .9s var(--ease-leo) .3s backwards; }
@media (prefers-reduced-motion: reduce) {
  .outcomes .oc-check .a-draw { animation: none !important; stroke-dashoffset: 0 !important; }
}

/* ---- the syllabus -------------------------------------------------
   The accordion above, one module per item, the module number in
   front of its name. The body is the module's topics as a chip
   list, so a module reads as a set rather than as a paragraph. */
.syllabus { margin-top: 40px; gap: 10px; }
.syllabus .acc-h button { font-size: 16.5px; padding: 18px 22px; }
/* the number keeps its own width; the title after it takes the slack,
   so the two sit together and the cross stays at the far edge */
.syl-n {
  flex: none;
  font-family: var(--font-display);
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  color: var(--orange-bright);
  direction: ltr;
  unicode-bidi: isolate;
}
.syllabus .acc-h button > .syl-n + span { flex: 1; min-width: 0; }
.syl-items {
  list-style: none;
  margin: 0;
  padding: 2px 22px 22px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.syl-items li {
  padding: 7px 14px;
  border-radius: var(--r-pill);
  border: 1px solid rgba(255,255,255,0.12);
  background: rgba(255,255,255,0.025);
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--text-2);
}
@media (max-width: 560px) {
  .syllabus .acc-h button { font-size: 15.5px; padding: 16px 18px; }
  .syl-items { padding: 0 18px 18px; }
}

/* ---- the two delivery formats ---------------------------------
   The open cohort for one person; the intensive for a team. Same
   card twice, so the two read as a choice, each with its own button.
   A course not offered for open enrolment says so in a dashed card. */
.delivery {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 22px;
  margin-top: 44px;
}
@media (max-width: 860px) { .delivery { grid-template-columns: 1fr; gap: 16px; margin-top: 36px; } }
.delivery-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
  padding: 32px 30px 30px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  transition: transform .5s var(--ease-leo), border-color .5s var(--ease-leo);
}
.delivery-card:hover { transform: translateY(-4px); border-color: rgba(255,255,255,0.22); }
.delivery-card h3 {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 400;
  color: var(--text-1);
  margin-top: 4px;
}
.delivery-card p { color: var(--text-3); font-size: 15px; line-height: 1.7; }
.delivery-card ul {
  list-style: none;
  margin: 2px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.delivery-card li {
  position: relative;
  padding-inline-start: 20px;
  color: var(--text-2);
  font-size: 14.5px;
  line-height: 1.55;
}
.delivery-card li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 9px;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--orange);
  opacity: .8;
}
.delivery-card .chips { gap: 6px; }
.delivery-card .btn { align-self: flex-start; margin-top: auto; }
.delivery-card .btn:first-of-type { margin-top: 12px; }
.delivery-card.by-request { border-style: dashed; }
.delivery-card.by-request:hover { transform: none; border-color: var(--line); }
@media (max-width: 560px) {
  .delivery-card { padding: 26px 22px 24px; }
  .delivery-card .btn { align-self: stretch; justify-content: center; }
}

/* ---- the enquiry dock ----------------------------------------------
   blocks.js writes it as .enq-dock[data-dock] > .dock-inner, holding
   the course name (.dock-name), the button into the enquiry dialog
   and the phone number (a.dock-phone.ltr-num). On a desktop the
   course body runs in two columns (.course-layout, written by the
   page) and the dock is the second: a small card that stays put while
   the syllabus scrolls. On a phone it is a bar along the bottom edge,
   shown once the hero has gone by (js/academy.js adds .on) and held
   out of the tab order until then. The bar's bottom padding respects
   the home indicator; the two side insets are physical by definition,
   so those two are set physically. */
.course-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 48px;
  align-items: start;
}
.enq-dock {
  position: sticky;
  top: 110px;
  min-width: 0;
  padding: 24px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  /* the handset drawn in front of the number, inlined so it needs no
     second request and no markup; the phone bar shows it alone */
  --phone-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z'/%3E%3C/svg%3E");
}
.enq-dock .dock-inner {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}
.enq-dock .dock-name {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 500;
  line-height: 1.35;
  color: var(--text-1);
}
.enq-dock .btn { justify-content: center; }
.enq-dock .dock-phone {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: 44px;
  font-size: 14.5px;
  color: var(--text-2);
  transition: color .3s;
}
.enq-dock .dock-phone::before {
  content: "";
  width: 17px; height: 17px;
  flex-shrink: 0;
  background: var(--orange);
  -webkit-mask: var(--phone-glyph) center / contain no-repeat;
          mask: var(--phone-glyph) center / contain no-repeat;
}
.enq-dock .dock-phone:hover { color: var(--orange-bright); }

@media (max-width: 999px) {
  .course-layout { grid-template-columns: 1fr; gap: 0; }
  .enq-dock {
    position: fixed;
    inset-inline: 0;
    top: auto;
    bottom: 0;
    z-index: 850;
    padding-top: 10px;
    padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px));
    padding-left: max(14px, env(safe-area-inset-left, 0px));
    padding-right: max(14px, env(safe-area-inset-right, 0px));
    border-radius: 0;
    border-width: 1px 0 0;
    background: rgba(8,7,6,0.92);
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    box-shadow: 0 -12px 40px -16px rgba(0,0,0,0.7);
    transform: translateY(110%);
    visibility: hidden;
    transition: transform .5s var(--ease-leo), visibility .5s;
  }
  .enq-dock.on { transform: none; visibility: visible; }
  .enq-dock .dock-inner { flex-direction: row; align-items: center; gap: 12px; }
  /* two short lines rather than one cut short: at 390px the name has
     about 90px beside the button, and "FortiGate fi..." says less
     than "FortiGate firewall / administration" does */
  .enq-dock .dock-name {
    flex: 1;
    min-width: 0;
    font-size: 13px;
    line-height: 1.25;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
  }
  /* the button gives up its arrow: at 390px the bar has about 90px
     left for the name once the button and the phone have theirs, and
     the arrow was 28px of that */
  .enq-dock .btn { flex-shrink: 0; min-height: 44px; padding: 11px 18px; font-size: 14.5px; }
  .enq-dock .btn .arrow { display: none; }
  /* the number stays in the link, so a screen reader still hears it;
     only the handset is drawn, in a 44px ring */
  .enq-dock .dock-phone {
    flex-shrink: 0;
    width: 44px;
    min-height: 44px;
    gap: 0;
    border: 1px solid var(--line);
    border-radius: 50%;
    font-size: 0;
    color: transparent;
  }
  .enq-dock .dock-phone::before { width: 18px; height: 18px; }
  /* the accessibility button lives in the same corner: lift it, and its
     panel, clear of the bar while the bar is up */
  body:has(.enq-dock.on) .a11y-fab { bottom: calc(14px + 68px + env(safe-area-inset-bottom, 0px)); }
  body:has(.enq-dock.on) .a11y-panel { bottom: calc(70px + 68px + env(safe-area-inset-bottom, 0px)); }
  /* and the legal row at the foot of the page is not left under it */
  body:has(.enq-dock.on) .footer-bottom { padding-bottom: calc(84px + 68px); }
}
@media (prefers-reduced-motion: reduce) { .enq-dock { transition: none; } }

/* ---- the certification ladder ------------------------------------
   The vendor's rungs in order, a hairline through the badges, the
   rungs the academy teaches lit and the rest standing back. Any
   number of rungs shares the row equally; under 760px the ladder
   turns and runs down the page with the line down its spine. */
.cert-ladder {
  position: relative;
  list-style: none;
  margin: 52px 0 0;
  padding: 0;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 14px;
}
.cert-ladder::before {
  content: "";
  position: absolute;
  top: 27px;
  inset-inline: 10%;
  height: 1px;
  background: linear-gradient(to right, transparent, var(--line) 10%, rgba(255,255,255,0.18) 50%, var(--line) 90%, transparent);
  z-index: 0;
}
.cert-ladder > li {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 10px;
  min-width: 0;
  opacity: .62;
  transition: opacity .5s var(--ease-leo);
}
.cert-ladder > li.taught { opacity: 1; }
.rung-code {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 64px;
  height: 54px;
  padding: 0 16px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--card);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: .03em;
  color: var(--text-2);
  /* "NSE 5-6" carries a hyphen, which is a place a line may break -
     and did, inside the phone's 64px badge */
  white-space: nowrap;
  direction: ltr;
  unicode-bidi: isolate;
  transition: border-color .5s var(--ease-leo), background .5s var(--ease-leo), box-shadow .5s var(--ease-leo);
}
.taught .rung-code {
  background: linear-gradient(135deg, var(--orange-bright), var(--orange));
  border-color: transparent;
  color: #fff;
  box-shadow: 0 14px 34px -14px rgba(243,112,33,0.7);
}
.rung-name {
  font-family: var(--font-display);
  font-size: 14.5px;
  line-height: 1.35;
  color: var(--text-2);
}
.taught .rung-name { color: var(--text-1); }
.rung-legacy {
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--text-3);
  unicode-bidi: plaintext;
}
/* "taught at the academy", under a lit rung. The lit badge is the
   rung's orange; this is a caption and stays in the text scale. */
.rung-tag {
  margin-top: 2px;
  font-family: var(--font-display);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--text-2);
}
@media (max-width: 760px) {
  .cert-ladder {
    grid-auto-flow: row;
    grid-auto-columns: auto;
    grid-template-columns: 1fr;
    gap: 18px;
    margin-top: 40px;
  }
  .cert-ladder::before {
    top: 27px;
    bottom: 27px;
    height: auto;
    inset-inline: auto;
    inset-inline-start: 32px;
    width: 1px;
    background: linear-gradient(to bottom, transparent, var(--line) 8%, rgba(255,255,255,0.18) 50%, var(--line) 92%, transparent);
  }
  /* the badge down the spine, the name and its captions beside it.
     Three rows named so the badge can span them all; a rung with no
     legacy name or no tag leaves its row empty at no height. */
  .cert-ladder > li {
    display: grid;
    grid-template-columns: 64px minmax(0, 1fr);
    grid-template-rows: auto auto auto;
    column-gap: 16px;
    row-gap: 2px;
    align-items: center;
    align-content: center;
    text-align: start;
  }
  .rung-code { grid-column: 1; grid-row: 1 / 4; width: 64px; min-width: 0; padding: 0; font-size: 14px; letter-spacing: .02em; }
  .rung-name, .rung-legacy, .rung-tag { grid-column: 2; }
  .rung-tag { margin-top: 0; }
}

/* ---- the four steps -------------------------------------------------
   The method: assessment, program, hands-on, certification. A big
   light number in the gradient, then the step. Four across, two on a
   tablet, one on a phone. */
.steps-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 22px;
  margin-top: 56px;
}
@media (max-width: 1000px) { .steps-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px)  { .steps-grid { grid-template-columns: 1fr; gap: 14px; margin-top: 40px; } }
.step {
  position: relative;
  min-width: 0;
  padding: 30px 28px 32px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  transition: transform .5s var(--ease-leo), border-color .5s var(--ease-leo);
}
.step:hover { transform: translateY(-5px); border-color: rgba(243,112,33,0.3); }
.step-n {
  display: block;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(44px, 4vw, 60px);
  line-height: 1;
  letter-spacing: -0.02em;
  background: var(--grad-word);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  direction: ltr;
  unicode-bidi: isolate;
  width: fit-content;
}
.step h3 {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 500;
  color: var(--text-1);
  margin: 22px 0 10px;
}
.step p { color: var(--text-3); font-size: 15px; line-height: 1.7; }
.step .ico { margin-top: 20px; }
@media (max-width: 560px) { .step { padding: 24px 22px 26px; } .step h3 { margin-top: 16px; } }

/* ---- the lab figure -------------------------------------------------
   The classroom photograph, framed the way the site frames film: the
   rounded card, a scrim up from the foot, the caption on the scrim
   and three badges over the top corner (blocks.js writes them as
   .lab-badges between the image and the figcaption). On a phone the
   caption steps below the photograph, where it has room; the badges
   stay on it. */
.lab-figure {
  position: relative;
  margin: 48px 0 0;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--card);
  overflow: hidden;
}
.lab-figure img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  filter: brightness(.92) saturate(.92);
  transition: transform 1.4s var(--ease-leo);
}
.lab-figure:hover img { transform: scale(1.02); }
.lab-figure::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0,0,0,0.74) 0%, rgba(0,0,0,0.22) 38%, transparent 62%);
  pointer-events: none;
}
.lab-figure figcaption {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  z-index: 2;
  padding: 26px 30px;
  color: var(--text-2);
  font-size: 15px;
  line-height: 1.6;
  max-width: 64ch;
}
.lab-badges {
  position: absolute;
  top: 18px;
  inset-inline-start: 18px;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  max-width: calc(100% - 36px);
}
.lab-badge {
  display: inline-flex;
  align-items: center;
  padding: 7px 14px;
  border-radius: var(--r-pill);
  border: 1px solid rgba(255,255,255,0.22);
  background: rgba(0,0,0,0.45);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  font-family: var(--font-display);
  font-size: 13px;
  line-height: 1.3;
  color: #fff;
  white-space: nowrap;
}
@media (max-width: 640px) {
  .lab-figure { margin-top: 36px; }
  .lab-figure img { aspect-ratio: 4 / 3; }
  .lab-figure::after { display: none; }
  .lab-figure figcaption {
    position: static;
    max-width: none;
    padding: 16px 18px 18px;
    font-size: 14.5px;
    border-top: 1px solid var(--line);
  }
  .lab-badges { top: 14px; inset-inline-start: 14px; max-width: calc(100% - 28px); }
}

/* ---- the enquiry switch ---------------------------------------------
   Two radios, visually hidden but still focusable, and their labels
   drawn as a segmented control: the checked side in the button
   gradient, the other a ghost. The pill is the <span>, so the state
   can be drawn with a sibling selector and needs nothing newer. */
.cta-form .enq-switch {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 5px;
  padding: 5px;
  margin: 0;
  min-inline-size: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: rgba(255,255,255,0.03);
}
.enq-switch legend {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}
.seg { display: flex; min-width: 0; cursor: pointer; }
.cta-form .seg input {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  opacity: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  pointer-events: none;
}
.seg span {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 10px 14px;
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  font-family: var(--font-display);
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.3;
  color: var(--text-2);
  text-align: center;
  transition: background .35s var(--ease-leo), color .35s var(--ease-leo), border-color .35s var(--ease-leo), box-shadow .35s var(--ease-leo);
}
.seg:hover span { color: #fff; border-color: rgba(255,255,255,0.18); }
/* :checked is the truth; .on is what js/academy.js mirrors onto the
   label, so the same look is reachable without a sibling selector */
.seg input:checked + span,
.seg.on span {
  background: linear-gradient(135deg, var(--orange-bright), var(--orange));
  border-color: transparent;
  color: #fff;
  box-shadow: var(--shadow-orange);
}
.seg input:focus-visible + span { outline: 2px solid var(--orange-bright); outline-offset: 3px; }

/* the two audience-specific field groups sit inside the form's own
   grid, so the wrapper dissolves and the fields take their cells;
   hidden, the whole group leaves the grid together */
.enq-ind, .enq-corp { display: contents; }
.enq-ind[hidden], .enq-corp[hidden] { display: none; }

/* ---- the consent row ------------------------------------------------
   A real checkbox at 24px, the sentence beside it at 14px, the link
   underlined. The form's field rule would stretch the box to the
   column - held here to its own size. */
.consent {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-3);
  cursor: pointer;
}
.cta-form .consent input[type="checkbox"] {
  appearance: auto;
  -webkit-appearance: auto;
  width: 24px;
  height: 24px;
  flex: 0 0 24px;
  margin: 0;
  padding: 0;
  border-radius: 7px;
  accent-color: var(--orange);
  cursor: pointer;
}
.consent > span, .consent label { min-width: 0; }
.consent a {
  color: var(--text-2);
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color .3s;
}
.consent a:hover { color: var(--orange-bright); }

/* ---- the marks on touch --------------------------------------------
   The course card's vendor logo takes the wall's per-frame light when
   js/glow.js writes --near on the card, and a press lights it outright.
   Without either it rests at the wall's floor, which is still legible. */
@media (hover: none), (pointer: coarse) {
  .course-card { --lit: var(--near, 0); }
  .course-card:active { --lit: 1; }
  .cc-vendor img {
    filter:
      grayscale(calc(1 - var(--lit)))
      brightness(calc(1 + 0.9 * (1 - var(--lit))))
      contrast(calc(1 - 0.08 * (1 - var(--lit))));
    opacity: calc(0.52 + 0.48 * var(--lit));
    transition: none;
  }
}

/* ---- touch ergonomics for the new controls -------------------------- */
@media (pointer: coarse) {
  .consent { min-height: 44px; align-items: center; }
  .cc-meta { padding-top: 14px; }
  .cat-filters .filter-btn { min-height: 44px; }
}

/* ---- high contrast: the new surfaces go to black with the rest ------ */
.a11y-contrast :where(.aud-card, .course-card, .delivery-card, .step, .outcomes li, .hero-aside, .enq-dock, .lab-figure, .rung-code, .seg span) {
  background-color: #000 !important;
}
.a11y-contrast .step-n {
  background: none !important;
  -webkit-text-fill-color: #fff !important;
  color: #fff !important;
}
/* the lit rung and the chosen segment keep their state as a fill:
   white on black, which is the one contrast that needs no gradient */
.a11y-contrast .taught .rung-code,
.a11y-contrast .seg input:checked + span {
  background: #fff !important;
  color: #000 !important;
  -webkit-text-fill-color: #000 !important;
  border-color: #fff !important;
  box-shadow: none !important;
}

/* the catalogue anchors the nav points at sit under a fixed pill; the
   offset keeps a no-script fragment jump from landing beneath it */
.cat-anchor { display: block; scroll-margin-top: 120px; }


/* ============================================================
   From the launch sweep - both languages, both breakpoints
   ============================================================ */
/* The English home headline: four lines at 104px put the buttons
   under an 800px fold. A lower ceiling holds it to three, as the
   Hebrew rule above already does for its side; balance keeps a
   one-word orphan off the last line in either language. */
[dir="ltr"] .hero .display-1 { font-size: min(clamp(44px, 7vw, 104px), 5.8vw, 84px); }
.hero .display-1 { text-wrap: balance; }
@media (max-height: 840px) and (min-width: 561px) {
  .hero .display-1 { font-size: min(clamp(40px, 6vw, 84px), 5.6vw, 78px); }
}
/* A course hero shares its row with the facts panel, so the title has
   about half the width the other heroes have. */
.subpage-hero.has-aside .display-1 { font-size: clamp(34px, 4.6vw, 66px); text-wrap: balance; }
@media (max-width: 560px) {
  .subpage-hero.has-aside .display-1 { font-size: 32px; }
  .subpage-hero { padding: 116px 0 56px; }
  .cta-banner { padding: 36px 20px; }
}
/* the buttons under a left-aligned lede start where the lede starts */
.subpage-hero .hero-ctas { justify-content: flex-start; }
/* 44px on a coarse pointer, for the three controls that measured 42 and 38 */
.lang-switch, .menu-toggle { min-width: 44px; min-height: 44px; }
.socials a { width: 44px; height: 44px; }
/* the accessibility button steps aside while a dialog or the drawer is open */
body:has(.pmodal.open, .mobile-drawer.open) .a11y-fab,
body:has(.pmodal.open, .mobile-drawer.open) .a11y-panel { visibility: hidden; }
/* the enquiry button in the phone drawer */
.mobile-drawer .panel .btn { margin-top: 16px; justify-content: center; align-self: stretch; }
/* a wide wordmark was width-limited by the cell before it reached its optical height */
.partner-logo-cell { padding-inline: 10px; }
/* the catalogue with nothing left to show */
.cat-empty { display: none; margin-top: 18px; color: var(--text-3); font-size: 15px; }
.cat-filters.empty .cat-empty { display: block; }
.cat-reset { color: var(--orange-bright); text-decoration: underline; text-underline-offset: 3px; font: inherit; padding: 4px 0; }


/* ============================================================
   The vendor's mark, behind a course hero - struck once

   Placed as the file, not painted through a mask: the asset is already
   the logo in the vendor's own colours - Fortinet's white letters with
   the red accent, Palo Alto's white with its orange - and a mask flattens
   both to one. Alpha is what makes it a watermark: a gradient that fades
   the mark into the ground, and a clip that lets it in.

   The global img cap has to be lifted, or it is held to its container.

   ------------------------------------------------------------
   Where it sits. It used to be centred on the hero's end side, which
   is the side the facts panel is on - so the panel's blur ran a grey
   stripe through the middle of the word and left a chunk sticking out
   at each end. Measured at 1440x900 the panel was 72..637 and the mark
   51..691: the mark was bisected on every course page, in both
   languages.

   It hangs off the bottom of the facts panel now, which is why
   blocks.js wraps the panel in .hero-side. The obvious anchor - the
   hero's own bottom edge, where ::before already draws a warm horizon
   - is the one that cannot be used: the English headline wraps to four
   lines where the Hebrew takes three, so the hero is around two
   hundred pixels taller in English and the same rule puts the mark
   inside the frame in one language and under the fold in the other.
   The panel is vertically centred in the hero, so hanging the mark
   from it lands in both.

   It is anchored to the frame edge it leaves by, and the falloff is a
   radial from that corner - densest where it runs out of the page,
   gone well before the headline column.

   How big. The house rule for a wall of marks - h = C / sqrt(aspect),
   clamped - is what keeps an 8.6:1 wordmark and a 1.9:1 block at the
   same optical weight. build/blocks.js computes it and writes --vw and
   --vh into the markup, the way the group site's client marquee
   carries its own numbers.

   ------------------------------------------------------------
   How it arrives. js/forge.js writes a stroke with a pulse running its
   real arc length and the ink landing just behind. A filled wordmark
   has no stroke to run - getPointAtLength on these paths walks the
   outline of each letter, which at this size is fuzz - so this is the
   sibling for filled art. The light enters at the frame edge the mark
   is cut by, runs inward along the line the mark is read on, and the
   ink lands behind it. The light is the mark's own file at full
   brightness over a warm spot on the ground: the vendor's colours
   lifted rather than replaced, and a bloom arriving on the surface,
   which is the argument js/glow.js makes for why light has to be drawn
   and not implied.

   Once, and then it rests. The middle of this hero already has the
   forge breathing on an 11-second cycle; two things breathing is one
   too many. The reveal engine in js/academy.js hands over .in when the
   hero is in view and unobserves - which is also why a phone, where
   the mark sits four hundred pixels below the fold, sees it struck
   rather than walking in on a mark that has been holding since load.
   ============================================================ */
/* the column the facts panel sits in, so the mark can hang from it */
.hero-side { position: relative; min-width: 0; }

.hero-vendor {
  /* the frame edge the mark leaves by, and the corner the light
     enters at - the one place direction is named, so nothing else in
     this block has to care which way the page runs */
  --hv-x: 100%;
  /* the inner edge the mark fades toward - the copy's side */
  --hv-side: left;
  --hv-rest: .34;
  --hv-ease: cubic-bezier(.32, 0, .2, 1);
  --hv-strike: 1.75s;
  /* Out to the frame edge, and not one pixel past it. An earlier pass
     here ran the mark off the page and let the frame cut it, which
     gives you the head of the word in Hebrew and its tail in English -
     "FORTINE" against "RTINET" - and a cut wordmark reads as a broken
     page rather than as a crop. The owner said the same thing about a
     big cropped mark before this was built. So the mark is whole, and
     its outer edge lines up with the outer edge of the facts panel
     hanging above it, which is an alignment the reader can see. */
  --hv-bleed: 0px;

  position: absolute;
  /* The whole lockup, flush with the frame edge, dissolving inward
     toward the copy. One image mirrored rather than two: the dense end
     is the head of the wordmark under RTL and its tail under LTR, but
     the composition - dense at the outer edge, gone before the copy
     column - is the same on both sides of the screen, and neither
     language loses a letter. */
  inset-inline-end: calc(var(--hv-bleed) * -1);
  inset-block-start: calc(100% + clamp(10px, 1.4vw, 20px));
  /* The optical-area rule gives a height, and the file's own
     proportions give the width from it. Fortinet's 8.6:1 lockup at
     112px wants 965px, which is wider than the column it hangs in - so
     max-width caps it and the aspect ratio takes the height down with
     it. That is what keeps the mark whole: it is as large as its own
     column allows and no larger, on every vendor, in both languages. */
  width: min(100%, calc(var(--vw) * 1px));
  aspect-ratio: var(--vw) / var(--vh);
  height: auto;
  /* behind the panel's column and behind the copy, which is what
     "the headline has to win" means when the mark is inside .container
     rather than behind it */
  z-index: -1;
  pointer-events: none;
  /* The mark sits wholly inside the panel's own column now, so it has
     no copy to get out of the way of and the falloff is a soft inner
     edge rather than a radial that eats it. The old radial was drawn
     for a mark that ran off the page; against a mark that does not, it
     left one letter showing. no-repeat matters: the default tiles the
     gradient, and the bloom overflows this box on purpose - with a
     repeating mask it would come back up the hero in bands. */
  -webkit-mask-image: linear-gradient(to var(--hv-side), #000 0%, #000 78%, rgba(0,0,0,.85) 90%, rgba(0,0,0,.55) 100%);
          mask-image: linear-gradient(to var(--hv-side), #000 0%, #000 78%, rgba(0,0,0,.85) 90%, rgba(0,0,0,.55) 100%);
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}

[dir="rtl"] .hero-vendor { --hv-x: 0%; --hv-side: right; }

/* A track hero has no facts panel to hang from - blocks.js leaves the
   mark where it always was, a direct child of the hero - so it takes
   the hero's own bottom edge instead. It can: a track hero is one
   headline and one lede and comes out the same height in both
   languages, which is the thing a course hero does not do. */
.subpage-hero > .hero-vendor {
  inset-block-start: auto;
  inset-block-end: clamp(18px, 5vh, 58px);
  z-index: 0;
}

.hero-vendor img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
}

/* The reveal engine's own opening move - up thirty pixels and fade -
   is not this one. It is here for the .in class and nothing else. */
.hero-vendor.reveal { opacity: 0; transform: none; transition: none; }

/* the mark, at its resting weight, clipped to nothing until the light
   has passed over it */
/* A course hero hangs the facts panel over the mark and the mark below
   the hero's own bottom edge, so the band the mark has is the old 124px
   and not a pixel more - a taller lockup gets its wordmark cut off by
   the hero's overflow. The track pages have the whole width of that
   band free, which is where the optical-area size (Cisco 455x240 rather
   than 235x124) belongs. Same rule, two amounts of room: the third
   term caps the height at 124 and lets the file's own proportions take
   the width down with it. */
.subpage-hero:has(.hero-aside) .hero-vendor {
  width: min(100%, calc(var(--vw) * 1px), calc(124px * var(--vw) / var(--vh)));
}

.hv-mark { opacity: var(--hv-rest); clip-path: inset(0 0 0 100%); }
[dir="rtl"] .hv-mark { clip-path: inset(0 100% 0 0); }

/* the same file at full brightness, in a band that travels with the
   front - an eighth of the mark's width, so the lit line is always
   growing out of the light rather than appearing somewhere else */
.hv-lume { opacity: 0; filter: brightness(1.7) saturate(1.15); clip-path: inset(0 -12% 0 100%); }
[dir="rtl"] .hv-lume { clip-path: inset(0 100% 0 -12%); }

/* the ground under the front, not the mark: a warm spot travelling
   the same path, which is what makes the pass read as light */
.hv-bloom {
  position: absolute;
  inset-block: -140% -140%;
  inline-size: 40%;
  inset-inline-end: -20%;
  opacity: 0;
  background: radial-gradient(closest-side, rgba(255,196,140,.50) 0%, rgba(243,112,33,.22) 44%, transparent 76%);
}

.hero-vendor.in                    { animation: hvSettle 2.5s var(--hv-ease) .2s both; }
.hero-vendor.in .hv-mark           { animation: hvInk    var(--hv-strike) var(--hv-ease) .35s both; }
.hero-vendor.in .hv-lume           { animation: hvLume   var(--hv-strike) var(--hv-ease) .35s both; }
.hero-vendor.in .hv-bloom          { animation: hvBloom  var(--hv-strike) var(--hv-ease) .35s both; }
[dir="rtl"] .hero-vendor.in .hv-mark { animation-name: hvInkRtl; }
[dir="rtl"] .hero-vendor.in .hv-lume { animation-name: hvLumeRtl; }

/* the box lifts a little as the light crosses it and settles - the
   mark arrives on the horizon rather than switching on over it */
@keyframes hvSettle {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}
/* ink grows from the edge the light entered at */
@keyframes hvInk    { from { clip-path: inset(0 0 0 100%); }     to { clip-path: inset(0 0 0 0); } }
@keyframes hvInkRtl { from { clip-path: inset(0 100% 0 0); }     to { clip-path: inset(0 0 0 0); } }
/* the band is linear in the same front, so it never drifts off it */
@keyframes hvLume {
  0%   { clip-path: inset(0 -12% 0 100%); opacity: 0; }
  9%   { opacity: .88; }
  72%  { opacity: .66; }
  100% { clip-path: inset(0 88% 0 0); opacity: 0; }
}
@keyframes hvLumeRtl {
  0%   { clip-path: inset(0 100% 0 -12%); opacity: 0; }
  9%   { opacity: .88; }
  72%  { opacity: .66; }
  100% { clip-path: inset(0 0 0 88%); opacity: 0; }
}
@keyframes hvBloom {
  0%   { inset-inline-end: -20%; opacity: 0; }
  13%  { opacity: 1; }
  70%  { opacity: .78; }
  100% { inset-inline-end: 80%; opacity: 0; }
}

@media (max-width: 999px) {
  /* Stacked, the panel is the last thing in the hero, so the mark is
     the hero's last line, and there are about 90px under the panel to
     put it in. 0.46 is what leaves a margin in that 90 for the tallest
     mark as well as the widest: measured at 390, Cisco clears the
     hero's bottom edge by 16px and Fortinet by 21, in both languages.
     At 0.58 Cisco cleared by four pixels, which is not a margin. */
  .hero-vendor {
    --hv-rest: .26;
    /* Capped to the column as on the desktop, so a wide lockup is not
       cut by the edge of a phone: Fortinet's 8.6:1 wants 444px at this
       scale and the screen has 358, so min() takes it and the aspect
       ratio brings the height down with it. Cisco's 1.9:1 is 108 wide
       here, well inside, so it keeps the size this scale was chosen
       for and still clears the hero's bottom edge. */
    width: min(100%, calc(var(--vw) * .46px));
    height: auto;
    inset-block-start: calc(100% + 14px);
  }
}

/* Reduced motion, by either route, gets the resting state - the whole
   design minus the arrival. The reveal engine adds .in immediately in
   that case, so the animations have to be named off rather than waited
   out, and the mark has to be told its finished clip rather than its
   opening one.

   The accessibility panel's pause button is the same problem by
   another route: .a11y-nomotion * { animation: none !important } stops
   the arrival, and with the arrival stopped the mark's own default is
   a clip closed to nothing. Named to the resting state here as well,
   above the [dir] rules. The panel writes both the class and
   data-motion="off"; either is enough to match. */
.a11y-nomotion .hero-vendor.reveal,
[data-motion="off"] .hero-vendor.reveal { opacity: 1; transform: none; }
.a11y-nomotion .hero-vendor .hv-mark,
[data-motion="off"] .hero-vendor .hv-mark { clip-path: none; opacity: var(--hv-rest); }
.a11y-nomotion .hero-vendor .hv-lume,
.a11y-nomotion .hero-vendor .hv-bloom,
[data-motion="off"] .hero-vendor .hv-lume,
[data-motion="off"] .hero-vendor .hv-bloom { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  /* Every selector here carries an extra class on purpose. The two
     [dir="rtl"] rules above are a class heavier than the rules they
     override, and specificity beats source order, so the plain
     versions of these lost to them: the animation was named off but
     animation-name came back as hvInkRtl, the clip stayed shut at
     inset(0 100% 0 0), and a reader who asks for no motion got no
     mark at all rather than the resting state. */
  .hero-vendor.reveal, .hero-vendor.reveal.in { opacity: 1; transform: none; }
  .hero-vendor.reveal.in,
  .hero-vendor.reveal.in .hv-mark,
  .hero-vendor.reveal.in .hv-lume,
  .hero-vendor.reveal.in .hv-bloom { animation: none; }
  .hero-vendor .hv-mark { clip-path: none; opacity: var(--hv-rest); }
  .hero-vendor .hv-lume, .hero-vendor .hv-bloom { opacity: 0; }
}


/* ============================================================
   The Courses menu, two levels deep

   Each topic carries a caret that unfolds the courses under it, so a
   course page is reachable from the header rather than only from the
   catalogue. The fold is the same grid-template-rows move the drawer
   already uses, which animates a height nobody has to measure.
   ============================================================ */
.subnav { min-width: 296px; }
.subnav-item { list-style: none; }
.subnav-head { display: flex; align-items: center; gap: 2px; }
.subnav-head > a { flex: 1; min-width: 0; }
.subnav-toggle {
  flex: none;
  display: grid;
  place-items: center;
  width: 30px; height: 30px;
  border-radius: 8px;
  color: #6B6B75;
  transition: background .2s, color .2s, transform .35s var(--ease-leo);
}
.subnav-toggle:hover { background: rgba(243,112,33,0.10); color: #C2570E; }
.subnav-toggle svg { transition: transform .35s var(--ease-leo); }
.subnav-item.open .subnav-toggle svg { transform: rotate(180deg); }

.subnav-courses {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .42s var(--ease-leo);
}
.subnav-item.open .subnav-courses { grid-template-rows: 1fr; }
/* The height folds away and the links have to go with it. Without
   this the twelve course links keep visibility:visible inside a
   zero-height box: Tab walks straight into them, Enter follows one,
   and nothing is on screen to say where the focus went. The outer
   fold got this right (.drawer-subs > div, above); these two did not.
   The transition matches the height's, so the links stay visible
   through the close and go hidden at the end of it. */
.subnav-courses > div { overflow: hidden; visibility: hidden; transition: visibility .42s; }
.subnav-item.open .subnav-courses > div { visibility: visible; }
.subnav-courses a {
  padding: 7px 13px;
  padding-inline-start: 26px;
  font-size: 13.5px;
  color: #55555F;
  position: relative;
}
/* a hairline down the group, so the courses read as belonging to the
   topic above them rather than as five more topics */
.subnav-courses a::before {
  content: "";
  position: absolute;
  inset-inline-start: 15px;
  top: 0; bottom: 0;
  width: 1px;
  background: rgba(0,0,0,0.10);
}
.subnav-courses a:hover { color: #C2570E; }
.subnav-all { margin-top: 4px; padding-top: 4px; border-top: 1px solid rgba(0,0,0,0.07); }

/* ---- the same two levels in the drawer ---- */
.mobile-drawer .drawer-topic .drawer-head { gap: 2px; }
.mobile-drawer .topic-toggle {
  flex: none;
  display: grid;
  place-items: center;
  min-width: 46px; min-height: 46px;
  border-radius: 10px;
  color: #6B6B75;
  transition: background .2s, color .2s;
}
.mobile-drawer .topic-toggle:hover { background: rgba(243,112,33,0.10); color: #C2570E; }
.mobile-drawer .topic-toggle svg { transition: transform .35s var(--ease-leo); }
.mobile-drawer .drawer-topic.open .topic-toggle svg { transform: rotate(180deg); }
.mobile-drawer .drawer-courses {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .42s var(--ease-leo);
}
.mobile-drawer .drawer-topic.open .drawer-courses { grid-template-rows: 1fr; }
.mobile-drawer .drawer-courses > div { overflow: hidden; visibility: hidden; transition: visibility .42s; }
.mobile-drawer .drawer-topic.open .drawer-courses > div { visibility: visible; }
/* The drawer panel is white, and --text-3 is a colour for the dark
   surfaces - white at 55%. These links were being painted white on
   white: laid out, tappable, and invisible, which reads as a menu that
   opens onto nothing. They take the drawer's own ink, one step back
   from the topic above them, and a hairline that can be seen. */
.mobile-drawer .drawer-courses a {
  display: block;
  padding: 10px 0;
  padding-inline-start: 18px;
  font-size: 15px;
  color: rgba(10,10,14,0.62);
  border-inline-start: 1px solid rgba(10,10,14,0.14);
  margin-inline-start: 6px;
}
.mobile-drawer .drawer-courses a:hover { color: #C2570E; }
@media (prefers-reduced-motion: reduce) {
  .subnav-courses, .mobile-drawer .drawer-courses,
  .subnav-toggle svg, .mobile-drawer .topic-toggle svg { transition: none; }
}


/* ============================================================
   The photographs

   A row of them, staggered - every second one sits lower, which is
   what stops four portraits in a line from reading as a contact
   sheet. Each arrives on its own beat: the clip opens upward with a
   delay taken from its index, so the row assembles left to right
   rather than appearing at once.

   On approach the photograph warms and grows a little inside its
   frame, a light rises from its lower edge, and the corner glyph
   says what pressing it does. Nothing is written under any of them.
   ============================================================ */
/* the container wears .reveal only so the engine stamps .in on it when
   it comes into view - the photographs are what animates, not the box */
.shots.reveal { opacity: 1; transform: none; transition: none; }
.shots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 20px;
  margin-top: 56px;
  align-items: start;
}
.shot {
  position: relative;
  display: block;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--card);
  cursor: zoom-in;
  /* the arrival: clipped from the foot, on this photograph's own beat */
  clip-path: inset(0 0 100% 0);
  opacity: 0;
  transform: translateY(26px);
  transition:
    clip-path 1.05s var(--ease-leo) calc(var(--i, 0) * 110ms),
    opacity .7s var(--ease-leo) calc(var(--i, 0) * 110ms),
    transform 1.05s var(--ease-leo) calc(var(--i, 0) * 110ms),
    border-color .55s var(--ease-leo),
    box-shadow .55s var(--ease-leo);
}
.shots.in .shot {
  clip-path: inset(0 0 0 0);
  opacity: 1;
  transform: translateY(0);
}
/* the rhythm: the second of each pair hangs lower */
.shots.in .shot:nth-child(even) { transform: translateY(46px); }

.shot img {
  display: block;
  width: 100%;
  /* the markup carries width and height so the grid holds its shape
     before the file arrives - and those are presentational hints, so
     without height:auto the height attribute wins and aspect-ratio is
     ignored: a 1600px tall cell in a 380px slot */
  height: auto;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  filter: saturate(.88) brightness(.9);
  transition: transform 1.1s var(--ease-leo), filter .6s var(--ease-leo);
}
/* the light that rises off the lower edge on approach */
.shot-glow {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  height: 55%;
  background: linear-gradient(to top, rgba(243,112,33,0.30), rgba(243,112,33,0.06) 42%, transparent 78%);
  opacity: 0;
  transition: opacity .55s var(--ease-leo);
  pointer-events: none;
}
/* the corner glyph - four arrows opening outward */
.shot-open {
  position: absolute;
  inset-block-start: 14px;
  inset-inline-end: 14px;
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  border-radius: 12px;
  background: rgba(10,9,8,0.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: #fff;
  opacity: 0;
  transform: translateY(-6px) scale(.92);
  transition: opacity .45s var(--ease-leo), transform .45s var(--ease-leo);
  pointer-events: none;
}
.shot-open svg { width: 17px; height: 17px; }

.shot:hover, .shot:focus-visible {
  border-color: rgba(243,112,33,0.42);
  box-shadow: 0 26px 60px -28px rgba(243,112,33,0.5);
}
.shot:hover img, .shot:focus-visible img { transform: scale(1.06); filter: none; }
.shot:hover .shot-glow, .shot:focus-visible .shot-glow { opacity: 1; }
.shot:hover .shot-open, .shot:focus-visible .shot-open { opacity: 1; transform: none; }
.shot:focus-visible { outline-offset: 3px; }

@media (max-width: 620px) {
  .shots { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .shots.in .shot:nth-child(even) { transform: translateY(26px); }
  .shot-open { width: 32px; height: 32px; inset-block-start: 10px; inset-inline-end: 10px; }
}

/* ---- the viewer ------------------------------------------------ */
.shotbox {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 12px;
  padding: clamp(16px, 5vw, 56px);
  background: rgba(6,5,4,0.94);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  opacity: 0;
  transition: opacity .4s var(--ease-leo);
}
.shotbox.open { opacity: 1; }
.shotbox-img {
  grid-column: 2;
  justify-self: center;
  max-width: 100%;
  max-height: calc(100svh - clamp(32px, 10vw, 112px));
  border-radius: var(--r-lg);
  box-shadow: 0 50px 140px -36px rgba(0,0,0,0.95);
  transform: scale(.965);
  opacity: 0;
  transition: transform .55s var(--ease-leo), opacity .4s var(--ease-leo);
}
.shotbox.open .shotbox-img { transform: none; opacity: 1; }
/* the step: the photograph leaves before the next one arrives */
.shotbox.stepping .shotbox-img { opacity: 0; transform: scale(.99); transition-duration: .18s; }
.shotbox-close, .shotbox-step {
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 50%;
  background: rgba(255,255,255,0.06);
  color: #fff;
  cursor: pointer;
  transition: background .3s, border-color .3s, transform .3s var(--ease-leo);
}
.shotbox-close:hover, .shotbox-step:hover {
  background: rgba(255,255,255,0.14);
  border-color: rgba(255,255,255,0.34);
  transform: scale(1.06);
}
.shotbox-close { position: absolute; inset-block-start: clamp(14px, 3vw, 26px); inset-inline-end: clamp(14px, 3vw, 26px); }
.shotbox-step.prev { grid-column: 1; }
.shotbox-step.next { grid-column: 3; }
[dir="rtl"] .shotbox-step svg { transform: scaleX(-1); }
@media (max-width: 620px) {
  .shotbox { grid-template-columns: 1fr; }
  .shotbox-img { grid-column: 1; }
  .shotbox-step { position: absolute; inset-block-end: calc(20px + env(safe-area-inset-bottom, 0px)); }
  .shotbox-step.prev { inset-inline-start: 22%; }
  .shotbox-step.next { inset-inline-end: 22%; }
}
@media (prefers-reduced-motion: reduce) {
  .shot, .shot img, .shot-glow, .shot-open, .shotbox, .shotbox-img, .shotbox-step { transition: none; }
  .shot { clip-path: none; opacity: 1; transform: none; }
  .shots.in .shot:nth-child(even) { transform: none; }
}

/* ============================================================
   A film with a play button

   The bands elsewhere are muted loops that start themselves; this one
   has sound, so it starts when it is asked to and not before. The
   button covers the poster until the first play and then gets out of
   the way - the browser's own controls take over, which is what a
   reader reaches for to pause or seek.
   ============================================================ */
.film { margin: 48px 0 0; }
.film-frame {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line);
  background: #000;
}
.film-media { display: block; width: 100%; height: auto; }
.film-play {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border: 0;
  background: radial-gradient(ellipse 60% 60% at 50% 50%, rgba(0,0,0,0.30), rgba(0,0,0,0.10) 70%, transparent);
  cursor: pointer;
  transition: opacity .3s var(--ease-leo);
}
.film-play::before {
  content: "";
  position: absolute;
  width: 84px; height: 84px;
  border-radius: 50%;
  background: var(--orange);
  box-shadow: 0 18px 50px -12px rgba(243,112,33,0.65);
  transition: transform .45s var(--ease-leo);
}
.film-play svg {
  position: relative;
  width: 30px; height: 30px;
  color: #1A0F06;
  margin-inline-start: 4px;
}
[dir="rtl"] .film-play svg { transform: scaleX(-1); margin-inline-start: 0; margin-inline-end: 4px; }
.film-play:hover::before { transform: scale(1.07); }
.film-play:focus-visible { outline-offset: -4px; }
.film-frame.playing .film-play { opacity: 0; pointer-events: none; }
.film figcaption {
  margin-top: 16px;
  color: var(--text-3);
  font-size: 14.5px;
  line-height: 1.7;
}
@media (max-width: 700px) {
  .film-play::before { width: 66px; height: 66px; }
  .film-play svg { width: 24px; height: 24px; }
}
@media (prefers-reduced-motion: reduce) {
  .film-play, .film-play::before { transition: none; }
}

/* ============================================================
   Whether a course is open

   One chip, on the card and in the dock, and one row at the head of
   the facts panel. The dot is the whole difference: warm and lit on
   a course taking registrations now, quiet grey on one that is
   planned. The lit dot breathes once every few seconds, and holds
   still for a reader who asked for less movement.

   It sits in the flow, above the course name, rather than in the
   corner beside the level pill - two pills in one corner is how a
   card ends up with a corner that wraps at 390px in English.
   ============================================================ */
.cc-status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: .02em;
  line-height: 1.2;
  color: var(--text-3);
}
.cc-status i {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: currentColor;
  opacity: .6;
}
.cc-status.is-open { color: var(--orange-bright); }
.cc-status.is-open i {
  opacity: 1;
  animation: statusPulse 2.8s var(--ease-leo) infinite;
}
@keyframes statusPulse {
  0%   { box-shadow: 0 0 0 0 rgba(243,112,33,0.5); }
  70%  { box-shadow: 0 0 0 7px rgba(243,112,33,0); }
  100% { box-shadow: 0 0 0 0 rgba(243,112,33,0); }
}
@media (prefers-reduced-motion: reduce) { .cc-status.is-open i { animation: none; } }

.course-card .cc-status { margin-top: -2px; }
/* the same fact at the head of the facts panel, where the value is
   the only orange thing in the column */
.course-facts .cf-open dd { color: var(--orange-bright); }
/* in the sticky card beside the syllabus; the phone bar has 90px for
   the course name as it is, so it does not carry this */
.enq-dock .dock-status { margin-top: -6px; }
@media (max-width: 999px) { .enq-dock .dock-status { display: none; } }

/* the cohort select, in the registration form and nowhere else - it
   is the first thing asked after who the registration is for */
.enq-cohort { margin-bottom: 2px; }

/* The extra filter groups, and the control that reveals them.

   Above 760px every group is simply out, as it always was, and the
   control is not rendered at all. Below it the bar carries the one
   filter people came for - what is open - and the other four wait
   behind a button, which takes the bar from 666px to about 150px on
   a 390px screen. */
.cat-more { display: none; }
/* The wrapper is not a box: above 760px the four groups are direct
   children of the bar exactly as they were before it existed. It has
   to outrank `.cat-filters > div`, which sets the groups' own flex and
   matches this div too - at equal specificity that rule wins on order
   and the bar gains a wrapping row nobody asked for. */
.cat-filters > .cat-rest { display: contents; }
@media (max-width: 760px) {
  .cat-more {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    align-self: start;
    min-height: 44px;
    padding: 10px 18px;
    border-radius: var(--r-pill);
    border: 1px solid var(--line);
    background: transparent;
    font-family: var(--font-display);
    font-size: 14px;
    color: var(--text-2);
  }
  /* physical edges, not logical ones: the borders would flip with the
     direction while the rotation below would not, and the caret came
     out pointing down in English and sideways in Hebrew */
  .cat-more::after {
    content: "";
    width: 7px; height: 7px;
    border-right: 1.6px solid currentColor;
    border-bottom: 1.6px solid currentColor;
    transform: rotate(45deg) translate(-1px, -1px);
    transition: transform .3s var(--ease-leo);
  }
  .cat-more[aria-expanded="true"] { color: var(--text-1); border-color: rgba(255,255,255,0.28); }
  .cat-more[aria-expanded="true"]::after { transform: rotate(-135deg) translate(-2px, -2px); }
  .cat-filters .cat-rest { display: none; }
  .cat-filters.more .cat-rest { display: contents; }
}

/* the line above the catalogue filters that says how registration
   works here - one sentence, set like a caption rather than a lede */
.cat-note {
  max-width: 68ch;
  margin: 0 0 26px;
  color: var(--text-3);
  font-size: 15px;
  line-height: 1.75;
}
