/* ==========================================================================
   Mārketinga Skola — design system v5 "ledger" (dark-first, Aug 2026)
   ONE canvas: #020d1c everywhere — the background never changes color.
   Cards are #00152c + a mandatory 1px hairline; depth = hairlines, never
   shadows. Three text tiers only (#fff / #c9d8e8 / #8ba3bd — the floor).
   Cyan #03c3f8 is a SIGNAL with a fixed budget: primary CTA (one per
   viewport), eyebrow index + tick, stat suffixes + at most one numeral per
   page (the price on course pages), links + active nav, focus rings, the
   featured panel's 2px top bar. Never as heading color, background wash,
   border-at-rest, or icon tinting. OWNER RULES: no gradients, ever; no
   white backgrounds; generous scale — do not shave section padding.
   ========================================================================== */

:root {
  --canvas: #020d1c;
  --card: #00152c;
  --card2: #051e35;
  --line: rgba(255, 255, 255, 0.08);
  --line-strong: rgba(255, 255, 255, 0.16);
  --line-hover: rgba(255, 255, 255, 0.28);
  --cyan: #03c3f8;
  --navy-ink: #00152c;  /* ink for the cyan topbar - 8.9:1 on #03c3f8 */
  --topbar-h: 32px;     /* the header sticks below this; keep them in sync */
  --cyan-hover: #45d4fa;
  --link: #03c3f8;        /* interactive text — flips on .paper */
  --tick: #03c3f8;        /* checkmarks / small accent glyphs */
  --heading: #ffffff;
  --body: #c9d8e8;
  --muted: #8ba3bd;
  --well: #051e35;         /* inset fill: inputs, hover wells */
  /* The one lighter surface, for banded sections. 1.29:1 against the canvas:
     --card (1.06) and --well (1.15) were measured as invisible across a full
     section, which is what made an earlier attempt at this read as nothing. */
  --band: #0e2743;
  --warn: #ff9b9b;         /* validation only - never decorative */
  /* --- type scale (tools/apply-type-scale.mjs) --- */
  --t-micro: 0.75rem;   /* 12-12px · uppercase tracked micro-labels ONLY */
  --t-sm: 0.875rem;   /* 14-14px · fine print, meta, nav, badges, compact UI */
  --t-base: 1rem;   /* 16-16px · component body text, inputs, buttons */
  --t-body: clamp(1rem, 0.94rem + 0.28vw, 1.125rem);   /* 16-18px · page and article reading text */
  --t-lead: clamp(1.125rem, 1.04rem + 0.35vw, 1.375rem);   /* 18-22px · leads, hero subs, blockquotes */
  --t-d1: clamp(1.25rem, 1.1rem + 0.62vw, 1.75rem);   /* 20-28px · h3, card and module titles */
  --t-d2: clamp(1.5rem, 1.27rem + 0.95vw, 2.25rem);   /* 24-36px · article, course and prose h2 */
  --t-d3: clamp(1.875rem, 1.5rem + 1.55vw, 3rem);   /* 30-48px · section h2, cta band, stat numerals */
  --t-d4: clamp(2.25rem, 1.72rem + 2.15vw, 3.75rem);   /* 36-60px · inner page hero h1 */
  --t-d5: clamp(2.75rem, 1.97rem + 3.2vw, 5rem);   /* 44-80px · home hero h1 */
  /* --- end type scale --- */
  --radius: 0;          /* SQUARE. The system is a ledger: hairline grids,
                             indexed eyebrows, corner ticks. Rounded corners
                             fought that, and seven different radii were in use. */
  --radius-btn: 0;
  --container: 1200px;
  --pad-x: clamp(20px, 4vw, 48px);
  --sec-pad: clamp(6rem, 10vw, 10rem);
  --card-pad: clamp(28px, 2vw + 16px, 40px);
  --font-display: 'Space Grotesk', 'Inter', system-ui, sans-serif;
  --font-body: 'Inter', system-ui, -apple-system, sans-serif;
  /* Motion vocabulary (9 Oct 2026). A spring that overshoots and settles is
     what makes a hover feel physical instead of a colour swap. Hover and focus
     use these at fixed, short durations - never multiplied by --motion,
     because slowed feedback reads as lag. */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --lift: 6px;          /* how far a clickable card rises off the grid */
}

/* ---------- base ---------- */
* { box-sizing: border-box; }
/* The hidden attribute must beat any display rule. Without this, .consent { display:grid }
   outranked the UA's [hidden]{display:none} and the cookie card never closed. */
[hidden] { display: none !important; }
html { scroll-behavior: smooth; background: var(--canvas); }
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.65;
  color: var(--body);
  background: var(--canvas);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img { max-width: 100%; height: auto; }
a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }
::selection { background: rgba(3, 195, 248, 0.35); color: #fff; }
:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; border-radius: 0; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--heading);
  margin: 0 0 0.5em;
  text-wrap: balance;
}
h1 { font-size: var(--t-d5); line-height: 1.03; letter-spacing: -0.03em; }
h2 { font-size: var(--t-d3); line-height: 1.08; letter-spacing: -0.02em; }
h3 { font-size: var(--t-d1); line-height: 1.25; letter-spacing: -0.01em; }
h4 { font-size: var(--t-d1); line-height: 1.3; }
h5 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 2.2em 0 1em;
}
p { margin: 0 0 1.15em; }
.lead { font-size: var(--t-lead); line-height: 1.55; color: var(--body); max-width: 56ch; }
.accent-text, .grad-text { color: var(--cyan); }

.container { max-width: var(--container); margin: 0 auto; padding: 0 var(--pad-x); }
.container--narrow { max-width: 820px; }
.center { text-align: center; }
.col:empty { display: none; }
/* Sticky chrome is the strip plus the header, so a linked heading has to clear
   both or it lands underneath them. */
[id] { scroll-margin-top: calc(var(--topbar-h) + 88px); }

/* ---------- topbar ---------- */
/* CYAN STRIP, owner's call (7 Sep 2026): "cyan background, dark navy
   typography... make them always visible". This is the second deliberate
   exception to the cyan budget, after the WhatsApp float — the phone number
   and the address are the two things a service buyer looks for first, so they
   get the one loud surface on the site and they never scroll away.
   Navy #00152c on cyan #03c3f8 measures 8.9:1, comfortably past WCAG AAA;
   never lighten the ink toward --muted here, that tier is for the dark canvas
   and would fail on this ground. The strip sticks and the header sticks below
   it, so --topbar-h has to match the real height at every width. */
.topbar { background: var(--cyan); color: var(--navy-ink); font-size: var(--t-sm); position: sticky; top: 0; z-index: 60; }
.topbar-inner { display: flex; justify-content: space-between; align-items: center; min-height: var(--topbar-h); gap: 16px; }
.topbar a { color: var(--navy-ink); font-weight: 500; display: inline-flex; align-items: center; gap: 7px; transition: color .16s ease, background-color .16s ease; }
.topbar a:hover { color: var(--navy-ink); text-decoration: none; }
.topbar-contacts { display: flex; align-items: center; gap: 18px; }
.topbar-contacts a { position: relative; letter-spacing: .01em; white-space: nowrap; }
/* the contact strip earns its own hairline on hover rather than an underline */
.topbar-contacts a::after { content: ""; position: absolute; left: 0; right: 0; bottom: -3px; height: 1px; background: var(--navy-ink); transform: scaleX(0); transform-origin: left; transition: transform .22s cubic-bezier(.2,.7,.3,1); }
.topbar-contacts a:hover::after { transform: scaleX(1); }
/* a navy hairline between the two contacts, the ledger's own separator */
.topbar-contacts a + a { padding-left: 18px; }
.topbar-contacts a + a::before { content: ""; position: absolute; left: 0; top: 50%; height: 13px; width: 1px; margin-top: -6px; background: rgba(0, 21, 44, .28); }
/* social marks invert the strip on hover: navy square, cyan glyph */
.topbar-social { display: flex; gap: 4px; align-items: center; }
.topbar-social a { width: 26px; height: 26px; justify-content: center; }
.topbar-social a:hover { background: var(--navy-ink); color: var(--cyan); }

/* ---------- header ---------- */
.header {
  background: rgba(2, 13, 28, 0.88);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  position: sticky;
  top: var(--topbar-h);
  z-index: 50;
  border-bottom: 1px solid var(--line);
}
.header-inner { display: flex; align-items: center; justify-content: space-between; min-height: 76px; gap: 24px; }
.brand { display: inline-flex; align-items: center; flex-shrink: 0; }
.brand img { display: block; width: 148px; height: auto; transition: transform 0.4s var(--ease-spring); }
/* The logo is a rocket, so it lifts off a little. Full opacity: fading the
   logo was the one hover on the site that made something LESS visible. */
.brand:hover img { transform: translate(2px, -3px) rotate(-3deg); }
@media (max-width: 1020px) { .brand img { width: 132px; } }

.nav ul { list-style: none; margin: 0; padding: 0; display: flex; align-items: center; gap: 6px; }
.nav > ul > li { position: relative; }
.nav a {
  display: block;
  padding: 10px 12px;
  font-weight: 500;
  font-size: var(--t-sm);
  color: var(--body);
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.15s ease;
}
/* Hover and active share ONE mark: a 2px cyan rule that wipes in from the left.
   It replaces the old inset box-shadow, which appeared instantly and read as a
   different device from everything else on the page. transform only, so it
   stays on the compositor. */
.nav > ul > li > a { position: relative; }
.nav > ul > li > a::before {
  content: "";
  position: absolute;
  left: 12px; right: 12px; bottom: 3px;
  height: 3px;
  background: var(--cyan);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.36s var(--ease-spring);
}
.nav > ul > li > a:hover::before,
.nav > ul > li:focus-within > a::before { transform: scaleX(1); }
.nav > ul > li > a:hover { color: #fff; text-decoration: none; }
.nav > ul > li.active > a { color: #fff; }
.nav > ul > li.active > a::before { transform: scaleX(1); }
.nav li.has-children > a::after {
  content: "";
  display: inline-block;
  margin-left: 7px;
  width: 6px; height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translateY(-3px);
  opacity: 0.5;
  transition: transform 0.22s cubic-bezier(0.2, 0.7, 0.3, 1), opacity 0.18s ease;
}
.nav li.has-children:hover > a::after,
.nav li.has-children:focus-within > a::after,
.nav li.has-children.open > a::after {
  transform: rotate(-135deg) translateY(-3px) translateX(-3px);
  opacity: 0.9;
}
/* Scoped to .nav for the same reason as the mobile rule below: the dropdown
   is a <ul>, and .nav ul (0,1,1) outranks .dropdown (0,1,0). */
.nav .dropdown {
  position: absolute;
  top: calc(100% + 10px); left: 0;
  min-width: 268px;
  background: var(--card2);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: 8px;
  display: flex;
  flex-direction: column;
  /* display: none cannot animate. visibility keeps the links out of the tab
     order while hidden, which opacity alone would not. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 0.18s ease, transform 0.2s cubic-bezier(0.2, 0.7, 0.3, 1), visibility 0.2s;
}
.dropdown::before { content: ""; position: absolute; top: -14px; left: 0; right: 0; height: 14px; }
.nav li.has-children:hover > .dropdown,
.nav li.has-children:focus-within > .dropdown,
.nav li.has-children.open > .dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
/* each row settles a beat after the panel, left to right */
.dropdown li { opacity: 0; transform: translateX(-6px); transition: opacity 0.2s ease, transform 0.24s cubic-bezier(0.2, 0.7, 0.3, 1); }
.nav li.has-children:hover > .dropdown li,
.nav li.has-children:focus-within > .dropdown li,
.nav li.has-children.open > .dropdown li { opacity: 1; transform: translateX(0); }
.dropdown li:nth-child(2) { transition-delay: 0.03s; }
.dropdown li:nth-child(3) { transition-delay: 0.06s; }
.dropdown li:nth-child(4) { transition-delay: 0.09s; }
.dropdown li:nth-child(5) { transition-delay: 0.12s; }
.dropdown li { width: 100%; }
.dropdown a { padding: 10px 14px; font-weight: 400; white-space: normal; border-radius: 0; color: var(--body); }
.dropdown a { position: relative; transition: color 0.16s ease, background 0.16s ease; }
.dropdown a::before {
  content: "";
  position: absolute; left: 0; top: 6px; bottom: 6px;
  width: 2px; background: var(--cyan);
  transform: scaleY(0); transform-origin: top;
  transition: transform 0.2s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.dropdown a:hover::before { transform: scaleY(1); }
.dropdown a:hover { background: rgba(255, 255, 255, 0.06); color: #fff; text-decoration: none; }

.nav-cta > a {
  background: var(--cyan);
  color: var(--canvas) !important;
  border-radius: var(--radius-btn);
  padding: 11px 22px;
  margin-left: 12px;
  font-family: var(--font-display);
  font-weight: 600;
}
.nav-cta > a:hover { background: var(--cyan-hover); color: var(--canvas); box-shadow: none; }

.nav-toggle { display: none; background: none; border: 0; cursor: pointer; padding: 10px; }
.nav-toggle span { display: block; width: 24px; height: 2px; background: #fff; margin: 6px 0; }

@media (max-width: 1020px) {
  .nav-toggle { display: block; }
  .nav { display: none; position: absolute; top: 100%; left: 0; right: 0; background: var(--canvas); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line-strong); max-height: calc(100vh - 160px); overflow: auto; }
  .nav.open { display: block; }
  .nav ul { flex-direction: column; align-items: stretch; gap: 0; padding: 12px 10px; }
  .nav a { padding: 13px 16px; white-space: normal; font-size: var(--t-sm); }
  .nav > ul > li.active > a { box-shadow: inset 2px 0 0 var(--cyan); }
  /* Scoped to .nav on purpose. The dropdown IS a <ul>, so `.nav ul` (0,1,1)
     outranks a bare `.dropdown` (0,1,0) and its `display: flex` would win —
     which is exactly why this rule used to carry !important. `.nav .dropdown`
     reaches (0,2,0) and wins on specificity instead of force. */
  .nav .dropdown {
    position: static; border: 0;
    border-left: 1px solid var(--line-strong);
    border-radius: 0; margin: 0 0 4px 16px; background: transparent; padding: 0;
    /* in normal flow the panel must not hold space while closed */
    display: none; opacity: 1; visibility: visible; transform: none; transition: none;
  }
  .nav li.has-children.open > .dropdown { display: flex; }
  .dropdown li { opacity: 1; transform: none; transition: none; }
  .nav > ul > li > a::before { display: none; }
  .nav > ul > li.active > a { box-shadow: inset 2px 0 0 var(--cyan); }
  .nav-cta > a { margin: 10px 16px; text-align: center; }
}

/* ---------- sections: one canvas, hairline rhythm ---------- */
.sec { padding: var(--sec-pad) 0; border-top: 1px solid var(--line-strong); }
main > .sec:first-child, main > section:first-child { border-top: 0; }
/* legacy section variants all sit on the same canvas — no stripes */
.sec--dark, .sec--soft { background: transparent; color: var(--body); }
.sec--hairline { border-top: 1px solid var(--line); }

/* indexed dossier eyebrow */
.eyebrow, .sec--hero h2:first-child {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  background: none;
  border: 0;
  padding: 0;
  margin: 0 0 16px;
}
.eyebrow::before { content: ""; width: 20px; height: 2px; background: var(--cyan); flex-shrink: 0; }
.eyebrow .idx {
  background: var(--cyan); color: var(--navy-ink);
  padding: 3px 6px 2px; font-weight: 600;
  font-variant-numeric: tabular-nums; letter-spacing: 0.04em;
}
.center .eyebrow::after { content: ""; width: 20px; height: 2px; background: var(--cyan); flex-shrink: 0; }

/* split section header.
   The eyebrow runs across the full width on its own row; the heading and the
   intro sit side by side under it, TOP-aligned, so both start on the same line
   and the larger heading on the left is read first. Until 9 Oct 2026 both
   columns were bottom-aligned, so whenever the intro ran longer than the
   heading it started higher and was read before it. Owner: "the body text
   reads before the headline, because it is higher."
   All 155 section headers share one shape - a <div> holding the eyebrow and
   the h2, then an optional p.lead - so that <div> steps out of the layout
   with display: contents and nothing in the markup changed. The lead drops by
   a few pixels so its first line sits on the heading's first line rather than
   above its cap height. */
.sec-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 380px);
  grid-template-areas: "eye eye" "head lead";
  gap: 0 80px;
  align-items: start;
  margin-bottom: clamp(40px, 5vw, 56px);
}
.sec-head > div:first-child { display: contents; }
.sec-head .eyebrow { grid-area: eye; }
.sec-head h2 { grid-area: head; margin-bottom: 0; max-width: 20ch; }
.sec-head .lead { grid-area: lead; margin: 0; padding-top: 0.35em; font-size: var(--t-lead); color: var(--body); }
.sec-head .eyebrow { display: flex; width: 100%; }
.sec-head .eyebrow::after { content: ""; flex: 1; height: 1px; background: var(--line); margin-left: 6px; }
.sec-head .lead a { font-weight: 500; }
@media (max-width: 900px) {
  .sec-head { grid-template-columns: 1fr; grid-template-areas: "eye" "head" "lead"; gap: 0; }
  .sec-head .lead { padding-top: 0; margin-top: 16px; }
}

/* hero — the page is the hero */
.sec--hero {
  border-top: 0;
  /* Same top padding as every other page header (.page-hero). It was
     clamp(96px, 12vw, 168px) until 14 Sep 2026 - owner: too much empty space
     above the heading. Phones keep their own value in the 980px block. */
  padding: clamp(56px, 6.5vw, 92px) 0 0;
}
.sec--hero[style*="--bg"] { background-image: var(--bg); background-size: cover; background-position: center; position: relative; }
.sec--hero[style*="--bg"]::before { content: ""; position: absolute; inset: 0; background: rgba(2, 13, 28, 0.92); }
.sec--hero > .container { position: relative; z-index: 1; }
.sec--hero h1 { margin-bottom: 0.45em; }
.sec--hero .sub { font-size: var(--t-lead); line-height: 1.55; color: var(--body); max-width: 56ch; margin: 0; }

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
  gap: clamp(40px, 5vw, 88px);
  align-items: center;
}
@media (max-width: 980px) { .hero-grid { grid-template-columns: 1fr; } }
/* The homepage hero carries artwork in its right column like every other page
   header (14 Sep 2026). Scoped with :has so any other .hero-grid keeps its old
   columns. The proof numbers that used to fill that column run as one ledger
   row below the headline instead. */
/* Desktop only, and it has to be: :has() adds its argument's specificity, so
   outside a min-width query this beat the 980px one-column rule. And a 460px
   track with nothing in it still takes free space BEFORE a 1fr track gets any,
   so on phones the copy column collapsed to a sliver and the hero ran 1 200px
   tall. Same grid trap as the article column's empty rail. */
@media (min-width: 981px) { .hero-grid:has(> .hero-media) { grid-template-columns: minmax(0, 1fr) minmax(0, 460px); } }
.hero-stats { margin-top: clamp(44px, 5vw, 72px); }

/* the evidence panel — the featured card */
.panel {
  background: var(--card);
  border: 1px solid var(--line);
  border-top: 2px solid var(--cyan);
  border-radius: var(--radius);
  padding: var(--card-pad);
  position: relative;
}
.panel::before, .panel::after {
  content: "";
  position: absolute;
  width: 12px; height: 12px;
  border: 0 solid var(--cyan);
}
.panel::before { top: -2px; left: -1px; border-left-width: 2px; border-top-width: 2px; }
.panel::after { bottom: -1px; right: -1px; border-right-width: 2px; border-bottom-width: 2px; }
/* plain variant — same card, no cyan featuring (max one featured panel per page) */
.panel--plain { border-top: 1px solid var(--line); }
.panel--plain::before, .panel--plain::after { display: none; }

/* ledger stats */
.stats { display: flex; flex-direction: column; margin: 0; max-width: none; gap: 0; padding: 0; border: 0; }
.stat { border-top: 1px solid var(--line); border-left: 0; padding: 20px 0 22px; }
.stat:first-child { border-top: 0; padding-top: 0; }
/* ONE rank below a section h2, deliberately (8 Sep 2026). At --t-d3 a stat
   numeral rendered at exactly the same size, weight and colour as a section
   heading, so /portfolio/ presented 12 numerals competing with 6 real headings
   and the eye had no way to tell a title from a figure. The numeral is still
   the largest thing inside its own cell by a wide margin (the label is 12px),
   so it keeps its punch without pretending to start a section. The mobile hero
   already did exactly this. */
.stat .num {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-d2);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--heading);
  font-variant-numeric: tabular-nums;
}
.stat .num .sfx { color: var(--cyan); }
.stat .label { display: block; margin-top: 8px; font-size: var(--t-micro); letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }

/* horizontal ledger row variant */
.stats--row { flex-direction: row; gap: clamp(28px, 5vw, 64px); }
.stats--row .stat { border-top: 1px solid var(--line-strong); flex: 1; padding: 18px 0 0; }
.stats--row .stat:first-child { border-top: 1px solid var(--line-strong); padding-top: 18px; }
@media (max-width: 640px) { .stats--row { flex-direction: column; gap: 0; } .stats--row .stat { padding: 16px 0; } }

/* client logo strip */
.logo-strip { border-top: 1px solid var(--line); margin-top: clamp(56px, 7vw, 88px); padding: 36px 0 40px; }
.logo-strip .caption { font-size: var(--t-micro); letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); margin: 0 0 26px; }
/* Logo strip — ONE moving row. Sources are pre-normalised by
   tools/normalize-logos.mjs to a single tone and one optical weight, so no CSS
   filters and no opacity fading are needed. The track holds the set twice and
   translates by exactly -50%, so the loop is seamless. */
.marquee {
  overflow: hidden;
  position: relative;
  /* no borders here — .logo-strip already draws the single hairline, and two
     bordered boxes read as "a strip inside a strip" */
  border: 0;
  padding: 0;
}
.marquee-track {
  display: flex;
  align-items: center;
  gap: clamp(48px, 6vw, 88px);
  width: max-content;
  animation: marquee calc(46s * var(--motion)) linear infinite;
  will-change: transform;
}
.marquee-track img {
  height: 64px;
  width: auto;
  object-fit: contain;
  display: block;
  flex: none;
  opacity: 1;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
@keyframes marquee { from { transform: translate3d(0,0,0); } to { transform: translate3d(-50%,0,0); } }
@media (max-width: 640px) { .marquee-track img { height: 52px; } .marquee-track { animation-duration: calc(34s * var(--motion)); } }
@media (prefers-reduced-motion: reduce) {
  .marquee-track { animation: none; flex-wrap: wrap; width: auto; justify-content: center; gap: 32px; }
  /* Header motion degrades to instant state changes: the underline, the caret,
     the dropdown and its rows all still WORK, they just stop moving. */
  .nav > ul > li > a::before,
  .dropdown, .dropdown li, .dropdown a::before,
  .nav li.has-children > a::after,
  .topbar-contacts a::after,
  .brand img { transition: none !important; }
}

/* legacy marquee (unused on new pages, kept for compatibility) */
.marquee { overflow: hidden; }
.marquee-track { display: flex; align-items: center; gap: clamp(44px, 6vw, 80px); width: max-content; animation: marquee calc(36s * var(--motion)) linear infinite; padding: 6px 0; }
.marquee-track img, .logo-row img { max-height: 44px; width: auto; display: block; margin: 0 auto; }
@keyframes marquee { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .marquee-track { animation: none; flex-wrap: wrap; width: auto; justify-content: center; } }
.marquee-label { font-size: var(--t-micro); letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); margin: 0 0 22px; }

/* rows / columns (legacy generated grid) */
.row { display: grid; gap: clamp(24px, 3vw, 44px); align-items: center; margin: 0 0 clamp(28px, 3.5vw, 48px); }
.row:last-child { margin-bottom: 0; }
.cols-1 { grid-template-columns: 1fr; }
.cols-2 { grid-template-columns: 1fr 1fr; }
.row--form { grid-template-columns: 1.5fr 1fr; }
.cols-3 { grid-template-columns: repeat(3, 1fr); }
.cols-4 { grid-template-columns: repeat(4, 1fr); }
.cols-5 { grid-template-columns: repeat(5, 1fr); }
.cols-6 { grid-template-columns: repeat(6, 1fr); }
.row.top { align-items: stretch; }
@media (max-width: 980px) {
  .cols-3, .cols-4 { grid-template-columns: 1fr 1fr; }
  .cols-5, .cols-6 { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 640px) {
  .cols-2, .cols-3, .cols-4 { grid-template-columns: 1fr; }
  .cols-5, .cols-6 { grid-template-columns: 1fr 1fr; }
}

.divider { width: 44px; height: 2px; background: var(--cyan); border: 0; margin: 18px 0 26px; }
.center .divider, .col.center .divider { margin-left: auto; margin-right: auto; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: var(--cyan);
  color: var(--canvas) !important;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-base);
  letter-spacing: 0.01em;
  padding: 15px 30px;
  border: 0;
  border-radius: var(--radius-btn);
  cursor: pointer;
  text-decoration: none !important;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease,
    transform 0.3s var(--ease-spring), box-shadow 0.3s var(--ease-spring);
}
/* The button lifts off the page onto a hard white block: no blur, no glow,
   just a second square offset behind it. Pressing it puts it back down. */
.btn:hover { background: var(--cyan-hover); transform: translate(-3px, -3px); box-shadow: 3px 3px 0 #fff; }
.btn:active { background: #02b1e4; transform: none; box-shadow: 0 0 0 #fff; transition-duration: 0.08s; }
/* The ghost button does not lift - it is the secondary action and the lift
   belongs to the primary. It floods cyan from the left instead. */
.btn--ghost {
  position: relative;
  z-index: 0;
  overflow: hidden;
  background: transparent !important;
  border: 1px solid rgba(255, 255, 255, 0.32);
  color: #fff !important;
}
.btn--ghost::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--cyan);
  transform: scaleX(0); transform-origin: left;
  transition: transform 0.34s var(--ease-out);
}
.btn--ghost:hover { border-color: var(--cyan); color: var(--navy-ink) !important; transform: none; box-shadow: none; }
.btn--ghost:hover::before { transform: scaleX(1); }
.btn--sm { padding: 10px 20px; font-size: var(--t-sm); }
.btn-wrap { margin: clamp(32px, 4vw, 44px) 0 0; display: flex; gap: 16px; flex-wrap: wrap; }
/* one muted line under a button row: what the click costs (the free call) */
.fine.btn-note { margin-top: 14px; }
/* one sentence of proof under a grid: a published result, linked to its case */
.proof-line { margin: clamp(24px, 3vw, 36px) 0 0; max-width: 68ch; color: var(--muted); }
.center .btn-wrap, .btn-wrap.center { justify-content: center; }
.btn svg { flex-shrink: 0; }

.arrow-link { font-family: var(--font-display); font-weight: 500; font-size: var(--t-sm); color: #fff; white-space: nowrap; }
.arrow-link::after { content: " →"; display: inline-block; transition: transform 0.15s ease; }
.arrow-link:hover { text-decoration: none; color: #fff; }
.arrow-link:hover::after { transform: translateX(4px); }

/* ==========================================================================
   v7 "ALIVE" (9 Oct 2026). Owner: "make the design interactive, cool and a bit
   funky while retaining professionalism and the color scheme... play with the
   cyan accent, make bold underlines, cool animations"; then "we don't have to
   go as far as impromotion, but make this one at least somewhat fun."

   The palette, the square geometry and the ledger devices all stay. What
   changes is how things RESPOND. Three older rules are relaxed here, on
   purpose and only as far as written:
   - depth from box-shadow: HARD offsets only (no blur, no spread, no glow),
     and only on something being hovered or pressed;
   - translate on hover: buttons and clickable cards lift;
   - the cyan budget: cyan may be a surface where it marks an action - a
     lifted card's block, a link flooding on hover, a ghost button filling.
   A tilted cyan service ticker was tried the same day and removed. Owner:
   "this doesnt fit the theme at all" - it was Impromotion's vocabulary, not
   this site's. Nothing here is tilted or moves on its own.
   Body text, headings at rest and backgrounds never turn cyan.

   A note on `linear-gradient(var(--cyan), var(--cyan))` below: it is ONE
   colour, a flat fill. It is the only way to give an inline element a bar
   whose width can animate without extra markup. The no-gradients rule is
   about colour ramps, and none of these is one.
   ========================================================================== */

/* --- clickable cards lift off the grid -------------------------------------
   ONLY cards that are links: a lift says "you can press this", and on a cell
   that leads nowhere it would be a lie. The individual `translate` property,
   not `transform`, because .reveal animates transform on the same element and
   the two would fight. */
.cell:has(> .arrow-link):hover,
.cell:has(> .arrow-link):focus-within,
.course-tile:has(.arrow-link):hover,
.course-tile:has(.arrow-link):focus-within,
.post-card:hover,
.post-card:focus-within {
  translate: calc(var(--lift) * -1) calc(var(--lift) * -1);
  box-shadow: var(--lift) var(--lift) 0 var(--cyan);
  z-index: 2;
}
/* .reveal declares its own `transition`, which would replace the card's
   list, so revealed cards carry both in one rule that outranks it. */
.reveal:is(.cell, .course-tile, .post-card) {
  transition: opacity calc(0.5s * var(--motion)) ease, transform calc(0.5s * var(--motion)) ease,
    background 0.15s ease, border-color 0.15s ease,
    translate 0.32s var(--ease-spring), box-shadow 0.32s var(--ease-spring);
}

/* The card's own link: an arrow that runs forward and a bold cyan bar that
   draws under the label. In a card the link's ::after is the stretched
   overlay, so both are background layers instead of pseudo-elements. */
.cell:has(> .arrow-link) .arrow-link,
.course-tile:has(.arrow-link) .arrow-link {
  padding: 0 1.55em 5px 0;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 12'%3E%3Cpath d='M1 6h15M11 1.5 15.5 6 11 10.5' fill='none' stroke='%2303c3f8' stroke-width='2'/%3E%3C/svg%3E"),
    linear-gradient(var(--cyan), var(--cyan));
  background-repeat: no-repeat;
  background-position: right 0.3em top calc(50% - 2px), 0 100%;
  background-size: 0.95em auto, 0 3px;
  transition: background-position 0.34s var(--ease-spring), background-size 0.34s var(--ease-out);
}
.cell:has(> .arrow-link):is(:hover, :focus-within) .arrow-link,
.course-tile:has(.arrow-link):is(:hover, :focus-within) .arrow-link {
  background-position: right 0 top calc(50% - 2px), 0 100%;
  background-size: 0.95em auto, calc(100% - 1.55em) 3px;
}

/* --- links in running text: a bold underline that floods on hover ---------
   Navy ink on the flood, never --canvas: inside .paper --canvas is white, and
   white on cyan is 2.2:1. Navy on cyan is 8.9:1 on both surfaces. */
:is(main p, main li):not(.toc li, .chip, .article-meta) > a:not(.btn, .arrow-link, .more):not(:has(img)) {
  background: linear-gradient(var(--cyan), var(--cyan)) no-repeat 0 100% / 100% 2px;
  padding: 0 2px 1px;
  margin: 0 -2px;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  transition: background-size 0.26s var(--ease-out), color 0.18s ease;
}
:is(main p, main li):not(.toc li, .chip, .article-meta) > a:not(.btn, .arrow-link, .more):not(:has(img)):is(:hover, :focus-visible) {
  background-size: 100% 100%;
  color: var(--navy-ink);
  text-decoration: none;
}

/* --- the keyword in a heading gets a bold cyan underline ------------------
   Mark it with <em> in page markup, or with `heroMark:` in front matter for a
   page hero (the `mark` filter). One word or phrase per heading, the one the
   reader should leave with. It sits low, through the descenders, like a
   marker stroke rather than a hyperlink. */
:is(h1, h2, h3) em, .hl {
  font-style: normal;
  background: linear-gradient(var(--cyan), var(--cyan)) no-repeat 0 100% / 100% 0.12em;
  padding-bottom: 0.02em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* --- kinetic headline (main.js adds .split and the spans) ----------------
   Each word rides in its own clipping box, so it rises up out of a line
   rather than fading in. The box is padded down by the descender depth so
   a ļ or j is not cut off, and pulled back by the same amount so the line
   height does not change. */
.split .w { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: 0.16em; margin-bottom: -0.16em; }
.split .wi { display: inline-block; }

/* ---------- collapsed hairline grid ---------- */
.hgrid {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.hgrid--3 { grid-template-columns: repeat(3, 1fr); }
.hgrid--2 { grid-template-columns: repeat(2, 1fr); }
.hgrid--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 980px) { .hgrid--3, .hgrid--4 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px) { .hgrid--2, .hgrid--3, .hgrid--4 { grid-template-columns: 1fr; } }
.cell {
  background: var(--cell, var(--canvas));
  padding: var(--card-pad);
  position: relative;
  display: flex;
  flex-direction: column;
  transition: background 0.15s ease, translate 0.32s var(--ease-spring), box-shadow 0.32s var(--ease-spring);
}
.cell:hover { background: var(--cell-hover, var(--card2)); }

/* Whole-card links (owner, 5 Sep 2026: "make the whole cards clickable, not
   just the links at the bottom"). This is the stretched-link pattern: the card
   stays ONE real anchor - the existing "Uzzini vairāk" - whose ::after covers
   the card, so screen readers and search engines still see a single properly
   labelled link and there is no nested-anchor markup and no JavaScript.
   Selected with :has() so no card markup changed; where :has() is missing the
   bottom link simply keeps working as before. Safe here because no card in the
   grid points at two different URLs - verified before writing this. */
.cell:has(> .arrow-link),
.course-tile:has(.arrow-link) { position: relative; }
.cell:has(> .arrow-link) .arrow-link::after,
.course-tile:has(.arrow-link) .arrow-link::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
}
.cell:has(> .arrow-link),
.course-tile:has(.arrow-link) { cursor: pointer; }
.cell .cell-idx {
  position: absolute;
  top: var(--card-pad); right: var(--card-pad);
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-micro);
  color: var(--muted);
}
.cell h3 { margin: 0 0 12px; padding-right: 40px; }
.cell p { flex: 1; margin-bottom: 0; font-size: var(--t-base); }
.cell .arrow-link, .cell blockquote a { margin-top: 20px; display: inline-block; }
.cell blockquote { border: 0; margin: 0; padding: 0; }
.cell blockquote p { margin: 0; }

/* ---------- cards (legacy .blurb + general) ---------- */
.blurb {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--card-pad);
  height: 100%;
  display: flex;
  flex-direction: column;
  transition: border-color 0.2s ease;
}
.blurb:hover { border-color: var(--line-hover); }
.blurb h3 { margin-bottom: 0.5em; }
.blurb p { flex: 1; margin-bottom: 0; font-size: var(--t-base); }
.blurb img { width: 56px; margin-bottom: 16px; }
.blurb blockquote { border: 0; margin: 18px 0 0; padding: 0; font-style: normal; flex: 0; }
.blurb blockquote p { margin: 0; }
.blurb blockquote a { font-family: var(--font-display); font-weight: 500; font-size: var(--t-sm); color: #fff; }
.blurb blockquote a::after { content: " →"; display: inline-block; transition: transform 0.15s ease; }
.blurb blockquote a:hover { text-decoration: none; }
.blurb blockquote a:hover::after { transform: translateX(4px); }

/* .card-icon: one Material Symbols icon (Sharp, filled; see _includes/icons)
   above a text card's heading (10 Oct 2026, owner: the boxed text sections
   needed something to read by). No tile behind it: on a band a tile was a
   fourth tone in one card (11 Oct 2026). Grey, never cyan - the cyan budget
   rules out mass icon tint; a clickable card's icon turns white on hover. */
.card-icon { display: block; margin-bottom: 18px; color: var(--muted); line-height: 0; }
.card-icon .icon { width: 36px; height: 36px; display: block; }
.cell:has(> .arrow-link):is(:hover, :focus-within) .card-icon { color: var(--heading); }

.testimonial {
  margin: 0;
  background: transparent;
  color: var(--body);
  border: 0;
  border-left: 1px solid var(--line-strong);
  border-radius: 0;
  padding: 6px 0 6px 32px;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.testimonial::before { content: "“"; font-family: var(--font-display); font-size: var(--t-d3); line-height: 0.5; color: var(--muted); display: block; margin-top: 12px; }
.testimonial .t-body { flex: 1; font-size: var(--t-base); line-height: 1.7; }
.testimonial .t-body em { font-style: normal; }
.testimonial footer { display: flex; flex-direction: column; }
.testimonial footer strong { color: var(--heading); font-family: var(--font-display); font-weight: 600; font-size: var(--t-base); }
.testimonial footer span { color: var(--muted); font-size: var(--t-micro); letter-spacing: 0.06em; text-transform: uppercase; margin-top: 2px; }
@media (max-width: 640px) {
  .testimonial { border-left: 0; border-top: 1px solid var(--line-strong); padding: 22px 0 0; }
}
/* Public reviews (11 Oct 2026). A second row of testimonials sits under the
   first with the same hairline columns; the rating badges are links to the
   Google and Facebook profiles, so every total can be checked at its source.
   Stars and the thumb are white, never cyan. */
p + .row.reviews { margin-top: clamp(32px, 4vw, 48px); }
.rating-row { display: flex; flex-wrap: wrap; gap: 12px; margin: 0 0 clamp(28px, 3.5vw, 48px); }
.rating-row:last-child { margin-bottom: 0; }
/* Phones get one row of public reviews: six stacked quotes ran 2 000px, and
   the badges above them link to every review anyway. */
@media (max-width: 640px) { .row.reviews + .row.reviews { display: none; } }
.rating {
  display: inline-flex; align-items: center; gap: 12px;
  padding: 12px 18px; border: 1px solid var(--line-strong);
  color: var(--body); text-decoration: none;
  transition: border-color .2s var(--ease-out);
}
.rating:hover, .rating:focus-visible { border-color: var(--heading); }
.rating-num { font-family: var(--font-display); font-weight: 600; font-size: var(--t-d1); line-height: 1; color: var(--heading); }
.rating-stars { display: inline-flex; gap: 2px; color: var(--heading); line-height: 0; }
.rating-stars .icon { width: 16px; height: 16px; }
.rating-meta { font-size: var(--t-micro); letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }

/* FAQ — collapsed hairline ledger list, not floating boxes */
.faq {
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  margin: 0;
  background: transparent;
  color: var(--body);
  overflow: hidden;
  transition: background 0.15s ease;
}
.faq:last-of-type { border-bottom: 1px solid var(--line); }
.faq[open] { background: var(--card); }
.faq summary {
  cursor: pointer;
  padding: 18px 54px 18px 22px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--t-base);
  color: var(--heading);
  list-style: none;
  position: relative;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "";
  position: absolute; right: 22px; top: 50%;
  width: 9px; height: 9px;
  border-right: 1.5px solid var(--muted);
  border-bottom: 1.5px solid var(--muted);
  transform: translateY(-70%) rotate(45deg);
  transition: transform 0.4s var(--ease-spring), border-color 0.2s ease;
}
.faq[open] summary::after { transform: translateY(-30%) rotate(225deg); border-color: var(--cyan); }
.faq summary:hover::after { border-color: var(--cyan); }
.faq[open] { box-shadow: inset 4px 0 0 var(--cyan); }
.faq > div { padding: 0 22px 20px; }

/* boxed CTA panel (generated pages) — the featured panel device */
.cta {
  background: var(--card);
  border: 1px solid var(--line);
  border-top: 2px solid var(--cyan);
  border-radius: var(--radius);
  color: var(--body);
  padding: clamp(40px, 5vw, 64px) clamp(26px, 5vw, 64px);
  text-align: center;
}
.cta h2, .cta h3 { color: var(--heading); }
.cta h3 { font-size: var(--t-d2); }
.cta p { max-width: 560px; margin-left: auto; margin-right: auto; }
.cta .btn-wrap { justify-content: center; margin-top: 30px; }

/* full-width closing band — the ONE raised band per page */
.cta-band { background: var(--card); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: clamp(72px, 9vw, 120px) 0; }

/* The process section reads as its own band, WITHOUT going white (9 Sep 2026).
   A full .paper inversion was tried first and the owner rejected it: "not
   entirely a fan of entirely white sections in the middle of the pages". This
   is the .cta-band treatment - the --card ground plus a hairline top and
   bottom - which the system already uses and which separates the section
   without changing surface. The --card step against --canvas is only 1.06:1 on
   its own; the hairlines are what actually draw the edge, so do not remove
   them thinking the fill is doing the work. */
.sec--band, .sec--alt { background: var(--band); border-top: 1px solid var(--line-strong); border-bottom: 1px solid var(--line-strong); }
.sec--band, .sec--alt { --card: #1a3a5c; --well: #1d4166; }
/* Cards in a band take the band's own surface, so the band reads as ONE
   tone divided by hairlines, not a dark grid laid on a lighter section
   (owner, 11 Oct 2026: "too much of a mix... doesn't read as professional"). */
.sec--band, .sec--alt { --cell: var(--band); --cell-hover: var(--card); }
/* Inside the band, each step gets the eyebrow's own device: a short cyan tick
   sitting on its rule. Four small marks, so the sequence reads as a sequence
   and the cyan stays far inside budget - it is the same "this starts here"
   signal the indexed eyebrows use, applied one level down. */
.sec--band .step { position: relative; }
.sec--band .step::before { content: ""; position: absolute; top: -2px; left: 0; width: 24px; height: 3px; background: var(--cyan); }
/* The numeral already carries a cyan square; two cyan marks per step is one
   too many once the tick is on the rule. */
.sec--band .step .step-num::after { display: none; }
.cta-band-inner { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 36px 72px; align-items: center; }
.cta-band h2 { font-size: var(--t-d3); margin-bottom: 0.35em; max-width: 17ch; }
.cta-band p { margin: 0; max-width: 46ch; color: var(--body); }
.cta-band .btn-wrap { margin: 0; }
@media (max-width: 900px) {
  .cta-band-inner { grid-template-columns: 1fr; }
  .cta-band .btn-wrap { margin-top: 12px; }
}

/* process steps — ledger style */
.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(32px, 4vw, 48px) clamp(24px, 3vw, 40px); }
@media (max-width: 980px) { .steps { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .steps { grid-template-columns: 1fr; } }
.step { background: none; border: 0; border-top: 1px solid var(--line-strong); border-radius: 0; padding: 22px 0 0; }
.step .step-num {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-d3);
  line-height: 1;
  color: var(--heading);
  font-variant-numeric: tabular-nums;
  display: block;
  margin-bottom: 18px;
}
.step .step-num::after { content: ""; display: inline-block; width: 7px; height: 7px; background: var(--cyan); margin-left: 8px; }
.step h3 { font-size: var(--t-d1); }
.step p { margin: 0; font-size: var(--t-base); }

.counter { padding: 8px 0; }
.counter .num {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-d3);
  letter-spacing: -0.02em;
  color: var(--heading);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

/* Video frames carry the aspect ratio of the ACTUAL file. Everything used to
   be hard-coded to 56.25% padding-top, i.e. 16:9 - but all eight case-study
   clips are 9:16 social verticals (480x854 / 1080x1920), so they were being
   letterboxed into squat black slabs a fraction of their height. */
.video-embed { position: relative; aspect-ratio: var(--ar, 16 / 9); border-radius: var(--radius); overflow: hidden; background: #000; border: 1px solid var(--line); }
.video-embed > iframe, .video-embed > video { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; object-fit: cover; background: #000; }
.video-embed--vertical { --ar: 9 / 16; }
/* Audio is not video. A Spotify episode card is a fixed 232px tall, so in the
   16:9 .video-embed box the rest of the box showed as a black slab under it
   (owner, 9 Oct 2026: "remove the black boxes"). Its own height, no frame and
   no fill. The 12px radius is Spotify's own card radius - without it the
   iframe's square corners show as small black triangles. The square-geometry
   rule is about our components, not a third party's player. */
.audio-embed { height: 232px; }
.audio-embed > iframe { display: block; width: 100%; height: 100%; border: 0; border-radius: 12px; }

/* A row of verticals: they are tall, so they get their own grid rather than
   .cols-4, and a max width so four Reels do not tower over the section. */
.video-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(14px, 1.6vw, 22px); align-items: start; max-width: 860px; }
@media (max-width: 860px) { .video-row { grid-template-columns: repeat(2, 1fr); max-width: 460px; } }

/* Case study block: heading, optional intro, videos and the outcome line all
   share one left edge, and the outcome is marked as a result rather than
   floating free as another paragraph. */
.case { margin-top: clamp(44px, 5vw, 68px); }
.case > h3 { margin: 0 0 12px; }
.case > p { max-width: 68ch; margin: 0 0 22px; }
.case .video-row { margin-bottom: 22px; }
.case-result { max-width: 68ch; margin: 0; padding-left: 18px; border-left: 2px solid var(--cyan); color: var(--body); }
.paper .case-result { border-left-color: var(--link); }

/* readable measure for long single-column text runs */
.col > p { max-width: 75ch; }

.team-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: clamp(24px, 3vw, 44px); }
.team-grid .team-card { width: min(100%, 300px); }

.team-card { text-align: left; }
.team-card img {
  width: 100%;
  max-width: 300px;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--radius);
  margin-bottom: 16px;
}
.team-card h3 { margin-bottom: 2px; font-size: var(--t-d1); }
.team-card p { color: var(--muted); font-size: var(--t-micro); margin: 0; letter-spacing: 0.06em; text-transform: uppercase; }

.contact-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--card-pad);
}
.contact-card ul { list-style: none; margin: 0 0 8px; padding: 0; }
.contact-card li { padding: 13px 0; border-bottom: 1px solid var(--line); display: flex; gap: 12px; align-items: start; }
.contact-card li:last-child { border-bottom: 0; }
.contact-card li svg { flex-shrink: 0; color: var(--muted); margin-top: 5px; }
.contact-card .small { font-size: var(--t-sm); color: var(--muted); }
.contact-card a { color: var(--link); }

.img { margin: 0; }
.img img { border-radius: var(--radius); display: block; border: 1px solid var(--line); }
.img--plain img { border-radius: 0; border: 0; }
/* The actor portraits are already brand artwork: transparent cutouts inside a
   cyan ring. They used to be forced grayscale inside a bordered square box,
   which threw away the ring the assets were made with and rendered them as
   grey squares - owner, 9 Sep 2026: "they were already cuts with cyan rings;
   now it's just greyed squares". So no filter, no box, no border: the cutout
   sits on the canvas as drawn. Never put grayscale back here; it is the same
   mistake as fading logos with opacity. */
.img--actor img {
  width: min(100%, 190px);
  aspect-ratio: 1;
  object-fit: contain;
  border-radius: 0;
  margin: 0 0 18px;
  background: none;
  border: 0;
}

/* ---------- course pages ---------- */
.page-hero { padding: clamp(56px, 6.5vw, 92px) 0 clamp(44px, 4.5vw, 64px); border-bottom: 1px solid var(--line); }
.page-hero h1 { font-size: var(--t-d4); max-width: 18ch; }
.page-hero .sub { color: var(--body); max-width: 56ch; margin: 10px 0 0; font-size: var(--t-lead); line-height: 1.6; }
.page-hero .chip {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 18px;
}
.page-hero .chip::before { content: ""; width: 20px; height: 2px; background: var(--cyan); flex-shrink: 0; }
.page-hero .chip a { color: var(--cyan); }
.page-hero .btn-wrap { margin-top: 32px; }
.page-hero .chips { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 26px; }
.page-hero .chips span {
  border: 1px solid var(--line-strong);
  border-radius: 0;
  padding: 8px 14px;
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--body);
}
.page-hero--pull { padding-bottom: clamp(130px, 15vw, 190px); }

/* Service hero with artwork (9 Sep 2026). Owner: each service page should show
   what the service IS in a picture, not only say it in the headline, and the
   picture should be objects rather than people or logos.
   Source order is text first, so on phones the copy and the CTA stay above the
   image instead of being pushed down by it - the same reason the homepage hero
   was reworked on 3 Sep. The figure carries the canvas colour, not --card: the
   artwork is generated ON #020d1c, so a card-coloured box behind it would draw
   a visible rectangle around a picture that already blends into the page. */
.page-hero--media .hero-grid2 {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 460px);
  gap: clamp(32px, 4.5vw, 72px);
  align-items: center;
}
/* No frame and no fill. The artwork is generated ON #020d1c and measures
   within 3-6/255 of --canvas at its corners, so it blends into the section
   and reads as drawn on the page rather than as a picture sitting on it.
   Do not put the border back without re-checking those corner values. */
.hero-media { margin: 0; border: 0; background: none; }

/* SVG motifs (9 Sep 2026). Owner: "can we make them as svgs... break the image
   into elements and animate them so they appear one after another, finishing
   in the full image?" Inline SVG rather than <img>, because CSS can only reach
   the parts when the markup is in the document. Side effect worth having: no
   background rect means no ground to match, so tools/match-ground.mjs stops
   being needed for any slot converted this way. */
.motif { display: block; width: 100%; height: auto; }
.hero-media img { display: block; width: 100%; height: auto; }
/* ---------- homepage hero reel (9 Oct 2026) ----------
   Owner: "the picture HAS to be something more interesting... a cool video,
   or render image with chatgpt or gif, but it has to be cool." Real ads in a
   feed-ad card, real results beside it - see hero-reel.njk for what is shown
   and why. Square corners like everything else: a feed card, not a drawn
   phone. The result cards sit on the same hard cyan offset as a lifted card,
   and drift a few pixels against the cursor (--px/--py, set by main.js). */
.hero-reel { position: relative; width: 100%; max-width: 460px; justify-self: end; padding: 24px 46px 8px 64px; --px: 0; --py: 0; }
.reel-phone {
  position: relative; display: block; max-width: 268px; margin: 0 auto;
  background: var(--card); border: 1px solid var(--line-strong);
  color: var(--heading); text-decoration: none !important;
  translate: calc(var(--px) * 4px) calc(var(--py) * 4px);
  transition: translate 0.6s var(--ease-out), border-color 0.2s ease;
}
.reel-phone:hover { border-color: var(--cyan); }
.reel-bar { display: flex; align-items: center; gap: 8px; padding: 9px 12px; font-size: var(--t-micro); line-height: 1.2; }
.reel-avatar { width: 18px; height: 18px; background: var(--cyan); flex: none; }
.reel-brand { font-family: var(--font-display); font-weight: 600; color: var(--heading); }
.reel-sponsored { margin-left: auto; color: var(--muted); }
.reel-video { display: block; width: 100%; height: auto; aspect-ratio: 9 / 16; object-fit: cover; background: #000; }
.reel-cta {
  display: flex; justify-content: space-between; align-items: center;
  padding: 10px 12px; background: var(--card2); border-top: 1px solid var(--line);
  font-family: var(--font-display); font-weight: 600; font-size: var(--t-sm);
  transition: background 0.2s ease, color 0.2s ease;
}
.reel-cta::after { content: "→"; color: var(--cyan); transition: color 0.2s ease, translate 0.3s var(--ease-spring); }
.reel-phone:hover .reel-cta { background: var(--cyan); color: var(--navy-ink); }
.reel-phone:hover .reel-cta::after { color: var(--navy-ink); translate: 4px 0; }
.reel-card {
  position: absolute; z-index: 2;
  display: grid; gap: 3px; min-width: 172px; padding: 14px 16px 15px;
  background: var(--card); border: 1px solid var(--line-strong);
  box-shadow: 6px 6px 0 var(--cyan);
  color: var(--body); text-decoration: none !important;
  transition: translate 0.6s var(--ease-out), transform 0.3s var(--ease-spring), box-shadow 0.3s var(--ease-spring);
}
.reel-card:hover { transform: translate(-3px, -3px); box-shadow: 9px 9px 0 var(--cyan); }
.reel-card--a { top: 70px; right: 0; translate: calc(var(--px) * -12px) calc(var(--py) * -10px); }
.reel-card--b { bottom: 130px; left: 0; translate: calc(var(--px) * 10px) calc(var(--py) * 8px); }
.reel-card-label { font-size: var(--t-micro); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
.reel-card-num { font-family: var(--font-display); font-weight: 600; font-size: var(--t-d2); line-height: 1.05; letter-spacing: -0.02em; color: var(--heading); font-variant-numeric: tabular-nums; }
.reel-card-num .sfx { color: var(--cyan); }
.reel-card-sub { font-size: var(--t-sm); color: var(--body); }
/* The video page's header uses the reel without the result cards (11 Oct
   2026): no room needs keeping for cards, and the inner-page hero hides its
   artwork on phones, where the wide reel under the headline takes over. */
.hero-reel--plain { padding: 0; max-width: 340px; }
@media (max-width: 980px) { .page-hero .hero-reel { display: none; } }
.reel-caption { margin-top: 14px; text-align: center; font-size: var(--t-micro); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
@media (prefers-reduced-motion: no-preference) {
  .hero-reel .reel-phone { --rise: 26px; animation: hero-rise calc(0.8s * var(--motion)) var(--ease-out) calc(0.3s * var(--motion)) backwards; }
  .hero-reel .reel-card { animation: reel-pop calc(0.7s * var(--motion)) var(--ease-spring) backwards; }
  .hero-reel .reel-card--a { animation-delay: calc(0.85s * var(--motion)); }
  .hero-reel .reel-card--b { animation-delay: calc(1.05s * var(--motion)); }
  .hero-reel .reel-caption { animation: hero-rise calc(0.6s * var(--motion)) var(--ease-out) calc(1.2s * var(--motion)) backwards; }
}
@keyframes reel-pop { from { opacity: 0; transform: translateY(18px) scale(0.9); } }
/* The phone and tablet version: horizontal, directly under the headline (see
   hero-reel-wide.njk). Hidden on desktop, where the vertical reel shows. */
.hero-reel-m { display: none; }
@media (max-width: 980px) {
  .hero-reel-m {
    display: block; max-width: 560px; margin: 6px 6px 26px 0;
    background: var(--card); border: 1px solid var(--line-strong);
    box-shadow: 6px 6px 0 var(--cyan);
    color: var(--heading); text-decoration: none !important;
  }
  .reel-m-video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; background: #000; }
  /* No bottom bar on the phone card: the whole card is the link already, and
     a button-like strip directly above the real call to action read as a
     second, competing button - and pushed that button past the first screen
     on a 375x812 phone. */
  .hero-reel-m .reel-cta { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .reel-phone, .reel-card { translate: none; }
}

@media (max-width: 980px) {
  .page-hero--media .hero-grid2 { grid-template-columns: 1fr; gap: clamp(28px, 4vw, 40px); }
  .hero-media { max-width: 560px; }
}

/* Collapse the join: a hero already provides the top air, so the first
   section after it must not add a full --sec-pad on top of it. */
.page-hero + .sec,
.sec--hero + .sec { padding-top: clamp(44px, 5vw, 72px); }
.page-hero + .paper .article-shell { padding-top: clamp(40px, 4.5vw, 64px); }
.page-hero .btn-wrap { margin-top: 26px; }
.page-hero .chips { margin-top: 22px; }

.course-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 384px;
  gap: clamp(40px, 5vw, 80px);
  align-items: start;
}
@media (max-width: 1020px) {
  .course-layout { grid-template-columns: 1fr; }
  .course-aside { order: -1; }
}
.course-aside { position: sticky; top: 100px; display: flex; flex-direction: column; gap: 20px; }
@media (max-width: 1020px) { .course-aside { position: static; } }

.course-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-top: 2px solid var(--cyan);
  border-radius: var(--radius);
  padding: var(--card-pad);
}
.course-card .price-label { font-size: var(--t-micro); font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); margin: 0 0 8px; }
.course-card .price { font-family: var(--font-display); font-weight: 600; font-size: var(--t-d3); letter-spacing: -0.02em; color: var(--heading); line-height: 1; margin: 0 0 4px; font-variant-numeric: tabular-nums; }
.course-card .price .sfx { color: var(--cyan); }
.course-card .price small { font-size: var(--t-base); font-weight: 500; color: var(--muted); letter-spacing: 0; }
.course-card .btn { width: 100%; margin-top: 20px; }
.course-card .fine { font-size: var(--t-sm); color: var(--muted); text-align: center; margin: 12px 0 0; }

/* Standalone fine print under a payment/booking block. Without these it
   inherited body size at full container width and read as a wall of terms.
   The full policy lives in .fine-more so it stays available without
   dominating the section. */
.fine { font-size: var(--t-sm); color: var(--muted); max-width: 68ch; margin: clamp(28px, 3vw, 40px) 0 0; }
.fine-more { max-width: 68ch; margin-top: 10px; }
.fine-more .faq summary { font-size: var(--t-sm); font-weight: 400; color: var(--muted); padding: 12px 40px 12px 0; }
.fine-more .faq summary::after { right: 6px; width: 7px; height: 7px; }
.fine-more .faq[open] { background: transparent; }
.fine-more .faq > div { padding: 0 0 16px; font-size: var(--t-sm); color: var(--muted); }
.fine-more .faq > div p { margin: 0 0 10px; }
.fine-more .faq > div p:last-child { margin-bottom: 0; }

.course-facts { list-style: none; margin: 20px 0 0; padding: 0; }
.course-facts li { display: flex; justify-content: space-between; gap: 18px; padding: 12px 0; border-top: 1px solid var(--line); font-size: var(--t-base); }
.course-facts li span:first-child { color: var(--muted); flex-shrink: 0; }
.course-facts li span:last-child { text-align: right; color: var(--heading); font-weight: 500; font-variant-numeric: tabular-nums; }

.badge { display: inline-flex; align-items: center; gap: 8px; border: 1px solid var(--line-strong); color: var(--body); border-radius: 0; padding: 8px 12px; font-size: var(--t-sm); font-weight: 500; }
.badge--muted { color: var(--muted); }
.course-card .badge { margin-top: 14px; }

.instructor-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 26px; }
.instructor-card .who { display: flex; align-items: center; gap: 16px; margin-bottom: 14px; }
.instructor-card img { width: 60px; height: 60px; object-fit: cover; border-radius: 0; }
.instructor-card .who strong { display: block; font-family: var(--font-display); font-weight: 600; font-size: var(--t-base); color: var(--heading); }
.instructor-card .who span { font-size: var(--t-micro); color: var(--muted); letter-spacing: 0.08em; text-transform: uppercase; }
.instructor-card p { font-size: var(--t-base); margin: 0 0 12px; }
.instructor-card .arrow-link { font-size: var(--t-sm); }

.tick-list { list-style: none; padding: 0; margin: 0 0 1.2em; }
.tick-list li { position: relative; padding-left: 30px; margin-bottom: 0.65em; }
.tick-list li::before { content: "✓"; position: absolute; left: 0; top: 0; color: var(--tick); font-weight: 700; }
/* Labelled ticks (9 Oct 2026). Owner, on a seven-item list of two- and
   three-line sentences: "this is just big blob of text... less text, put only
   what's important." A short bold label on its own line, then one clause: the
   label is what a skimming reader takes away, the clause is there for the
   reader who stops. */
.tick-list--labels li { margin-bottom: 1.05em; }
.tick-list--labels li strong { display: block; font-family: var(--font-display); font-weight: 600; color: var(--heading); }
/* Commercial terms set apart from the copy, so the strongest promise on a page
   is not buried in the second sentence of a lead. The cyan inset bar is the
   same device as an open FAQ question. */
.terms { margin: 26px 0; padding: 18px 22px; background: var(--card); box-shadow: inset 4px 0 0 var(--cyan); }
.terms p { margin: 0; }
.terms p + p { margin-top: 8px; color: var(--muted); }
.terms strong { font-family: var(--font-display); font-weight: 600; color: var(--heading); }

.course-body h2 { font-size: var(--t-d2); margin-top: 2.2em; scroll-margin-top: 110px; }
.course-body > p:first-child, .course-body > .lead:first-child { margin-top: 0; }

.course-tile {
  background: var(--canvas);
  padding: var(--card-pad);
  height: 100%;
  display: flex;
  flex-direction: column;
  transition: background 0.15s ease;
}
.course-tile:hover { background: var(--card2); }
.course-tag { font-family: var(--font-display); font-size: var(--t-micro); font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); margin-bottom: 16px; }
.course-tile h3 { font-size: var(--t-d1); margin-bottom: 16px; }
.course-tile h3 a { color: var(--heading); }
.course-tile h3 a:hover { color: var(--link); text-decoration: none; }
.course-tile .tick-list { flex: 1; margin-bottom: 20px; }
.course-tile .tick-list li { font-size: var(--t-base); margin-bottom: 0.55em; }

/* ---------- blog ---------- */
.post-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(24px, 2.8vw, 36px); }
@media (max-width: 980px) { .post-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px) { .post-grid { grid-template-columns: 1fr; } }

.post-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: border-color 0.2s ease;
}
.post-card:hover { border-color: var(--cyan); }
.post-card > a:first-child { display: block; aspect-ratio: 16/10; overflow: hidden; background: var(--card2); border-bottom: 1px solid var(--line); }
.post-card img { aspect-ratio: 16/10; object-fit: cover; width: 100%; display: block; }
.post-card-body { padding: 26px 28px 28px; display: flex; flex-direction: column; gap: 10px; flex: 1; }
.post-card .post-title { margin: 0; font-size: var(--t-d1); line-height: 1.25; letter-spacing: -0.01em; }
.post-card .post-title a { color: var(--heading); }
.post-card .post-title a:hover { color: var(--link); text-decoration: none; }
.post-card .date { color: var(--muted); font-size: var(--t-micro); font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase; }
.post-card p { margin: 0; font-size: var(--t-base); color: var(--muted); flex: 1; }
.post-card .more { font-family: var(--font-display); font-weight: 500; font-size: var(--t-sm); color: #fff; }
.post-card .more::after { content: " →"; display: inline-block; transition: transform 0.15s ease; }
.post-card:hover .more::after { transform: translateX(4px); }

.post-grid--featured .post-card:first-child { grid-column: span 2; }
.post-grid--featured .post-card:first-child .post-title { font-size: var(--t-d1); }
@media (max-width: 640px) { .post-grid--featured .post-card:first-child { grid-column: auto; } }

.post-meta { color: var(--muted); font-size: var(--t-micro); font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase; margin: 0 0 14px; }
.post-meta a { color: var(--cyan); }
.post-featured { border-radius: var(--radius); margin: 0 0 44px; width: 100%; border: 1px solid var(--line-strong); }
.article-pull { margin-top: clamp(-120px, -10vw, -80px); position: relative; }

.prose { font-size: var(--t-body); line-height: 1.8; color: var(--body); }
.prose h2, .prose h3 { margin-top: 2em; scroll-margin-top: 110px; }
.prose h2 { font-size: var(--t-d2); }
.prose img { border-radius: var(--radius); margin: 16px 0; border: 1px solid var(--line); }
.prose li { margin-bottom: 0.45em; }
.prose ul, .prose ol { padding-left: 1.3em; }
.prose blockquote { border-left: 2px solid var(--line-strong); margin: 1.5em 0; padding: 0.4em 0 0.4em 1.3em; color: var(--muted); }
.prose iframe { max-width: 100%; width: 100%; aspect-ratio: 16/9; height: auto; border: 0; border-radius: var(--radius); }
.prose a { color: var(--link); text-decoration: underline; text-underline-offset: 3px; }
.prose strong { color: var(--heading); }

.chip-row { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: clamp(32px, 4vw, 48px); }
/* Inside a card the paragraph above has no bottom margin (.cell p), so the
   links sat flush against the last line of text. */
.cell .chip-row { margin: 22px 0 0; }
.chip-link {
  display: inline-block;
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--body);
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: 0;
  padding: 9px 16px;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.chip-link:hover, .chip-link.active { border-color: rgba(255, 255, 255, 0.6); color: #fff; text-decoration: none; }

/* ---------- footer ---------- */
.footer { background: var(--canvas); color: var(--muted); padding: clamp(64px, 8vw, 96px) 0 0; font-size: var(--t-sm); border-top: 1px solid var(--line); }
.footer-grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1.2fr; gap: clamp(32px, 4vw, 64px); padding-bottom: clamp(44px, 5vw, 64px); }
@media (max-width: 980px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .footer-grid { grid-template-columns: 1fr; } }
.footer-h { color: var(--muted); font-size: var(--t-micro); letter-spacing: 0.16em; text-transform: uppercase; margin: 0 0 20px; font-family: var(--font-display); font-weight: 500; }
.footer-brand .wordmark { font-family: var(--font-display); font-weight: 600; font-size: var(--t-d1); color: #fff; display: inline-block; margin-bottom: 12px; letter-spacing: -0.02em; }
.footer-brand p { max-width: 30ch; color: var(--muted); }
.footer ul { list-style: none; margin: 0; padding: 0; }
.footer ul li { margin-bottom: 12px; }
.footer a { color: var(--body); }
.footer a:hover { color: #fff; text-decoration: none; }
.footer-social { display: flex; gap: 16px; margin-top: 20px; }
.footer-social a { color: var(--muted); }
.footer-social a:hover { color: #fff; }
.footer-bottom {
  border-top: 1px solid var(--line);
  padding: 24px 0;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  font-size: var(--t-sm);
  color: var(--muted);
}

/* ONE TEMPO KNOB for everything that animates on its own - entrances, scroll
   reveals, motif assembly, counters (main.js reads it too), ambient loops.
   1 = the original timing; 1.3 since 14 Sep 2026, owner: "make all of the
   animations animate slightly slower". Hover, focus and dropdown feedback is
   deliberately NOT on it: slowing UI feedback reads as lag, not calm. */
:root { --motion: 1.3; }

/* ---------- reveal ---------- */
@media (prefers-reduced-motion: no-preference) {
  .reveal { opacity: 0; transform: translateY(12px); transition: opacity calc(0.5s * var(--motion)) ease, transform calc(0.5s * var(--motion)) ease; }
  .reveal.in { opacity: 1; transform: none; }
}

.skip-link { position: absolute; left: -9999px; top: 0; background: #fff; color: #020d1c; padding: 12px 18px; z-index: 100; }
.skip-link:focus { left: 0; }

/* ==========================================================================
   PAPER — the light reading surface (owner request: white background for the
   blog posts, and for other content where it helps readability).
   Token-driven, so every component that works on the dark canvas works here
   unchanged. Cyan is DECORATIVE ONLY on paper; interactive text uses
   --link #01608c (5.9:1 on white). Never put cyan text on white.
   ========================================================================== */
.paper {
  --canvas: #ffffff;
  --card: #f4f8fc;
  --card2: #e9f1f8;
  --line: rgba(11, 27, 43, 0.13);
  --line-strong: rgba(11, 27, 43, 0.24);
  --well: #eef4f9;         /* inset fill flips too, or inputs stay navy */
  --warn: #a3232f;         /* the dark-canvas red is unreadable on paper */
  --line-hover: rgba(11, 27, 43, 0.42);
  --heading: #0b1b2b;
  --body: #33475b;
  --muted: #5a6f84;
  --link: #01608c;
  --tick: #01608c;
  background: var(--canvas);
  color: var(--body);
}
.paper--tint { --canvas: #f6f9fc; background: var(--canvas); }
.paper .accent-text { color: var(--link); }
.paper ::selection { background: rgba(3, 195, 248, 0.28); color: #0b1b2b; }
.paper :focus-visible { outline-color: var(--link); }
/* buttons on paper: navy fill reads calmer than a cyan slab on white */
.paper .btn { background: #0b1b2b; color: #ffffff !important; }
.paper .btn:hover { background: #16324b; box-shadow: 3px 3px 0 var(--cyan); }
.paper .btn--ghost { border-color: rgba(11, 27, 43, 0.3); color: #0b1b2b !important; }
.paper .btn--ghost:hover { border-color: #0b1b2b; background: rgba(11, 27, 43, 0.05) !important; }
/* Both forms, deliberately. `.paper .page-hero` only matches when paper is an
   ANCESTOR - and a service page's hero carries both classes on the SAME
   element, so the descendant form silently never applies there. That is how a
   cyan chip link survived on a white ground at 2.07:1, which is the exact
   combination the paper rules ban. Any future `.paper .page-hero ...` rule
   needs its `.page-hero.paper ...` twin. */
.paper .eyebrow,
.paper .page-hero .chip,
.page-hero.paper .chip { color: var(--muted); }
.paper .page-hero .chip a,
.page-hero.paper .chip a { color: var(--link); }
.paper .eyebrow .idx { color: var(--link); }
.paper .faq[open] { background: var(--card); }
.paper .cta, .paper .panel, .paper .course-card,
.paper .instructor-card, .paper .contact-card { background: var(--card); }
.paper .media figcaption { background: rgba(11, 27, 43, 0.9); color: #e9f1f8; }

/* ==========================================================================
   MEDIA — framed imagery slots. The artwork is flat brand illustration on the
   same navy, so it sits inside a hairline frame instead of floating.
   ========================================================================== */
.media { margin: 0; position: relative; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius); background: var(--card); }
.media img { display: block; width: 100%; height: 100%; object-fit: cover; }
.media--wide { aspect-ratio: 3 / 2; }
/* The LIAA price as a receipt (18 Sep 2026). Owner: the three equal numerals
   did not say what a buyer pays, gets back or is left with. The rows read as a
   sum - price, minus LIAA's share, the client's share under a double rule - and
   the bar shows the split at a glance. The client's share is the only large
   numeral. The support stays conditional in its own label (CONTENT-RULES 2). */
.calc { margin: 0; }
.calc-row { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; padding: 12px 0; border-top: 1px solid var(--line); }
.calc-row:first-child { border-top: 0; padding-top: 0; }
.calc-row dt { color: var(--body); font-size: var(--t-base); }
.calc-row dd { margin: 0; color: var(--heading); font-size: var(--t-base); font-variant-numeric: tabular-nums; white-space: nowrap; text-align: right; }
.calc-note { display: block; margin-top: 2px; color: var(--muted); font-size: var(--t-sm); }
.calc-tax { color: var(--muted); font-size: var(--t-sm); }
.calc-row--total { border-top: 3px double var(--line-strong); margin-top: 4px; padding-top: 16px; }
.calc-row--total dt { color: var(--heading); font-weight: 600; }
.calc-num { font-family: var(--font-display); font-weight: 600; font-size: var(--t-d2); line-height: 1; letter-spacing: -0.02em; }
.calc-num .sfx { color: var(--cyan); }
.calc-bar { display: flex; height: 30px; margin-top: 18px; border: 1px solid var(--line-strong); font-size: var(--t-micro); letter-spacing: 0.08em; text-transform: uppercase; }
.calc-bar span { display: flex; align-items: center; padding: 0 10px; white-space: nowrap; overflow: hidden; }
.calc-bar-liaa { background: var(--well); color: var(--muted); }
.calc-bar-you { background: var(--body); color: var(--navy-ink); font-weight: 600; justify-content: flex-end; }
.calc-flow-h { margin: 26px 0 6px; font-size: var(--t-micro); letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.calc-flow { margin: 0; padding: 0; list-style: none; counter-reset: flow; }
.calc-flow li { counter-increment: flow; display: grid; grid-template-columns: 22px 1fr; gap: 6px; padding: 5px 0; font-size: var(--t-sm); color: var(--body); }
.calc-flow li::before { content: counter(flow); color: var(--muted); font-family: var(--font-display); font-weight: 600; }
.calc-flow b { color: var(--heading); font-weight: 600; }
.price-calc .fine { margin-top: 18px; }
/* The two offers side by side on the LIAA pillar: their leads differ in length,
   so the receipts started at different heights. A subgrid gives both columns
   the same four rows (title, lead, receipt, link), so the receipts line up. */
@media (min-width: 641px) {
  .offer-cols { grid-template-rows: repeat(4, auto); row-gap: 0; }
  .offer-cols > .col { display: grid; grid-template-rows: subgrid; grid-row: span 4; align-content: start; }
}

/* The LIAA scope table. The buyer copies this into their cenu aptaujas
   protokols, so it is a real <table> (copies as tab separated text), not a
   grid of divs. Hairlines and square corners like every other surface; it
   scrolls inside its own box rather than widening the page on a phone. */
.scope-wrap { overflow-x: auto; margin: clamp(24px, 3vw, 34px) 0; }
.scope { width: 100%; min-width: 660px; border-collapse: collapse; font-size: var(--t-sm); }
.scope th, .scope td { text-align: left; vertical-align: top; padding: 14px 22px 14px 0; border-bottom: 1px solid var(--line); }
.scope th { color: var(--muted); font-size: var(--t-micro); text-transform: uppercase; letter-spacing: .08em; border-bottom-color: var(--line-strong); }
.scope td:first-child { color: var(--heading); }
.scope tbody tr:last-child td { border-bottom: 0; }

/* A band holding a motif instead of a photograph: no frame, no fill, page
   ground, so it dissolves into the section the way the hero artwork does.
   Written `.media.media--motif` and placed AFTER `.media`. Third time this bit
   today: a single-class modifier ties with the base class on specificity, so
   whichever sits later in the file wins, and mine sat earlier - the frame and
   the card fill both survived. `.paper .page-hero` and `.hero-media--faces`
   were the first two. Qualify modifiers with the base class. */
.media.media--motif { border: 0; background: none; aspect-ratio: auto; overflow: visible; }
.media.media--motif .motif { display: block; width: 100%; height: auto; }
.media--square { aspect-ratio: 1; }
.media--portrait { aspect-ratio: 3 / 4; }
/* The founder frame carries deliberate headroom above the subject, which made
   the homepage process section unnecessarily tall. The photograph occupies the
   bottom square of that frame, so a 1:1 crop anchored to the bottom removes the
   drawn headroom exactly and takes nothing off the subject. */
/* The founder portrait is drawn with no field of its own (see
   tools/brand-portraits.mjs), so it sits straight on the section: no
   frame and no fill, or it reads as a dark tile pasted onto the band. */
.media--crop-top { aspect-ratio: 1 / 1; border: 0; background: none; }
.media--crop-top img { object-position: center bottom; }
.media figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 13px 18px;
  background: rgba(2, 13, 28, 0.82);
  border-top: 1px solid var(--line);
  font-size: var(--t-micro); letter-spacing: 0.12em; text-transform: uppercase; color: #c9d8e8;
}

/* clip-wipe reveal for imagery (flat — no fade through a color) */
@media (prefers-reduced-motion: no-preference) {
  .media.reveal { opacity: 1; transform: none; }
  .media.reveal img { clip-path: inset(0 0 100% 0); transition: clip-path calc(0.85s * var(--motion)) cubic-bezier(0.22, 1, 0.36, 1); }
  .media.reveal.in img { clip-path: inset(0 0 0 0); }
}

/* Inner-page hero entrance. Pure CSS so it needs no observer and cannot leave
   content hidden if the script never runs; `backwards` holds the from-state
   during the delay. Same rise as .reveal, so the page reads as one system. */
@keyframes hero-rise { from { opacity: 0; transform: translateY(var(--rise, 14px)); } }
@keyframes motif-in { from { opacity: 0; transform: translateY(12px) scale(0.94); } }
@keyframes motif-in-scroll { from { opacity: 0; transform: translateY(14px) scale(0.94); } to { opacity: 1; transform: none; } }
@keyframes hero-drift { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
@media (prefers-reduced-motion: no-preference) {
  .page-hero .chip,
  .page-hero h1,
  .page-hero .sub,
  .page-hero .chips,
  .page-hero .btn-wrap { animation: hero-rise calc(0.6s * var(--motion)) cubic-bezier(0.22, 1, 0.36, 1) backwards; }
  .page-hero .chip { animation-delay: calc(0.04s * var(--motion)); }
  .page-hero h1 { animation-delay: calc(0.1s * var(--motion)); }
  .page-hero .sub { animation-delay: calc(0.18s * var(--motion)); }
  .page-hero .chips { animation-delay: calc(0.26s * var(--motion)); }
  .page-hero .btn-wrap { animation-delay: calc(0.34s * var(--motion)); }
  /* The artwork lands last, after the CTA, so the hero assembles in reading
     order. It rises slightly further than the text because it is much bigger
     and the same 14px on a 460px block reads as no movement at all. */
  .page-hero--media .hero-media { animation: hero-rise calc(0.75s * var(--motion)) cubic-bezier(0.22, 1, 0.36, 1) calc(0.42s * var(--motion)) backwards; }
  .page-hero--media .hero-media { --rise: 22px; }
  /* Then it drifts, very slowly and very slightly. This is the hero-dot
     vocabulary the owner already approved, not a new device: 6px over 9s is
     below the threshold where motion reads as an effect. The drift is on the
     IMG and the entrance is on the FIGURE, because two animations on one
     element would fight over transform. */
  .hero-media img { animation: hero-drift calc(9s * var(--motion)) ease-in-out calc(1.2s * var(--motion)) infinite; }
  /* In-page motifs assemble when they scroll into view rather than on load.
     They ride the reveal observer that already exists in main.js: the parent
     picks up .in (or .is-visible), and the parts stagger from there.
     The holding opacity:0 lives INSIDE this no-preference block on purpose -
     under `reduce` it is never applied, so the drawing is simply present
     rather than stuck invisible waiting for an observer that never fires. */
  /* Held hidden ONLY while main.js is holding the reveal (.reveal without .in).
     It used to be a bare `.motif--scroll .m`, which hid the drawing forever
     wherever the observer never ran - JS off, or no IntersectionObserver.
     The second selector of each pair covers the class sitting ON the revealed
     element itself (a .media band is its own reveal target), where a
     descendant selector can never match. `backwards` fill holds the
     from-state through each piece's delay, now that nothing else does - and
     NOT `both`: a forwards fill keeps the finished animation alive, the piece
     stays on a GPU layer, and hairlines in it resample differently from the
     rest of the page (measured 4.6-5.6/255 along every grid line). Once .in
     is on, the resting style is already opacity 1, so nothing needs holding
     afterwards. */
  .reveal:not(.in) .motif--scroll .m,
  .reveal.motif--scroll:not(.in) .m { opacity: 0; }
  .reveal.in .motif--scroll .m,
  .reveal.in.motif--scroll .m,
  .is-visible .motif--scroll .m,
  .in .motif--scroll .m {
    animation: motif-in-scroll calc(0.5s * var(--motion)) cubic-bezier(0.22, 1, 0.36, 1) backwards;
    animation-delay: calc(var(--i, 0) * 0.07s * var(--motion));
  }
  /* Parts assemble in drawing order, then the whole motif drifts with the rest
     of the hero. transform-box: fill-box is required or the scale pivots on the
     SVG user-space origin and the shape flies in from the corner. */
  /* Parts assemble in drawing order, then the whole motif drifts with the rest
     of the hero. The delay comes from an inline --i on each group, so a motif
     can have any number of parts without adding CSS.
     transform-box: fill-box is required, or scale pivots on the SVG user-space
     origin and the shape flies in from the corner. */
  .motif .m {
    transform-box: fill-box;
    transform-origin: center;
    animation: motif-in calc(0.45s * var(--motion)) cubic-bezier(0.22, 1, 0.36, 1) backwards;
    animation-delay: calc((0.46s + var(--i, 0) * 0.075s) * var(--motion));
  }
  /* Post headers are PIECES of the real cover: each piece is a clipped copy of
     the whole picture, so its fill-box is the whole picture's box and
     `center` would pivot every piece on the picture's middle. Each piece
     carries its own transform-origin inline, in user units, which is what
     view-box resolves them against - so it settles in place like a traced
     shape does. */
  .motif.motif--pieces .m { transform-box: view-box; }
  .hero-media:has(.motif) { animation: hero-rise calc(0.75s * var(--motion)) cubic-bezier(0.22, 1, 0.36, 1) calc(0.3s * var(--motion)) backwards, hero-drift calc(9s * var(--motion)) ease-in-out calc(2s * var(--motion)) infinite; }

  /* Tick items cascade inside their own list (main.js staggers by sibling
     index), so the shift is smaller than a card's or it reads as jitter. */

  /* Picture creeps in on hover. .cell-media already clips, so this stays a
     flat crop change - no shadow, no glow, nothing the ledger forbids. */
  .cell-media img,
  .course-tile--media .cell-media img { transition: transform 0.7s cubic-bezier(0.22, 1, 0.36, 1); }
  .cell--media:hover .cell-media img,
  .course-tile--media:hover .cell-media img,
  .cell--media:focus-within .cell-media img,
  .course-tile--media:focus-within .cell-media img { transform: scale(1.045); }
}

/* ==========================================================================
   ARTICLE — long-form reading on paper
   ========================================================================== */
.read-progress {
  position: fixed; top: 0; left: 0; height: 3px; width: 100%;
  transform: scaleX(0); transform-origin: 0 50%;
  background: var(--cyan); z-index: 80; pointer-events: none;
}
.article-shell { padding-block: clamp(52px, 6vw, 84px) clamp(64px, 8vw, 104px); }
/* The single definition of the article grid lives further down, next to the
   reading-column comment — keeping a second one here silently overrode it. */
.article-grid { display: grid; align-items: start; }

.article-body .prose { font-size: var(--t-body); line-height: 1.78; }
/* No enlarged first paragraph: it read as a different size mid-article and
   introduced a fourth text colour on top of the three the system allows. */
/* No rule and no tick above an article h2 (9 Sep 2026). A hairline plus a cyan
   mark was added to break up the white column and the owner read it as a
   "weird section break" - inside running prose the heading itself is already
   the break, and a horizontal rule every few paragraphs chops the reading.
   The tick device stays where it belongs: eyebrows and steps, not body copy. */
.article-body .prose h2 {
  font-size: var(--t-d2);
  margin: 2.2em 0 0.7em;
  color: var(--heading);
}
.article-body .prose h3 { font-size: var(--t-d1); margin: 2em 0 0.6em; color: var(--heading); }
.article-body .prose img { border: 1px solid var(--line); border-radius: var(--radius); margin: 2em 0; }
.article-body .prose ul, .article-body .prose ol { padding-left: 1.4em; margin: 0 0 1.4em; }
.article-body .prose li { margin-bottom: 0.55em; }
.article-body .prose li::marker { color: var(--muted); }
.article-body .prose blockquote {
  border-left: 3px solid var(--cyan);
  margin: 2em 0; padding: 0.2em 0 0.2em 1.5em;
  font-size: var(--t-lead); line-height: 1.6; color: var(--heading); font-style: normal;
}
.article-body .prose strong { color: var(--heading); font-weight: 600; }
.article-body .prose a { color: var(--link); text-decoration-thickness: 1px; }
.article-body .prose iframe { border-radius: var(--radius); margin: 2em 0; }
.article-body .prose hr { border: 0; border-top: 1px solid var(--line); margin: 2.6em 0; }

/* in-article table of contents */
.toc { position: sticky; top: 104px; font-size: var(--t-sm); }
@media (max-width: 1020px) {
  .toc { position: static; margin-bottom: 40px; border: 1px solid var(--line); border-radius: var(--radius); padding: 20px 22px; background: var(--card); }
}
.toc-h { font-family: var(--font-body); font-size: var(--t-micro); font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); margin: 0 0 14px; }
.toc ol { list-style: none; margin: 0; padding: 0; counter-reset: toc; }
.toc li { counter-increment: toc; border-left: 1px solid var(--line); }
.toc li.is-active { border-left-color: var(--cyan); }
.toc a { display: block; padding: 8px 0 8px 16px; color: var(--muted); line-height: 1.4; }
.toc a::before { content: counter(toc, decimal-leading-zero) "  "; color: var(--line-strong); font-variant-numeric: tabular-nums; }
.toc a:hover { color: var(--heading); text-decoration: none; }
.toc li.is-active > a { color: var(--heading); font-weight: 500; }

/* article meta row under the title (on the dark hero) */
.article-meta { display: flex; flex-wrap: wrap; gap: 10px 20px; align-items: center; margin: 20px 0 0; font-size: var(--t-sm); color: var(--muted); letter-spacing: 0.04em; }
.article-meta .dot { width: 3px; height: 3px; background: currentColor; border-radius: 50%; opacity: 0.6; }

/* author strip closing the article */
.author-strip { display: flex; gap: 18px; align-items: center; margin-top: 56px; padding-top: 28px; border-top: 1px solid var(--line); }
.author-strip img { width: 56px; height: 56px; border-radius: 0; object-fit: cover; border: 1px solid var(--line); }
.author-strip strong { display: block; color: var(--heading); font-family: var(--font-display); }
.author-strip span { font-size: var(--t-sm); color: var(--muted); }

/* ==========================================================================
   DYNAMICS — counters, scroll cues, back-to-top (all reduced-motion safe)
   ========================================================================== */
.stat .num[data-count] { font-variant-numeric: tabular-nums; }
.to-top {
  position: fixed; right: 22px; bottom: 82px; z-index: 70;
  width: 44px; height: 44px; display: grid; place-items: center;
  background: #00152c; color: #ffffff;
  border: 1px solid rgba(255, 255, 255, 0.22); border-radius: 0;
  opacity: 0; pointer-events: none; transform: translateY(8px);
  transition: opacity 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
}
.to-top.show { opacity: 1; pointer-events: auto; transform: none; }
.to-top:hover { border-color: var(--cyan); background: var(--cyan); color: var(--navy-ink); }
@media (max-width: 640px) { .to-top { right: 14px; bottom: 72px; } }

/* .steps nested inside a half-width column (homepage process + image) —
   viewport breakpoints cannot see the narrower container, so scope it. */
.row .steps { grid-template-columns: 1fr 1fr; }
@media (max-width: 640px) { .row .steps { grid-template-columns: 1fr; } }

/* --------------------------------------------------------------------------
   Article header: the cover sits BEHIND the title text as the hero backdrop,
   darkened with a flat scrim (solid colour at opacity — never a gradient).
   -------------------------------------------------------------------------- */
.page-hero--cover {
  position: relative;
  isolation: isolate;
  padding-top: clamp(88px, 10vw, 140px);
  padding-bottom: clamp(88px, 10vw, 140px);
  min-height: clamp(440px, 46vw, 580px);
  display: flex;
  align-items: center;
}
.page-hero--cover .hero-bg { position: absolute; inset: 0; z-index: -2; margin: 0; overflow: hidden; }
.page-hero--cover .hero-bg img { width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; }
.page-hero--cover::before { content: ""; position: absolute; inset: 0; z-index: -1; background: rgba(2, 13, 28, 0.74); }
.page-hero--cover .container { position: relative; }
@media (max-width: 640px) {
  .page-hero--cover { min-height: 0; }
  .page-hero--cover::before { background: rgba(2, 13, 28, 0.82); }
}

/* Article reading column — the ONE place the article grid is defined.
   An empty left gutter mirrors the TOC on the right, so the measure sits in the
   true centre of the page. Without it a right-hand sidebar pushes every line of
   the article off-centre. The gutter is a FIXED track on purpose: minmax(0,…)
   collapses to zero when a track has no content, which would un-centre it.
   The measure is set in px, not ch: ch resolves against the grid container font
   size rather than the 18px prose, so 62ch was rendering as ~76 characters. */
.article-shell > .container { max-width: 1060px; }
.article-grid {
  grid-template-columns: 1fr minmax(0, 720px) 210px;
  justify-content: center;
  gap: clamp(28px, 3.2vw, 48px);
}
.article-body { grid-column: 2; grid-row: 1; max-width: none; }
/* The TOC precedes the article in the markup so it leads on small screens;
   pinning both to row 1 keeps them side by side on desktop (without it the
   auto-placement cursor pushes the article into a second row). */
.toc { grid-column: 3; grid-row: 1; }
@media (max-width: 1020px) {
  .article-grid { grid-template-columns: minmax(0, 720px); justify-content: center; }
  .article-body, .toc { grid-column: 1; grid-row: auto; }
}

/* v7 "alive" motion (9 Oct 2026). Entrances are on --motion; hovers are not. */
@keyframes word-up { from { transform: translateY(112%) rotate(4deg); } }
@keyframes hl-draw { from { background-size: 0 0.12em; } }
@media (prefers-reduced-motion: no-preference) {
  /* the split headline replaces the block rise with a per-word one */
  .page-hero h1.split, .sec--hero h1.split { animation: none; }
  .split .wi {
    animation: word-up calc(0.9s * var(--motion)) var(--ease-spring) backwards;
    animation-delay: calc((0.1s + var(--i) * 0.065s) * var(--motion));
  }
  /* heading keywords draw in once their section arrives... */
  :is(h2, h3) em, .hl { transition: background-size calc(0.8s * var(--motion)) var(--ease-out) calc(0.3s * var(--motion)); }
  .reveal:not(.in) :is(h2, h3) em, .reveal:not(.in) .hl { background-size: 0 0.12em; }
  /* ...and in a hero, once the words have landed */
  .page-hero h1 em, .sec--hero h1 em { animation: hl-draw calc(0.85s * var(--motion)) var(--ease-out) calc(0.7s * var(--motion)) backwards; }
}
/* Reduced motion keeps every state, drops every movement: a hovered card
   still gets its cyan block and a button its white one, in place. */
@media (prefers-reduced-motion: reduce) {
  .btn:hover, .wa-float:hover,
  .cell:has(> .arrow-link):is(:hover, :focus-within),
  .course-tile:has(.arrow-link):is(:hover, :focus-within),
  .post-card:is(:hover, :focus-within) { translate: none; transform: none; }
  .btn, .cell, .course-tile, .post-card, .wa-float, .brand img,
  .btn--ghost::before, .nav > ul > li > a::before, .faq summary::after { transition-duration: 0.01s !important; }
  .brand:hover img { transform: none; }
}

/* ==========================================================================
   MOTION ACCENTS — vector-only, compositor-only (transform/opacity), so they
   cannot trigger layout or paint work. Everything here is inside a
   prefers-reduced-motion:no-preference guard.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {

  /* 1. Eyebrow tick + section rule draw themselves in when the header appears */
  .sec-head .eyebrow::before,
  .sec-head .eyebrow::after {
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform calc(0.7s * var(--motion)) cubic-bezier(0.22, 1, 0.36, 1) calc(0.08s * var(--motion));
  }
  .sec-head.in .eyebrow::before,
  .sec-head.in .eyebrow::after { transform: scaleX(1); }

  /* 2. The hero's terminal period snaps in once, after the headline settles */
  .sec--hero h1 .accent-text,
  .page-hero h1 .accent-text {
    display: inline-block;
    transform: scale(0);
    animation: ms-pop calc(0.45s * var(--motion)) cubic-bezier(0.22, 1.5, 0.36, 1) calc(0.5s * var(--motion)) forwards;
  }
  @keyframes ms-pop { to { transform: scale(1); } }


  /* 4. Hairline-grid cells gain a cyan edge that wipes down on hover */
  .cell::before, .course-tile::before {
    content: "";
    position: absolute; left: 0; top: 0; bottom: 0;
    width: 2px; background: var(--cyan);
    transform: scaleY(0); transform-origin: top center;
    transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1);
  }
  .course-tile { position: relative; }
  .cell:hover::before, .course-tile:hover::before { transform: scaleY(1); }
  /* Since v7 (9 Oct 2026) a card that IS a link lifts onto a cyan block
     instead, and this edge beside that block read as a three-sided frame. The
     edge stays for cells that lead nowhere: a quiet hover that promises no
     click, next to a loud one that does. */
  .cell:has(> .arrow-link)::before, .course-tile:has(.arrow-link)::before { display: none; }
  .cell .cell-idx { transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1), color 0.2s ease; }
  .cell:hover .cell-idx { transform: translateY(-2px); color: var(--cyan); }

  /* 5. Ledger stats lift their rule as the numbers count up */
  .stat { transition: border-color calc(0.4s * var(--motion)) ease; }
  .stat.in { border-top-color: var(--line-strong); }

  /* 6. Process step numerals rise slightly into place */
  .step.reveal .step-num { transform: translateY(6px); transition: transform calc(0.6s * var(--motion)) cubic-bezier(0.22, 1, 0.36, 1) calc(0.1s * var(--motion)); }
  .step.reveal.in .step-num { transform: none; }
}

/* ==========================================================================
   FORMS — hand-coded, no third-party iframe.
   These replaced Tally embeds. The old .form-embed had to be a white document
   card because Tally rendered dark text we could not style; owning the markup
   means the form is finally native to the dark canvas, and because every colour
   below is a token, the same form re-tones itself inside .paper for free.
   ========================================================================== */
.form { margin: 0; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 14px; }
/* The label is absolutely positioned inside the control, so the field is one
   box rather than a label row stacked on an input row. That is where most of
   the height saving comes from. */
.field { margin: 0; position: relative; }
.field--full { grid-column: 1 / -1; }
@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }

/* Floating label: reads as placeholder text at rest, rises out of the way once
   the field is focused or filled. Not a real placeholder — that would vanish as
   soon as someone types, losing the question they are answering (WCAG 3.3.2). */
.field > label {
  position: absolute;
  left: 15px;
  top: 14px;
  font-size: var(--t-sm);
  font-weight: 400;
  color: var(--muted);
  pointer-events: none;
  white-space: nowrap;
  max-width: calc(100% - 34px);
  overflow: hidden;
  text-overflow: ellipsis;
  transform-origin: left top;
  transition: transform 0.16s cubic-bezier(0.2, 0.7, 0.3, 1), color 0.16s ease;
}
.field .req { color: var(--cyan); margin-left: 2px; }
.paper .field .req { color: var(--link); }
.field .hint { color: var(--muted); }

/* floated state */
.field input:focus ~ label,
.field input:not(:placeholder-shown) ~ label,
.field textarea:focus ~ label,
.field textarea:not(:placeholder-shown) ~ label,
.field select:focus ~ label,
.field select:required:valid ~ label {
  transform: translateY(-9px) scale(0.78);
}
/* A non-required select is always :valid, so it needs the option check too. */
.field--select:not(:has(option[value=""]:checked)) > label { transform: translateY(-9px) scale(0.78); }
@media (prefers-reduced-motion: reduce) { .field > label { transition: none; } }

.form input[type="text"], .form input[type="email"], .form input[type="tel"],
.form input[type="url"], .form input[type="number"], .form select, .form textarea {
  font: inherit;
  font-size: var(--t-base);
  width: 100%;
  color: var(--heading);
  background: var(--well);
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  /* top padding carries the floated label; bottom stays tight */
  padding: 21px 14px 7px;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.form textarea { min-height: 92px; resize: vertical; line-height: 1.55; padding-top: 24px; }
.form select { appearance: none; cursor: pointer; padding-right: 38px; }
/* caret drawn as a flat mark; no image request, no gradient */
.form .select-wrap { position: relative; }
.form .select-wrap::after {
  content: ""; position: absolute; right: 15px; top: 50%; width: 8px; height: 8px;
  border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
  transform: translateY(-70%) rotate(45deg); pointer-events: none;
}
.form ::placeholder { color: var(--muted); opacity: 1; }
.form input:hover, .form select:hover, .form textarea:hover { border-color: rgba(255,255,255,0.18); }
.paper .form input:hover, .paper .form select:hover, .paper .form textarea:hover { border-color: rgba(11,27,43,0.28); }
.form input:focus-visible, .form select:focus-visible, .form textarea:focus-visible { outline: 2px solid var(--cyan); outline-offset: 1px; border-color: transparent; }
.paper .form input:focus-visible, .paper .form select:focus-visible, .paper .form textarea:focus-visible { outline-color: var(--link); }

/* consent — legally the important control, so it is a real target, not fine print */
.form-consent { grid-column: 1 / -1; display: flex; gap: 11px; align-items: flex-start; cursor: pointer; margin-top: 4px; }
.form-consent input { flex-shrink: 0; width: 18px; height: 18px; margin-top: 2px; accent-color: var(--cyan); cursor: pointer; }
.paper .form-consent input { accent-color: var(--link); }
.form-consent span { font-size: var(--t-sm); color: var(--muted); line-height: 1.55; }
.form-consent a { color: var(--link); }

.form-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 20px; margin-top: 20px; }
.form-foot .btn { margin: 0; }
.form-note { font-size: var(--t-sm); color: var(--muted); margin: 0; max-width: 40ch; }

/* validation + status. Red is the one colour outside the palette; it is
   reserved for errors, never decoration. */
.form [aria-invalid="true"] { border-color: var(--warn); }
.field-error { display: block; margin-top: 4px; font-size: var(--t-micro); color: var(--warn); }
.form-status { margin: 18px 0 0; font-size: var(--t-sm); min-height: 0; }
.form-status[data-state="error"] { color: var(--warn); }
.form-status[data-state="sending"] { color: var(--muted); }
.form.is-sending { opacity: 0.7; pointer-events: none; }

/* success replaces the form outright — a filled-in form left on screen invites
   a second submit and hides the confirmation */
.form-done { border: 1px solid var(--line); border-top: 2px solid var(--cyan); border-radius: var(--radius); background: var(--card); padding: clamp(26px, 4vw, 40px); }
.paper .form-done { border-top-color: var(--link); }
.form-done h3 { margin: 0 0 10px; }
.form-done p { margin: 0; color: var(--body); }

/* honeypot: off-screen, never focusable, never announced */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ==========================================================================
   MARKS — official third-party lockups (EU funding, Meta certification).
   They ship as transparent artwork, so they sit on the canvas directly. The
   old .img--card punched a white slab behind them, which read as a foreign
   object dropped onto the dark page.
   ========================================================================== */
.marks { display: flex; align-items: center; gap: clamp(22px, 4vw, 44px); flex-wrap: wrap; margin: 0; }
.marks img { display: block; height: auto; border: 0; border-radius: 0; }

/* the EU funding notice: legally mandated wording, given a real structure
   instead of a centred slab orphaned at the foot of the page */
.funding { margin-top: clamp(48px, 6vw, 76px); border-top: 1px solid var(--line); padding-top: clamp(28px, 3.5vw, 40px); display: grid; grid-template-columns: minmax(0, 260px) minmax(0, 1fr); gap: clamp(24px, 4vw, 52px); align-items: center; }
.funding img { width: 100%; max-width: 260px; height: auto; display: block; }
.funding p { margin: 0; font-size: var(--t-sm); line-height: 1.65; color: var(--muted); }
.funding p strong { display: block; margin-bottom: 6px; font-size: var(--t-micro); letter-spacing: 0.12em; text-transform: uppercase; color: var(--body); }
@media (max-width: 700px) { .funding { grid-template-columns: 1fr; gap: 24px; } }

/* screenshots are real captures with their own light UI — they get a hairline
   frame so they read as evidence, not as a stray white block */
.img--shot img { border: 1px solid var(--line); border-radius: var(--radius); background: var(--well); padding: 0; width: auto; max-width: 100%; }
/* .flow: a numbered sequence of short labelled steps joined by one hairline
   (AI page example). .mail: a real automated e-mail drawn as page markup on a
   dark card, never a white mail-client slab (the "no white slabs" rule). */
.flow { list-style: none; counter-reset: flow; margin: 0; padding: 0; }
.flow li { counter-increment: flow; position: relative; padding: 0 0 22px 52px; color: var(--body); }
.flow li::before { content: counter(flow, decimal-leading-zero); position: absolute; left: 0; top: 0; width: 34px; height: 34px; display: grid; place-items: center; border: 1px solid var(--line-strong); font-size: var(--t-micro); font-weight: 600; letter-spacing: .06em; color: var(--heading); background: var(--canvas); }
.flow li:not(:last-child)::after { content: ""; position: absolute; left: 17px; top: 34px; bottom: 0; width: 1px; background: var(--line-strong); }
.flow li strong { display: block; color: var(--heading); font-weight: 600; }
.mail { margin: 0; border: 1px solid var(--line); background: var(--card); }
.mail-head { padding: 16px 20px; border-bottom: 1px solid var(--line); }
.mail-head p { margin: 0; display: flex; gap: 14px; font-size: var(--t-sm); color: var(--body); }
.mail-head p + p { margin-top: 6px; }
.mail-head span { min-width: 3.5em; color: var(--muted); }
.mail-head strong { color: var(--heading); font-weight: 600; }
.mail-body { padding: 18px 20px 20px; font-size: var(--t-sm); color: var(--body); }
.mail-body p { margin: 0 0 10px; }
.mail-checks { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 6px; }
.mail-checks li { display: flex; gap: 12px; }
.mail-checks li::before { width: 1.2em; font-weight: 700; text-align: center; }
.mail-checks .bad::before { content: "!"; color: var(--heading); }
.mail-checks .ok::before { content: "+"; color: var(--muted); }
.mail figcaption { padding: 12px 20px; border-top: 1px solid var(--line); font-size: var(--t-sm); color: var(--muted); }
/* a real screenshot says what it shows in one muted line underneath, never as an overlay on the numbers */
.img--shot figcaption { margin-top: 12px; font-size: var(--t-sm); color: var(--muted); max-width: 60ch; }

/* Tables in articles. Two pricing/comparison tables had collapsed into loose
   paragraphs during the WordPress import; rebuilt as real tables by
   tools/rebuild-tables.mjs, they needed styling that did not exist yet.
   Every colour is a token, so the same rules serve the dark canvas and .paper. */
.prose table {
  width: 100%;
  border-collapse: collapse;
  margin: 2em 0;
  font-size: var(--t-sm);
  text-align: left;
}
.prose thead th {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0 14px 10px;
  border-bottom: 1px solid var(--line-strong);
}
.prose tbody td {
  padding: 13px 14px;
  border-bottom: 1px solid var(--line);
  color: var(--body);
  vertical-align: top;
}
.prose tbody tr:last-child td { border-bottom: 0; }
.prose tbody td:first-child { color: var(--heading); font-weight: 500; }
.prose th:first-child, .prose td:first-child { padding-left: 0; }
.prose th:last-child, .prose td:last-child { padding-right: 0; }
/* A table is the one thing in an article allowed to scroll sideways rather
   than force the whole page to. */
.prose .table-scroll { overflow-x: auto; }
@media (max-width: 620px) { .prose table { font-size: var(--t-micro); } }

/* A prompt in a free guide (/materiali/): copied as is, so it keeps its line
   breaks and wraps inside its own box instead of widening the page. */
.prose pre {
  margin: 1.5em 0;
  padding: 18px 20px;
  background: rgba(1, 96, 140, 0.05);
  border: 1px solid var(--line);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--t-sm);
  line-height: 1.55;
  color: var(--body);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.prose pre code { font: inherit; color: inherit; background: none; padding: 0; }

/* ==========================================================================
   HOMEPAGE HERO. The drifting cyan dots (hero-fx.njk, SVG animateMotion) were
   retired on 14 Sep 2026 when the homepage got a pieces motif like every other
   page header - owner: "retire the dots". Git has them if they come back.
   ========================================================================== */
.sec--hero { position: relative; isolation: isolate; overflow: hidden; }
.sec--hero > .container { position: relative; z-index: 1; }

/* ==========================================================================
   PEOPLE — a real face next to copy that names a real person.
   The service pages described human work and showed nobody, which is most of
   why the site read as robotic. These use the actual team photographs; nothing
   here is ever a generated person (see the portraits rule in CLAUDE.md).
   ========================================================================== */
.person { display: flex; align-items: center; gap: 16px; margin: 0 0 22px; }
.person img {
  width: 76px; height: 76px;
  object-fit: cover;
  border: 1px solid var(--line);
  flex-shrink: 0;
  display: block;
}
.person .who strong {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-body);
  color: var(--heading);
  line-height: 1.25;
}
.person .who span {
  display: block;
  margin-top: 3px;
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}
/* several people side by side */
.people { display: flex; flex-wrap: wrap; gap: 14px clamp(24px, 4vw, 44px); margin: 26px 0 0; }
.people .person { margin: 0; }
@media (max-width: 520px) { .people { gap: 18px; } .people .person { width: 100%; } }

/* ---------- additions (2 Sep 2026): consent, blog search, misc ---------- */
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }

/* A button that reads as an inline link (footer "Sīkdatņu iestatījumi"). */
.linkish { background: none; border: 0; padding: 0; margin: 0; font: inherit; color: var(--body); cursor: pointer; }
.linkish:hover { color: #fff; }

/* The services grid has seven cells in three columns; the last one spans the
   row instead of leaving two empty cells. */
.cell--wide { grid-column: 1 / -1; }
/* An incomplete last row exposes the grid's own background - the hairline
   colour - as a grey block. Seen on /video-reklama/ when the actors went from
   six to five (9 Oct 2026). One canvas filler takes the empty slot so it reads
   as an empty ledger cell. Counted per layout: three columns above 980px,
   two between 641 and 980px, none on phones. A last .cell--wide already
   spans its row, so it never needs one. */
@media (min-width: 981px) {
  .hgrid--3:has(> :last-child:nth-child(3n + 2))::after { content: ""; background: var(--cell, var(--canvas)); }
}
@media (min-width: 641px) and (max-width: 980px) {
  .hgrid--3:has(> :last-child:nth-child(2n + 1)):not(:has(> .cell--wide:last-child))::after { content: ""; background: var(--cell, var(--canvas)); }
}

/* Cookie consent - a card in the corner, hairlines only, two equal ghost
   buttons (accepting must not be louder than declining). Rendered only when
   analytics is configured; see base.njk + js/consent.js. */
.consent { position: fixed; left: 20px; right: 20px; bottom: 76px; z-index: 90; max-width: 600px; margin: 0 auto; background: var(--card); border: 1px solid var(--line-strong); padding: 22px 24px; display: grid; gap: 16px; }
@media (min-width: 760px) { .consent { left: 24px; right: auto; bottom: 24px; margin: 0; } }
.consent p { margin: 0; color: var(--body); font-size: var(--t-sm); line-height: 1.55; }
.consent strong { color: var(--heading); }
.consent-actions { display: flex; gap: 10px; flex-wrap: wrap; }

/* Blog index search */
.blog-tools { display: flex; flex-wrap: wrap; gap: 16px 24px; align-items: center; justify-content: space-between; margin-bottom: clamp(32px, 4vw, 48px); }
.blog-search { position: relative; display: block; flex: 1 1 280px; max-width: 440px; }
.blog-search svg { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); color: var(--muted); pointer-events: none; }
.blog-search input { width: 100%; background: var(--well); border: 1px solid var(--line-strong); border-radius: var(--radius); color: #fff; font: inherit; font-size: var(--t-base); padding: 13px 14px 13px 42px; }
.blog-search input::placeholder { color: var(--muted); }
.blog-search input:focus { outline: 2px solid var(--cyan); outline-offset: 2px; border-color: var(--line-hover); }
.blog-count { margin: 0; color: var(--muted); font-size: var(--t-sm); }
.blog-empty { margin: 0; padding: clamp(32px, 4vw, 48px); border: 1px solid var(--line); color: var(--muted); text-align: center; }
/* While a search is active the featured (first) card falls back to a plain card. */
.post-grid--featured.is-filtered > .post-card { grid-column: auto; }

/* Long-form legal text without the article sidebars. */
.article-body--solo { max-width: 68ch; }

/* Floating WhatsApp entry point. Owner (2 Sep 2026): cyan fill so it sticks
   out - the one deliberate exception to "one cyan CTA per viewport". Styled
   exactly like .btn: cyan fill, canvas-dark glyph and label, flat hover,
   square, no glow. Icon + label on desktop, icon only on phones;
   back-to-top stacks above it. */
.wa-float { position: fixed; right: 22px; bottom: 22px; z-index: 71; display: inline-flex; align-items: center; gap: 10px; height: 48px; padding: 0 16px 0 14px; background: var(--cyan); color: var(--canvas); border: 1px solid var(--cyan); border-radius: 0; font-family: var(--font-display); font-weight: 600; font-size: var(--t-sm); letter-spacing: 0.01em; text-decoration: none; transition: background 0.2s ease, border-color 0.2s ease, translate 0.3s var(--ease-spring), box-shadow 0.3s var(--ease-spring); }
.wa-float:hover { background: var(--cyan-hover); border-color: var(--cyan-hover); color: var(--canvas); text-decoration: none; translate: -3px -3px; box-shadow: 3px 3px 0 #fff; }
.wa-float:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.wa-float svg { flex-shrink: 0; }
@media (max-width: 640px) {
  .wa-float { right: 14px; bottom: 14px; width: 48px; padding: 0; justify-content: center; }
  .wa-float-label { display: none; }
}
/* ---------- lead magnet (automated page check) ---------- */
/* Sits ABOVE the consent card (z 90) because it can only open once that card
   is gone. Square, hairline, one cyan button: same ledger language as the
   rest, so it reads as part of the site rather than a bought-in widget. */
/* The automation quiz (/automatizacijas-tests/, 11 Oct 2026). Without JS
   every question shows as a fieldset; quiz.js adds .is-stepped and shows one
   at a time. Answers are full-width rows; the picked one gets a stronger
   border and the inset well, not cyan - cyan stays for the one button. */
.quiz-wrap { max-width: 760px; }
.quiz-progress { height: 3px; background: var(--line); margin-bottom: 14px; }
.quiz-progress span { display: block; height: 100%; width: 0; background: var(--cyan); transition: width 0.3s var(--ease-out); }
.quiz:not(.is-stepped) .quiz-progress, .quiz:not(.is-stepped) .quiz-nav { display: none; }
.quiz-count { margin: 0 0 18px; font-size: var(--t-micro); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); min-height: 1.4em; }
.quiz-step { border: 0; padding: 0; margin: 0 0 40px; min-width: 0; }
.quiz.is-stepped .quiz-step { margin-bottom: 24px; }
.quiz-step legend { padding: 0; margin-bottom: 20px; font-family: var(--font-display, inherit); font-size: var(--t-d1); font-weight: 600; color: var(--heading); line-height: 1.25; }
.quiz-idx { display: block; margin-bottom: 10px; font-size: var(--t-micro); letter-spacing: .08em; color: var(--muted); font-weight: 500; }
.quiz-opt { display: flex; align-items: center; gap: 14px; padding: 16px 18px; border: 1px solid var(--line-strong); margin-bottom: 10px; cursor: pointer; color: var(--body); transition: border-color 0.15s ease, background 0.15s ease; }
.quiz-opt:hover { border-color: var(--muted); }
.quiz-opt:has(input:checked) { border-color: var(--heading); background: var(--well); color: var(--heading); }
.quiz-opt input { width: 18px; height: 18px; margin: 0; accent-color: var(--cyan); flex: none; }
.quiz-nav { min-height: 44px; }
.quiz.is-stepped .quiz-idx { display: none; } /* the count above already says "3 no 9" */
.quiz-result h2 { margin: 12px 0 24px; }
.quiz-result h3 { margin: 40px 0 18px; }
/* The scorecard: one hairline row per area, a three-square meter (full = in
   order) and the level in words. White and grey only - no cyan here. */
.quiz-score { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line-strong); }
.quiz-score li { display: grid; grid-template-columns: 1fr auto 9.5em; align-items: center; gap: 18px; padding: 14px 0; border-bottom: 1px solid var(--line-strong); }
.qs-name { color: var(--heading); font-weight: 500; }
.qs-meter { display: inline-flex; gap: 4px; }
.qs-meter i { width: 14px; height: 14px; border: 1px solid var(--muted); }
.lv-0 .qs-meter i, .lv-1 .qs-meter i:nth-child(-n+2), .lv-2 .qs-meter i:first-child { background: var(--heading); border-color: var(--heading); }
.qs-level { color: var(--muted); }
.lv-2 .qs-level { color: var(--heading); font-weight: 600; }
.quiz-top { margin: 0 0 24px; padding-left: 1.4em; color: var(--body); }
.quiz-top li { margin-bottom: 26px; }
.quiz-top strong { display: block; margin-bottom: 8px; color: var(--heading); font-size: var(--t-lead); }
.quiz-top p { margin: 0 0 8px; }
.qt-label { display: block; font-size: var(--t-micro); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
@media (max-width: 560px) {
  .quiz-score li { grid-template-columns: 1fr auto; row-gap: 6px; }
  .qs-level { grid-column: 1 / -1; }
}
/* The AI step under the result: a website and an e-mail, then a wait that
   says what is happening (10-30 s), then three suggestions. */
.quiz-ai { margin-top: clamp(40px, 5vw, 64px); padding-top: clamp(32px, 4vw, 48px); border-top: 1px solid var(--line-strong); }
.quiz-ai > h3 { margin: 0 0 10px; }
.quiz-ai > p { margin: 0 0 24px; max-width: 60ch; }
.quiz-ai-form { display: grid; gap: 16px; max-width: 560px; }
.quiz-ai-form .btn { justify-self: start; }
.quiz-ai-form .fine { margin: 0; }
.quiz-ai-out:empty { display: none; }
.quiz-ai-lapa { margin: 12px 0 28px; font-size: var(--t-lead); line-height: 1.5; color: var(--heading); }
.quiz-wait { max-width: 560px; }
.quiz-wait p { margin: 14px 0 0; color: var(--muted); }
.quiz-wait-bar { display: block; position: relative; height: 3px; background: var(--line); overflow: hidden; }
.quiz-wait-bar::after { content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 30%; background: var(--cyan); animation: quiz-wait 1.4s var(--ease-out) infinite; }
@keyframes quiz-wait { from { transform: translateX(-100%); } to { transform: translateX(340%); } }
@media (prefers-reduced-motion: reduce) { .quiz-wait-bar::after { animation: none; width: 100%; } }
/* The popup is an invitation to the quiz now, not a form. */
.lm-panel .btn-wrap { margin-top: 26px; }

.lm { position: fixed; inset: 0; z-index: 200; background: rgba(2, 13, 28, .82); display: grid; place-items: center; padding: 20px; overflow-y: auto; }
.lm-panel { position: relative; width: 100%; max-width: 620px; background: var(--card); border: 1px solid var(--line-strong); padding: clamp(24px, 4vw, 44px); }
.lm-panel::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 2px; background: var(--cyan); }
.lm-panel h2 { font-size: var(--t-d2); margin: 10px 0 0; }
.lm-panel h3 { margin: 0 0 6px; }
.lm-sub { color: var(--muted); font-size: var(--t-sm); margin: 12px 0 0; }
.lm-close { position: absolute; top: 10px; right: 12px; background: none; border: 0; color: var(--muted); font-size: var(--t-d1); line-height: 1; cursor: pointer; padding: 6px 10px; }
.lm-close:hover { color: var(--heading); }
.lm-form { display: grid; gap: 16px; margin-top: 22px; }
.lm-form .btn { justify-self: start; }
.lm-fine { color: var(--muted); font-size: var(--t-micro); margin: 0; }
.lm-next { margin: 20px 0 22px; font-size: var(--t-sm); color: var(--body); }
/* A bottom sheet, NOT a full-screen takeover. This rule used to stretch the
   panel to min-height:100%, which covered the article edge to edge and read as
   an interstitial - the exact pattern Google treats as a mobile ranking problem
   and the reason the popup is delayed and scroll-gated in the first place.
   Leaving the page visible above the sheet is what makes it a dialog.
   svh, not vh: vh on a phone measures the viewport WITHOUT browser chrome, so
   88vh still pushed the button under Chrome's toolbar. */
@media (max-width: 560px) {
  .lm { padding: 0; place-items: end stretch; overflow: hidden; }
  .lm-panel {
    max-width: none;
    max-height: 88vh;
    max-height: 88svh;
    overflow-y: auto;
    padding: 26px 20px 22px;
  }
}

@media print { .wa-float, .to-top, .consent { display: none; } }

/* ---------- in-article infographic: generated text-free artwork + HTML legend ---------- */
/* The card colour is a TOKEN, not #fff: inside .paper it resolves to white for
   articles, on the dark marketing pages it resolves to #00152c. Hard-coding
   white punched a light slab into the dark canvas - the same artifact
   `.img--card` was deleted for. */
/* The figure sits flush on the page, so its ground must equal the page ground -
   on paper that is white, on the dark canvas it is the card colour. Using --card
   everywhere left a tinted rim around a white-ground image on articles. */
/* Column figures (9 Sep 2026). These replace the "dark-info" rasters, whose
   Latvian labels were baked into pixels - unreadable at ~9px on a phone, at
   risk of a misspelling no spellcheck could catch, and invisible to search.
   Text is real HTML now and the diagrams are inline SVG that animates. No
   frame and no fill: same ground as the page, like the hero motifs. */
.figcols { margin: clamp(28px, 3.5vw, 48px) 0 0; }
.figcols-h { font-size: var(--t-d2); margin: 0 0 clamp(24px, 3vw, 36px); }
/* Every column carries the same padding so the content boxes are equal and the
   SVGs render at identical heights - dropping it on the first column made that
   one 31px taller and knocked its diagram and footer out of line. The grid is
   pulled left by the same amount instead, so column one still sits flush with
   the heading above it. */
.figcols { --figpad: clamp(20px, 2.4vw, 34px); }
.figcols-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(24px, 3vw, 44px); margin-left: calc(-1 * var(--figpad)); }
.figcol { position: relative; padding-left: var(--figpad); border-left: 1px solid var(--line); display: flex; flex-direction: column; }
.figcol:first-child { border-left: 0; }
.figcol-idx { font-family: var(--font-display); font-weight: 600; font-size: var(--t-base); color: var(--cyan); letter-spacing: .06em; display: flex; align-items: center; gap: 12px; }
.figcol-idx::after { content: ""; height: 1px; flex: 1; background: var(--line-strong); }
/* Two lines reserved for the title as well as the description. On a narrow
   column - the course pages put this figure beside a sticky sidebar - one
   title wraps and the others do not, which pushed that column's diagram and
   footer 33px out of line with its neighbours. */
.figcol h4 { font-size: var(--t-d1); margin: 0 0 6px; color: var(--heading); min-height: 2.6em; }
/* Two lines reserved: one column's description wraps and the others do not,
   which pushed its diagram and footer out of line with its neighbours. */
.figcol > p { margin: 0 0 22px; color: var(--muted); font-size: var(--t-sm); line-height: 1.5; min-height: 3em; }
/* An icon, not a diagram: one solid mark per item, sized so the column reads
   as text with a marker rather than as a picture with a caption. */
.figcol-icon { width: clamp(60px, 6vw, 76px); height: auto; margin: 20px 0 22px; }
/* The closing note is a separate beat, not the next line of the description.
   margin-top:auto bottom-aligns it across columns; the padding and hairline
   are what stop it reading as a runaway third sentence. */
.figcol-foot { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--line); color: var(--muted); font-size: var(--t-micro); letter-spacing: .04em; }
@media (max-width: 780px) {
  .figcols-grid { grid-template-columns: 1fr; gap: 32px; }
  .figcols-grid { margin-left: 0; }
  .figcol { padding-left: 0; border-left: 0; border-top: 1px solid var(--line); padding-top: 24px; }
  .figcol:first-child { border-top: 0; padding-top: 0; }
}

.infographic { margin: 2.4em 0; border: 1px solid var(--line); background: var(--canvas); }
.infographic > img { display: block; width: 100%; height: auto; margin: 0; border: 0; border-bottom: 1px solid var(--line); }
.infographic--page { margin: clamp(28px, 3vw, 40px) 0 0; }
.infographic--page .infographic-list li { position: relative; padding-left: 34px; margin: 0; font-size: var(--t-sm); line-height: 1.5; color: var(--body); counter-increment: ig; }
.article-body .prose .infographic > img { display: block; width: 100%; height: auto; margin: 0; border: 0; border-bottom: 1px solid var(--line); border-radius: 0; }
.infographic figcaption { padding: 12px clamp(16px, 2.5vw, 24px); }
.infographic-text > summary { cursor: pointer; list-style: none; font-size: var(--t-sm); color: var(--muted); display: flex; align-items: center; gap: 8px; }
.infographic-text > summary::-webkit-details-marker { display: none; }
.infographic-text > summary::before { content: ""; width: 6px; height: 6px; border-right: 1px solid currentColor; border-bottom: 1px solid currentColor; transform: rotate(-45deg); transition: transform 0.15s ease; }
.infographic-text[open] > summary::before { transform: rotate(45deg); }
.infographic-text > summary:hover { color: var(--heading); }
.infographic-text[open] > summary { margin-bottom: 14px; }
.infographic-list { list-style: none; margin: 0; padding: 0; counter-reset: ig; display: grid; gap: 12px 24px; }
@media (min-width: 560px) { .infographic-list { grid-template-columns: 1fr 1fr; } }
.article-body .prose .infographic-list li { counter-increment: ig; position: relative; padding-left: 34px; margin: 0; font-size: var(--t-sm); line-height: 1.5; color: var(--body); }
.infographic-list li::before { content: counter(ig, decimal-leading-zero); position: absolute; left: 0; top: 3px; font-family: var(--font-display); font-weight: 600; font-size: var(--t-micro); letter-spacing: 0.08em; color: var(--tick); }
.infographic-list strong { display: block; color: var(--heading); font-weight: 600; margin-bottom: 2px; }

/* On phones the baked-in labels are ~9px, so the text version leads and the
   picture supports it. main.js opens the details; this makes the open state
   read like a caption rather than an expanded widget. */
@media (max-width: 700px) {
  .infographic-text[open] > summary { color: var(--heading); font-weight: 600; }
  .infographic-list { gap: 14px; }
}
/* ---------- homepage hero on phones (3 Sep 2026) ----------
   Above the fold at 390x844 used to be: a two-line topbar, 96px of hero
   padding, headline, two stacked buttons and the top edge of a 340px stats
   card. Now: one-line topbar (e-mail hidden, it is in the footer and the
   WhatsApp float), tighter padding, and the stats as three compact ledger
   rows so the client-logo strip reaches the first screen. */
@media (max-width: 640px) {
  /* The e-mail stays (owner: always visible). The social marks are what give
     up the room - they are in the footer too, and the phone and the address
     are what a phone-sized visitor actually taps. */
  :root { --topbar-h: 36px; }
  .topbar { font-size: var(--t-micro); }
  .topbar-social { display: none; }
  .topbar-inner { justify-content: flex-start; }
  .topbar-contacts { gap: 12px; width: 100%; justify-content: space-between; }
  .topbar-contacts a + a { padding-left: 12px; }
}
@media (max-width: 980px) {
  .sec--hero { padding-top: clamp(40px, 6vw, 64px); }
  .sec--hero .btn-wrap { gap: 10px; }
  .hero-grid { gap: 20px; }
  .sec--hero .btn-wrap { margin-top: 22px; }
  /* Dropped on phones: the logo strip reaching the first screen at 390x844
     (3 Sep 2026) is worth more than the artwork there. */
  .hero-grid > .hero-media { display: none; }
  .hero-stats { margin-top: 20px; }
  .hero-grid .panel { padding: 6px 20px; }
  .hero-grid .stats, .hero-stats .stats { display: flex; flex-direction: column; gap: 0; }
  .hero-grid .stat, .hero-stats .stat { display: flex; flex: none; align-items: baseline; gap: 14px; padding: 12px 0; border-top: 1px solid var(--line); }
  .hero-grid .stat:first-child, .hero-stats .stat:first-child { border-top: 0; padding-top: 12px; }
  .hero-grid .stat .num, .hero-stats .stat .num { font-size: var(--t-d2); flex: 0 0 auto; min-width: 4.2ch; }
  .hero-grid .stat .label, .hero-stats .stat .label { margin-top: 0; letter-spacing: 0.06em; line-height: 1.35; }
  .logo-strip { margin-top: 16px; padding: 16px 0 22px; }
  .logo-strip .caption { margin-bottom: 14px; }
}

/* ---------- service tiles with imagery ----------
   .cell--media puts a picture across the top of a ledger cell; the index
   sits on the picture in a small canvas-coloured box so it stays legible. */
.cell--media { padding-top: 0; }
.cell-media { position: relative; margin: 0 calc(-1 * var(--card-pad)) 22px; aspect-ratio: 16 / 10; overflow: hidden; background: var(--card); border-bottom: 1px solid var(--line); }
.cell-media img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: var(--focus, center); }
.cell--media .cell-idx { top: 14px; right: 14px; background: var(--canvas); padding: 5px 8px; line-height: 1; z-index: 1; }
.cell--wide.cell--media { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); column-gap: var(--card-pad); padding-top: var(--card-pad); }
.cell--wide.cell--media .cell-media { grid-row: 1 / 5; margin: calc(-1 * var(--card-pad)) 0 calc(-1 * var(--card-pad)) calc(-1 * var(--card-pad)); aspect-ratio: auto; border-bottom: 0; border-right: 1px solid var(--line); min-height: 220px; }
.cell--wide.cell--media .cell-idx { top: var(--card-pad); right: var(--card-pad); background: none; padding: 0; }
@media (max-width: 640px) { .cell--wide.cell--media { display: flex; padding-top: 0; } .cell--wide.cell--media .cell-media { margin: 0 calc(-1 * var(--card-pad)) 22px; aspect-ratio: 16 / 10; border-right: 0; border-bottom: 1px solid var(--line); min-height: 0; } .cell--wide.cell--media .cell-idx { top: 14px; right: 14px; background: var(--canvas); padding: 5px 8px; } }

/* Course tiles carry the same picture treatment as the ledger service cells. */
.course-tile--media { padding-top: 0; }
.course-tile--media .cell-media { margin-bottom: 22px; }
/* A tile holding a motif rather than a photograph: the drawing sets the height
   instead of being cropped to 16:10, and there is no card fill behind it - the
   artwork already sits on the page ground. All three course motifs share one
   viewBox, so the tiles still line up. */
.cell-media.cell-media--motif { aspect-ratio: auto; background: none; overflow: visible; }
.cell-media.cell-media--motif .motif { display: block; width: 100%; height: auto; }
/* A full-width motif band under a page hero. Wider than .media--wide so it
   reads as a divider rather than as an illustration inside a column. */
.media--band { aspect-ratio: 24 / 7; margin-bottom: clamp(44px, 5vw, 72px); }
@media (max-width: 640px) { .media--band { aspect-ratio: 16 / 9; } }

/* ==========================================================================
   LEAD-MAGNET GATE (13 Oct 2026) — a guide post opens its copyable part after
   an e-mail sign-up. post.njk splits the article; forms.js and an inline
   check in post.njk add .gids-open (content shown) and, for a returning
   subscriber, .gids-known (gate hidden). Without JS the noscript rule shows
   everything, because the form cannot be sent anyway.
   ========================================================================== */
.gated { display: none; }
.gids-open .gated { display: block; }
.gids-known .gate,
.gids-open .gate-intro { display: none; }
.gate { margin: 2.5em 0; }
.gate h3 { margin: 0 0 10px; }
.gate .tick-list { margin: 14px 0 22px; }
.gate .form-done { margin: 0; border: 0; padding: 0; background: none; }
