/* ===========================================================================
   si-components.css -- the SIAssist component layer
   ---------------------------------------------------------------------------
   Prefix `si-`. Beside is-components.css, not on top of it: the two share
   Bootstrap and nothing else (ADR-0009). Where a solution from the Innovation
   Scout fits, it is taken over because it is good -- never because it has to
   be shared.

   Source: agent_docs/design/si/si-fundament.md and the mockup under
   agent_docs/mockups/. Every value here is one of those two; no number is
   invented (ADR-0010).

   Sections
     1. Tokens
     2. The page ground and the type scale
     3. Spacing
     4. Scroll-in
     5. Components -- B2 si-statement
   =========================================================================== */

/* --- 1. Tokens ------------------------------------------------------------
   Taken from the mockup's :root, reduced to what is in use. The dark palette
   the mockup carries is deliberately NOT here: no night mode (Michael,
   2026-09-01), every colour is set exactly once. */
.si-page {
  /* The old site sets body{line-height:1.7; letter-spacing:.01em} and it reaches
     straight through here. Every line of the new pages was 6% taller and each
     character .16px wider than the mockup, which is a good part of what Michael
     described as "the mockup's type is finer" (konzept-siassist measured it in
     the rendered mockup, 2026-09-08). This is the counterpart to the mockup's
     own .si rule; it stays inside the new layer and leaves the old header and
     footer alone, and it corrects some fifteen single values at once. */
  line-height: 1.6;
  letter-spacing: normal;
  --si-bg:        #F7F8F6;
  --si-surface:   #FFFFFF;
  --si-panel:     #2F3E3A;
  /* The panel's own inks. They were rgba() literals spread over seven rules,
     and that is how an opaque colour turns translucent without anyone noticing:
     the heading sat at .92 and the partner name at .72, so the name of the firm
     carried the same ink as the sentence under it (konzept-siassist,
     2026-09-02). Named once, they can only be wrong in one place. */
  --si-panel-ink:    #EAEFEC;
  --si-panel-ink-70: rgba(234, 239, 236, .72);
  --si-panel-line:   rgba(255, 255, 255, .14);

  --si-ink:       #2F3E3A;
  --si-ink-70:    #5E6D68;
  --si-ink-45:    #8A9793;

  --si-line:      rgba(47, 62, 58, .12);
  --si-line-soft: rgba(47, 62, 58, .07);

  /* The gold wash: the ground the "In Entwicklung" mark stands on. Values from
     the mockup's light set -- it carries a dark one too, and we have no night
     mode, so only these three exist here.

     There is no --si-gold-wash-ink, although the delivery names one: its value
     is #5C4A08, which is --si-gold-ink to the byte. A second name for a colour
     we already have is the second truth this sheet keeps taking out. */
  --si-gold-wash:      #FDF4DC;
  --si-gold-wash-line: rgba(244, 180, 0, .4);

  /* Ink at 4.5% -- the ground of a tag and of a framed box (si-fundament.md
     § "si-tag"). Named in the foundation since 2026-09-01 and never added,
     because the home page has neither. The sub-pages have both. */
  --si-fill:      rgba(47, 62, 58, .045);

  /* The ground the solutions section stands on -- it is a field of its own in
     the mockup, not flush with the page. */
  --si-sol-band:  rgba(255, 255, 255, .62);

  /* Sign colours. They never carry text -- see the ink variants below. */
  --si-gold:      #F4B400;
  --si-terra:     #C85A2E;
  --si-ana:       #42796A;
  --si-dec:       #3A6A8C;

  /* The ink variants. Measured on white: gold 1.85:1 and terracotta 4.24:1 are
     both under the 4.5 floor, ana 5.03:1 and dec 5.80:1 pass -- but a group
     colour that sometimes carries text and sometimes does not is two rules, so
     text always takes the ink variant (si-fundament.md, section 4).

     Terracotta had no ink variant, which is the gap the rule itself left: it
     was the one mark whose raw value still carried type, and on the section
     ground that came to 3.98:1 (konzept-siassist, 2026-09-01). The raw #C85A2E
     stays a sign colour -- nodes, hexagons, numbers. */
  --si-gold-ink:  #5C4A08;
  --si-terra-ink: #B85028;
  --si-ana-ink:   #2B5347;
  --si-dec-ink:   #254F6B;
  --si-gold-on:   #3A2E05;   /* type ON gold */

  /* --- The type scale: the mockup's own ladder ---------------------------
     This used to be four values, on the reasoning that a small vocabulary is
     easier to keep. It was the wrong four: every size that got "put on the
     nearest declared step" flattened the page a little, and by the end all
     eight h2 were the same size where the mockup steps down section by section
     (Michael found it in the first screen; konzept-siassist, 2026-09-02).

     So the mockup's ladder IS the ladder. The guard did not get weaker -- it
     now guards the right rungs. Heading sizes are clamps and live with their
     section; these are the fixed steps below them. */
  --si-t-badge: .66rem;   /* 10.6 -- the DEMNAECHST badge  */
  --si-t-soon:  .70rem;   /* 11.2 -- the In-Entwicklung mark */
  --si-t-lead:  1.1875rem;/* 19.0 -- a section's lead; the mockup lets it
                             inherit its own 19px base, we have 16 */
  --si-t-note:  .95rem;   /* 15.2 -- the note under a grid, and the
                             closing line of the numbered section */
  --si-t-who:   .80rem;   /* 12.8 -- the partner line in a tile */
  --si-t-go:    .82rem;   /* 13.1 -- the way onward        */
  --si-t-micro: .72rem;   /* 11.5 -- eyebrow, stage, count */
  --si-t-tag:   .76rem;   /* 12.2 -- tag                   */
  --si-t-chip:  .86rem;   /* 13.8 -- filter chip           */
  --si-t-link:  .92rem;   /* 14.7 -- text link, role, who  */
  --si-t-btn:   .95rem;   /* 15.2 -- button                */
  --si-t-tile:  .97rem;   /* 15.5 -- tile body             */
  --si-t-body:  .98rem;   /* 15.7 -- card body, topic row  */
  --si-t-quote: 1.06rem;  /* 17.0 -- the statement's text  */
  --si-t-q:     1.14rem;  /* 18.2 -- card question         */
  --si-t-logo:  1.08rem;  /* 17.3 -- partner name          */
  --si-t-name:  1.16rem;  /* 18.6 -- card org              */
  --si-t-card:  1.2rem;   /* 19.2 -- tile and panel heads  */
  /* ONE size per heading level, across every section and every page kind --
     Michael, 2026-09-08: "vereinheitliche alle ueberschriftsgroessen im
     siassist css, egal was das mockup sagt". The mockup steps h2 through six
     values (45.6 / 41.6 / 38.4 / 34.4 / 32.8 / 31.2 / 30.4) and we matched it
     to the decimal; the jumps are what he saw, and they do not descend -- the
     second section is LARGER than the first. Two rungs replace all nine.

     The levels stay apart: h1 and h2 are one size EACH, not one size TOGETHER.
     Collapsing those two would leave the pages without a hierarchy at all. */
  --si-h1:      clamp(2rem, 4.4vw, 3.15rem);   /* 50.4 -- every h1 */
  --si-h2:      clamp(1.7rem, 3.2vw, 2.4rem);  /* 38.4 -- every h2 */
  --si-t-num:   1.6rem;   /* 25.6 -- the figure on a partner fact card;
                             the one size above --si-t-card, and the only
                             one on the ladder that is a display number */

  /* One source, two readers: the node row is this tall, and the rail lies at
     half of it. Written as a number in both places they drift the moment a chip
     inside the row grows -- measured, the row came out 28.4px and the rail sat
     2px above the dots. */
  --si-node-h: 26px;

  /* The air above the station row -- read twice, see .si-flow__steps. */
  --si-steps-pad: 3.75rem;

  /* The mockup's --shadow, one value for every raised surface. It was not a
     token here, and konzept-siassist said it was not worth a round of its own
     -- it is not getting one: a token and three uses, inside a round that was
     already open. */
  --si-shadow: 0 18px 40px -22px rgba(47, 62, 58, .22);

  --si-radius:    6px;
  --si-radius-lg: 12px;

  /* --- 3. Spacing: five steps, all multiples of 8 (si-fundament.md § 3) --- */
  --si-space-section: 6rem;    /* 96px -- between two sections */
  --si-space-xl:      3rem;    /* 48px -- head to content   */
  --si-space-l:       2rem;    /* 32px -- between blocks    */
  --si-space-m:       1rem;    /* 16px -- between elements  */
  --si-head-gap:      1.5rem;  /* 24px -- inside a head group: eyebrow, heading, lead */
  --si-gutter:        1.5rem;  /* 24px -- half of the g-5 row gutter; see .si-sec > .container */
  --si-space-s:       .5rem;   /*  8px -- inside an element */

  /* --- 2. The page ground ------------------------------------------------
     One number this sheet sets, and the only one: the base size. cms_core.css
     puts --bs-body-font-size at 1.25rem site-wide, and everything below a
     heading scales off it. The Scout solves the same thing with
     `.is-page { font-size: .875rem }` -- same shape, different value.

     Headings are NOT set here. They are Bootstrap's own (display-3 … h4),
     which compute with the viewport. That they do not render that way yet is
     cms_core.css:129-133, and tidying that sheet is its own round (ADR-0010).

     Ground and tokens share one rule on purpose: `.si-page` written twice is a
     second place to look, and the guard test caught exactly that. */
  font-size: 1rem;
  color: var(--si-ink);
  background: var(--si-bg);
}

/* The heading rule, and it is two corrections in one line. The weight was two
   steps too heavy (500 against 300) and the tracking ran the WRONG WAY: the
   mockup pulls the letters together, ours pushed them apart at +0.16px. That
   pair is what "the type in the mockup is finer" means (Michael, 2026-09-02).
   InterVariable carries wght 100..900, so 300 is really there -- read out of
   the font file, not assumed. */
.si-page :is(h1, h2, h3, h4) {
  margin: 0;
  font-weight: 300;
  letter-spacing: -.02em;
  line-height: 1.08;
  text-wrap: balance;
}

.si-page p { color: var(--si-ink-70); }

/* The line above a heading: uppercase, wide, quiet. `.small` is Bootstrap's
   own third text size -- .72rem in the mockup is not a step of anything. */
/* The size was the one property this rule did not set, so the `small` class the
   plugin carries won and the eyebrow came out 14px against the mockup's 11.5.
   Next to the stage name -- the same line of type, now 11.52 -- it showed
   (konzept-siassist, 2026-09-02). */
.si-eyebrow {
  font-size: var(--si-t-micro);
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--si-ink-45);
  /* The head group -- eyebrow, heading, lead -- sits on ONE gap, and it is
     1.5rem rather than the mockup's 1.1rem: Michael asked for text to have air
     against a heading and against a differently-set element (2026-09-08). That
     is a departure from the reference and it is deliberate; konzept-siassist
     measured 17.6 there and it stays reported, not silently kept.

     Before either value there was 0 between eyebrow and heading and Bootstrap's
     8px between heading and lead, which read as a heading with a caption stuck
     to it. Written as margins rather than a grid because the three are plugins
     of their own and no element wraps them. */
  margin: 0 0 var(--si-head-gap);
}

/* --- 3. Spacing -----------------------------------------------------------
   A section carries its air as PADDING, never as margin: the plugins these
   components are built from always emit their own spacing utility, and
   Bootstrap hangs !important on it -- a margin set here would be dead on
   arrival. The Scout learned that with a guard test; here it is designed in.

   Between two elements the gap belongs to the container, not to the child. */
.si-sec { padding-block: var(--si-space-section); }

/* Every section carries its OWN top and bottom padding, and the two add up
   between neighbours. There used to be a `.si-sec + .si-sec { padding-top: 0 }`
   here, from the delivery's "not 6rem on 6rem" -- it was simply wrong: the
   mockup wants the sum, and the sum is the breath of the page. Between hero and
   statement that is 96 + 88 = 184px where we had 96 (Michael, 2026-09-02).

   The partner band already needed an exception from that rule; the exception
   was the symptom.

   The nine values are the mockup's own clamps, resolving at >=1240px to
   112/96 - 88 - 104 - 104 - 88 - 88 - 72 - 88 - 88/96. */
.si-hero         { padding: clamp(3.5rem, 9vw, 7rem) 0 clamp(3.5rem, 8vw, 6rem); }
.si-statement    { padding-block: clamp(3rem, 7vw, 5.5rem); }
.si-flow         { padding-block: clamp(3.5rem, 8vw, 6.5rem); }
.si-tiles        { padding-block: clamp(3.5rem, 8vw, 6.5rem); }
.si-split--num   { padding-block: clamp(3.5rem, 7vw, 5.5rem); }
/* The one section the mockup rules off from the one above it. */
.si-split--bar   { padding-block: clamp(3.5rem, 7vw, 5.5rem); border-top: 1px solid var(--si-line-soft); }
.si-split--check { padding-block: clamp(3.5rem, 7vw, 5.5rem); }
.si-partners     { padding-block: clamp(3rem, 6vw, 4.5rem); }
.si-cta          { padding: clamp(3.5rem, 7vw, 5.5rem) 0 clamp(4rem, 8vw, 6rem); }

/* --- 4. Scroll-in (si-fundament.md § 7) -----------------------------------
   Decided for every page in the new style, not for the home page alone.

     .si-fx   above the fold -- pure CSS, paints in the first frame
     .si-rv   below it -- observer-driven, hidden only when JS can reveal it

   Two fallbacks are mandatory and both are here: without JavaScript nothing is
   ever hidden (the .si-js gate), and prefers-reduced-motion drops the movement
   rather than the content. Stagger runs through --i, 80ms a step. */
@media (prefers-reduced-motion: no-preference) {
  .si-fx {
    animation: si-rise .7s var(--si-ease, cubic-bezier(.16, 1, .3, 1)) both;
    animation-delay: calc(var(--i, 0) * 80ms);
  }
  .si-js .si-rv {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity .7s cubic-bezier(.16, 1, .3, 1), transform .7s cubic-bezier(.16, 1, .3, 1);
    transition-delay: calc(var(--i, 0) * 80ms);
  }
  .si-js .si-rv.si-rv--in { opacity: 1; transform: none; }
}

@keyframes si-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* --- 5. Components --------------------------------------------------------

   B2 si-statement -- heading left, two paragraphs right.

   The first section built, and deliberately the smallest: it forces the ladder,
   the spacing, the colours, the scroll-in, the template and the build path
   through without any of its own difficulty (2026-09-01).

   The mockup's grid is .92fr / 1.08fr. Bootstrap's twelve columns give 5/7 --
   0.833/1.167 against 0.852/1.148 of the mockup at the same gap. Close enough
   that the difference is invisible, and it costs no track definition of our
   own. Below lg the two stack, which the mockup does at 900px. */
.si-statement__body {
  display: grid;
  gap: 1.1rem;
  font-size: var(--si-t-quote);
}

.si-statement__body p { margin: 0; }
/* One rule for the whole style, not one per section: the same role carried 600
   in the statement and Bootstrap's 700 in the closing line, and in the closing
   line it also stayed on --si-ink-70 where the mockup darkens it. 500 and
   --si-ink, as the mockup has it in both places (konzept-siassist, 2026-09-01
   -- it belongs to the fundament, so it is written here at page level and not
   at a section's). */
.si-page strong { font-weight: 500; color: var(--si-ink); }

/* B1 si-hero -- opener. Text left, artwork right, logo row beneath.
   The mockup's 1.18fr/.82fr is Bootstrap's 7/5. */
/* The hero is the one place that computes its own heading size. Everywhere else
   the scale is Bootstrap's (ADR-0010); here the mockup asks for 2.35rem to 4rem
   with the viewport, and at 40px -- Bootstrap's h1 -- the opener stopped reading
   as one. Named as the exception it is, so nobody takes it for the rule. */
/* .si-sec sets `padding: 6rem 0` and thereby zeroes the horizontal padding a
   Bootstrap .container brings along. On a full-width ground that class sits on
   the ground itself, so the container inside keeps its 12px and insets that
   section's content against all the others. Zero it for every ground -- the
   selector only matches where a .container is a direct child of a .si-sec,
   which is exactly what _ground builds. */
.si-sec > .container,
.si-sec.container,
.si-psec,
.si-close,
.si-crumb__track {
  padding-inline: var(--si-gutter);
}

/* Header and footer come from the existing site and are shared with the old
   pages -- but THIS SHEET is loaded only by siassist_base.html, so a rule here
   reaches the old pages not at all. That is why the alignment is done in CSS and
   not by overriding the navbar block: overriding would mean copying base.html's
   markup into the si template, and a copy goes stale.

   Without it there were three edges on one page -- logo 52, content 64, footer
   52 (konzept-siassist, 2026-09-08). The mockup runs all three on one.

   The value is a LITERAL and not var(--si-gutter): the tokens are declared on
   .si-page, and these two elements sit outside it, so the variable is undefined
   there and the whole declaration falls to 0 -- measured, the edges moved to 40
   instead of to 64, which is worse than doing nothing. Declaring the token on
   :root instead would push one si value onto every page of the old site. The
   guard holds the literal and the token in step. */
#navbarContainer,
footer > .container {
  padding-inline: 1.5rem;
}

/* --- the navigation, on si pages only -------------------------------------
   Same reach as the gutter above: this sheet is loaded by siassist_base.html
   and by nothing else, so the old pages keep their navigation untouched.

   Michael asked for the navbar to behave like the page below it on hover, and
   for NO arrows there -- a menu is a place, not an action, and a row of arrows
   in a menu bar reads as six calls to action (2026-09-08).

   Two of the three changes are contrast, not taste, and both are measured:

     the Kontakt button carried WHITE type on gold -- 1.85:1, which is not
     readable type by any standard. It now takes the same dark ink our own gold
     buttons take, 7.23:1, and the same hover: dark gold with white on it,
     8.61:1.

     a nav link turned TERRACOTTA on hover -- #C85A2E, 3.98:1, the raw mark that
     this sheet keeps out of type everywhere else. The link keeps its ink and
     the gold rule underneath appears instead, which is what .si-tlink does.

   LITERALS, not var(). The tokens live on .si-page and the navigation is OUTSIDE
   it, so every var() here resolves to nothing and the whole declaration is
   dropped -- silently, and the rule reads correctly while doing nothing. This is
   the second time today: the header/footer gutter fifty lines up carries the
   same note, and I walked into it again anyway. #3A2E05 is --si-gold-on,
   #5C4A08 --si-gold-ink, #F4B400 --si-gold, #2F3E3A --si-ink. */
body:has(main.si-page) .navbar .nav-link-btn {
  /* `!important`, and it is the only tool that works here: cms_core.css writes
     `color: #fff !important` on this button, and nothing but another !important
     beats one. The alternative is editing that sheet, which the old pages read
     too -- and their navigation is not ours to change while both are live. */
  color: #3A2E05 !important;
}
body:has(main.si-page) .navbar .nav-link-btn:hover,
body:has(main.si-page) .navbar .nav-link-btn:focus-visible {
  /* `!important` here too, and for a reason worth naming: the resting rule above
     needs one to beat cms_core.css, and an !important beats a plain declaration
     even on :hover -- so without it the button kept its dark type on the dark
     hover ground. Measured, 1.55:1. One !important forces the next. */
  background: #5C4A08; border-color: #5C4A08; color: #FFF !important;
}
body:has(main.si-page) .navbar .nav-link:not(.nav-link-btn) {
  border-bottom: 2px solid transparent;
  transition: border-color .25s cubic-bezier(.16, 1, .3, 1);
}
body:has(main.si-page) .navbar .nav-link:not(.nav-link-btn):hover,
body:has(main.si-page) .navbar .nav-link:not(.nav-link-btn):focus-visible {
  color: #2F3E3A; border-bottom-color: #F4B400;
}

/* The dropdown -- the half of the navigation that was left in Bootstrap's own
   look. The links above it were brought over on 2026-09-08; the panel that
   opens under "Loesungen" was not, and Michael read it in the HTML before
   anyone had looked at it rendered (2026-09-08).

   LITERALS again, and this is the third rule in this sheet that has to say so:
   the panel is rendered outside main.si-page, so every var() would resolve to
   nothing and drop its whole declaration without a word. #FFFFFF is
   --si-surface, #2F3E3A --si-ink, rgba(47,62,58,.12) --si-line,
   rgba(47,62,58,.045) --si-fill, #F4B400 --si-gold, 6px --si-radius, and the
   shadow is --si-shadow.

   The hover mark is the gold BAR at the left edge, not a gold ground: the same
   decision as the nav links above, where terracotta type failed contrast and a
   rule under the word replaced it. A mark beside the word never touches the
   type it marks, so it cannot make it harder to read. */
body:has(main.si-page) .navbar .dropdown-menu {
  border: 1px solid rgba(47, 62, 58, .12);
  border-radius: 6px;
  box-shadow: 0 18px 40px -22px rgba(47, 62, 58, .22);
  background: #FFFFFF;
  padding: .35rem;
  margin-top: .5rem;
  min-width: 15rem;
}
body:has(main.si-page) .navbar .dropdown-item {
  color: #2F3E3A;
  border-radius: 4px;
  padding: .5rem .75rem .5rem .9rem;
  border-left: 3px solid transparent;
  transition: background-color .2s cubic-bezier(.16, 1, .3, 1),
              border-color .2s cubic-bezier(.16, 1, .3, 1);
}
body:has(main.si-page) .navbar .dropdown-item:hover,
body:has(main.si-page) .navbar .dropdown-item:focus-visible {
  background: rgba(47, 62, 58, .045);
  border-left-color: #F4B400;
  color: #2F3E3A;
}
/* Bootstrap paints .active with its own blue and white type. The page it is on
   is marked, not advertised: the gold bar stays, the ground stays quiet. */
body:has(main.si-page) .navbar .dropdown-item.active,
body:has(main.si-page) .navbar .dropdown-item:active {
  background: rgba(47, 62, 58, .045);
  border-left-color: #F4B400;
  color: #2F3E3A;
  font-weight: 500;
}

/* Why not 0. It WAS 0, and that is what let the page be pushed sideways on a
   phone: `.row.g-5` carries margin-inline -24px, and with a padless container
   there is nothing to absorb it -- measured 24px of overhang at 500 and 540,
   8px at 992 (konzept-siassist, 2026-09-08, reproduced here). Above 576 the
   centred container's auto margin happened to swallow it; below, the container
   is edge-to-edge and it does not.

   So the gutter must be at least the row's half-gutter, and g-5 is 3rem -> 24px.
   The alignment reason the 0 was written for is untouched: EVERY si container
   now carries the same value, so the sections still share one content edge --
   it has simply moved 24px inward, which is also why the text no longer touches
   the window edge at 360. */

/* Each section's heading is a step smaller than the one before -- the mockup's
   own clamps. Collapsed onto one size, all eight h2 came out at 32px and the
   page lost its order (konzept-siassist, 2026-09-02). At 2560px these resolve
   to 64 / 45.6 / 45.6 / 41.6 / 38.4 / 34.4 / 32.8. */
/* The hero alone: its eyebrow sits directly on the heading, where the head
   groups of flow, tiles and cta keep the 1.1rem (konzept-siassist measured all
   92 vertical pairs of the page, 2026-09-08). One section, not a family. */
/* It was 0 from 2026-09-08 morning, measured against the mockup, and Michael
   asked for air there the same afternoon. It takes the head group's own gap,
   so the hero opens like every other section rather than with a value of its
   own. A departure from the mockup, deliberate, third of the day. */
.si-hero .si-eyebrow { margin-bottom: var(--si-head-gap); }
.si-hero h1 { font-size: var(--si-h1); max-width: 19ch; }
.si-flow h2,
.si-tiles h2     { font-size: var(--si-h2); }
/* Both columns start at the top; without it the shorter one centres against the
   longer and the statement loses its baseline (mockup: align-items: start). */
.si-statement .row { align-items: start; }
.si-statement h2 { font-size: var(--si-h2); max-width: 20ch; }
.si-cta h2       { font-size: var(--si-h2); }
.si-partners h2  { font-size: var(--si-h2); }

/* The head group is capped as a GROUP -- eyebrow, heading and lead to the same
   width, which is what the mockup's .flow__head / .sol__head / .cta__head /
   .pband__head do with one max-width on the wrapper. Uncapped, "Wandel
   erkennen. Verstehen, was er verlangt. Vorteil daraus machen." stood on ONE
   line across 1320px where the mockup breaks it into three.

   Absolute pixels and not ch: ch resolves against the element's own font size,
   and the mockup's heads sit on rem values -- 16px there as here. Same size and
   same box means the same line break, which a ch value converted for a
   different base would not give (konzept-siassist measured the rendered mockup
   at 1400px, 2026-09-08; his first numbers were a conversion and wrong).

   It does not contradict Michael's rule that the lead takes the width of its
   heading -- capping the group is how that is produced. */
/* `> div >` alone caught the partner band and nothing else, so three of the four
   leads still ran the full 1272px while their headings were capped -- exactly
   the "heading capped, lead not" the cap was written to remove, only the other
   way round (measured here 2026-09-08). The reason is the same shape as the
   gutter bug: a section class sits sometimes on a wrapper AROUND the container
   and sometimes ON it, and the lead is a child in one case and a grandchild in
   the other. Both forms, once. */
:is(.si-flow, .si-flow > div) > :is(h2, .si-eyebrow, .si-split__lead) { max-width: 672px; }
:is(.si-tiles, .si-tiles > div) > :is(h2, .si-eyebrow, .si-split__lead) { max-width: 720px; }
:is(.si-cta, .si-cta > div) > :is(h2, .si-eyebrow, .si-split__lead) { max-width: 624px; }
:is(.si-partners, .si-partners > div) > :is(h2, .si-eyebrow, .si-split__lead) { max-width: 720px; }

/* 0px between heading and lead. It was there before too -- the old 1.5 line
   height left enough slack in the line box to hide it, and at 1.08 there is
   none left. A defect that another rule was covering (konzept-siassist,
   2026-09-02). */
.si-hero__lead {
  font-size: clamp(1.05rem, 1.7vw, 1.22rem); color: var(--si-ink-70);
  max-width: 46ch; margin: 1.6rem 0 0;
}

/* Two washes over the whole area, from the mockup. Without them the opener
   stands on flat white -- and put on the element that also holds the content
   width, they end at 1320px and read as a grey box instead. This class sits on
   the FULL-WIDTH ground now; the .container inside keeps the content in its
   track. Same shape as .is-process-band__ground in the Scout sheet. */
.si-hero {
  position: relative;
  overflow: hidden;
  background-image:
    radial-gradient(70% 90% at 88% 8%, rgba(244, 180, 0, .16), transparent 62%),
    radial-gradient(55% 70% at 2% 96%, rgba(209, 231, 221, .5), transparent 60%);
}

/* The drawing on the right. Decorative -- aria-hidden, no alt text -- and it
   drifts, 9s up and down by 10px. Same class of movement as the pulse, so it
   answers to the same gate. */
.si-hero__art { width: 100%; height: auto; display: block; }

@media (prefers-reduced-motion: no-preference) {
  .si-hero__art { animation: si-drift 9s ease-in-out infinite; }
}

@keyframes si-drift {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-10px); }
}
/* The mockup's own 2.4rem above and 2.6rem below, after the spacing ladder fell
   with the type ladder (konzept-siassist, 2026-09-02). Written as PADDING on
   this row rather than as margins on both: the plugins carry `m-0` and
   Bootstrap hangs !important on it, and the gap below has to sit ABOVE the logo
   row's border, where padding on that row could not put it. One element, two
   gaps, no !important anywhere. */
.si-hero__cta { display: flex; flex-wrap: wrap; gap: .85rem; margin: 0; padding: 2.4rem 0 2.6rem; }
/* The gold stroke under the lower third of the emphasised word -- the loudest
   mark in the mockup's heading, and here it had turned into a heavier word
   instead. Both together would say the same thing twice, so the weight goes
   back to the heading's own and the stroke carries the emphasis. nowrap keeps
   it from breaking across a line, where a stroke under half a word reads as a
   defect (konzept-siassist, 2026-09-01). */
.si-hero h1 em {
  font-style: normal;
  white-space: nowrap;
  background-image: linear-gradient(transparent 66%, rgba(244, 180, 0, .34) 66%);
  background-repeat: no-repeat;
  background-size: 100% 100%;
}
/* The stroke draws itself in -- and the base state above is the FULL stroke, so
   under reduced motion it simply stands there. Same lesson as the pulse: the
   quiet variant shows the thing, it does not remove it. */
@media (prefers-reduced-motion: no-preference) {
  .si-hero h1 em {
    animation: si-mark .9s var(--si-ease, cubic-bezier(.16, 1, .3, 1)) .55s both;
  }
}

@keyframes si-mark {
  from { background-size: 0% 100%; }
  to   { background-size: 100% 100%; }
}
/* The drawing is shorter than the text column, so left-aligned it hung from the
   top with 103.7px of nothing under it. The mockup's .hero__grid centres them
   (konzept-siassist, 2026-09-01). */
.si-hero .row { align-items: center; }

/* The logo row: equal optical height, unequal width. For brands that is the
   right way round -- never force a common width (delivery, section 1). */
.si-hero__logos {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--si-space-s);
  padding-top: 1.6rem; border-top: 1px solid var(--si-line);
  margin: 0; list-style: none;
}
/* Its own shadow, not --si-shadow: a raised surface lifts off the page, these
   plates only need to not disappear into the wash behind them. One value, one
   use, and it is the mockup's (konzept-siassist, 2026-09-01). */
.si-hero__logo {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--si-surface); border: 1px solid var(--si-line-soft);
  border-radius: var(--si-radius); padding: .75rem 1.15rem;
  box-shadow: 0 1px 3px rgba(47, 62, 58, .05);
}
.si-hero__logo img { height: 32px; width: auto; display: block; }

/* The measurements, on top of Bootstrap's .btn. Inheriting the skin was right;
   inheriting the SIZE was not -- Bootstrap's 6/12px padding and 16px type made
   a 38px button where the mockup has ~46 (Michael, 2026-09-02). Two class
   levels, because Bootstrap's own .btn is one. */
/* The gap is .3rem and the sign sits 8.8px from the word. Those are not the
   same number, and the difference is not a mistake: djangocms-frontend's link
   template hangs `ms-1` on the icon, and Bootstrap's spacing utilities carry
   !important -- measured, `margin-left: 0` from this sheet does not win. So the
   utility's 4px is counted IN rather than fought: 4.8 + 4 = 8.8, which is the
   value fundament.md sec 12 asks for. Change one and the other must follow;
   a guard holds them together. */
.si-page .btn {
  display: inline-flex; align-items: center; gap: .3rem;
  font-size: var(--si-t-btn); font-weight: 500;
  padding: .85rem 1.5rem; border-radius: var(--si-radius);
}

/* Skins on Bootstrap's .btn, not buttons of our own: focus ring and states are
   inherited (delivery, "Wiederverwendete Kleinteile"). */
.si-btn--gold { background: var(--si-gold); color: var(--si-gold-on); border-color: var(--si-gold); }
/* On hover the button goes DARK and its type goes white -- Michael asked for
   white type and a white arrow because the old hover (#F4B400 -> #EDAE00) was
   barely a change (2026-09-08).

   The background has to move with it, and that is measured, not preferred:
   white on #EDAE00 is 1.97:1, which is not readable type by any standard. On
   --si-gold-ink it is 8.61:1, and the button reads as the same colour gone
   deeper rather than as a different one. The arrow follows through
   currentColor. */
.si-btn--gold:hover,
.si-btn--gold:focus-visible {
  background: var(--si-gold-ink); border-color: var(--si-gold-ink); color: #FFF;
}
.si-btn--ghost { border-color: var(--si-line); color: var(--si-ink); background: transparent; }
.si-btn--ghost:hover { border-color: var(--si-ink-45); background: rgba(47, 62, 58, .035); color: var(--si-ink); }

/* B3 si-flow -- three drawings, then three stations. */
.si-flow__viz { display: grid; grid-template-columns: 1fr auto 1fr auto 1fr; gap: var(--si-space-s); align-items: center; margin: 0; }
.si-flow__fig { margin: 0; display: grid; gap: var(--si-space-s); }
.si-flow__fig img { width: 100%; height: auto; display: block; }
/* The caption is the DARK one and the example under it the light one. We had
   both on the same grey, which put the order on its head (konzept-siassist,
   2026-09-08). */
/* `.si-page` in front, or `.si-page p` wins and the caption renders --si-ink-70 --
   the third time today that this trap has cost a rule that reads correctly. */
.si-page .si-flow__cap { text-align: center; font-size: var(--si-t-chip); font-weight: 500; line-height: 1.3; color: var(--si-ink); margin: 0; }
/* A quiet sub-line, not a label. The gold pill belongs to .flowviz__tag in the
   mockup -- the caption ABOVE the diagram, which this page does not have. The
   styling had wandered onto the wrong element: "z. B. Daten und Prognosen" is an
   aside, and an aside in a bordered capsule reads as a category. */
/* Third place under the same decision as .si-step__num and .si-tile__who: at
   12px --si-ink-45 came to 2.85:1 on the section ground. I put it here in the
   round before konzept-siassist took the colour off the other two -- found by
   sweeping every text colour on the page, not by being told. */
.si-flow__eg {
  display: block; margin-top: .25rem;
  font-size: var(--si-t-micro); font-weight: 400; line-height: 1.3;
  /* --si-ink-70 for the same reason as .si-tile__who: the mockup's --ink-45
     is 3.03:1. Only the line-height moves here. */
  color: var(--si-ink-70);
}
.si-flow__arrow { color: var(--si-gold); justify-self: center; line-height: 1; }

@media (max-width: 819.98px) {
  .si-flow__viz { grid-template-columns: 1fr; }
  .si-flow__arrow { transform: rotate(90deg); }
}

/* The three stations sit on one rail. A grid and not Bootstrap columns, because
   the chevron between two cards lives in the GAP -- with columns the space
   between them is padding inside each one, and there is nothing to sit in. */
/* One source, two readers again: the rail is absolutely positioned inside this
   element, so its `top` is measured from the padding edge -- add the air here
   only and the line ends up 60px above the dots it runs through. */
.si-flow__steps { display: grid; gap: var(--si-space-l); position: relative; padding-top: var(--si-steps-pad); }

/* The rail. It was missing from the first build: the delivery listed the
   pulsing dot as dropped, and the dot went with it -- but the pulse is
   decoration and the dot is the anchor of this line. Without it three cards
   stand side by side instead of forming a chain (konzept-siassist, 2026-09-01).

   Below 1000px it is off: the stations stack, and a horizontal line through a
   vertical list connects nothing. */
.si-flow__rail { display: none; }

/* A station: node row above, card below. The dot takes its colour from the step
   and paints it through currentColor -- a sign, never type. */
/* 1.4rem and not --si-space-m: the mockup puts 22.4px between the node row and
   the card (`.step__node { margin-bottom: 1.4rem }`), we had 16 (konzept-siassist,
   2026-09-08). Set on the gap and NOT additionally on the node -- the two would
   add up, which is how the split button reached 50px this morning. */
.si-step { display: flex; flex-direction: column; gap: 1.4rem; height: 100%; }
/* flex: 0 0 auto, or the row shrinks: it is a flex item in a column that is
   `height: 100%`, so its 26px are a suggestion until they are not. Measured
   without it: 24.19px, and the rail then ran a pixel off the dots. */
.si-step__node {
  display: flex; align-items: center; gap: .9rem;
  height: var(--si-node-h); flex: 0 0 auto;
}
.si-step--1 .si-step__node { color: var(--si-terra); }
.si-step--2 .si-step__node { color: var(--si-gold); }
.si-step--3 .si-step__node { color: var(--si-panel); }
.si-step__dot { position: relative; width: 14px; height: 14px; border-radius: 50%; background: var(--si-bg); border: 2px solid currentColor; flex: 0 0 auto; }
.si-step__dot::after { content: ""; position: absolute; inset: 2px; border-radius: 50%; background: currentColor; }

/* The pulsing ring. It was out for one day on a taste judgement that was not
   Michael's; he asked for it on 2026-09-01 ("ja soll mit rein").

   It is defined here and animated only below, under no-preference. At rest it
   is fully transparent, so under `prefers-reduced-motion: reduce` there is
   nothing standing still on the page -- the ring is simply not there, which is
   what the mockup does too. That is a duty, not an extra.

   `currentColor` again: the ring takes the phase colour from the node without
   being told, exactly as the dot and its core do. */
.si-step__dot::before {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  border: 1px solid currentColor;
  opacity: 0;
}

@media (prefers-reduced-motion: no-preference) {
  .si-step__dot::before { animation: si-pulse 3.2s ease-out infinite; }
}

@keyframes si-pulse {
  0%          { transform: scale(.6);  opacity: .7; }
  70%, 100%   { transform: scale(1.5); opacity: 0; }
}
/* A DELIBERATE DEPARTURE FROM THE MOCKUP, not an oversight: the mockup sets
   --ink-45 here (#8A9793, 3.03:1 on white) and is itself under the floor.
   Michael wants the line on the process rail readable ("text auf der
   prozesslinie nicht zu sehr transparent"), so it takes --si-ink-70 (#5E6D68,
   5.44:1) -- still clearly quieter than the stage name beside it. Same call
   for .si-tile__who below. Do not "correct" either back to the mockup
   (konzept-siassist, 2026-09-01). */
.si-step__num { font-size: var(--si-t-micro); font-weight: 600; letter-spacing: .16em; color: var(--si-ink-70); }
/* `position: relative` is the load-bearing half, not the colour. The rail is
   `position: absolute` and the chip was `static`, so the rail painted OVER it --
   a positioned element wins against a non-positioned one in the same stacking
   context whatever the source order, and the gold line ran straight through the
   word (Michael diagnosed it, 2026-09-08). The background was already opaque
   white; making it whiter would have changed nothing at all.
   The .78 is the second half of his ask: the chip sits ON the rail rather than
   cutting a hole in it, so the line stays visible through the word. Lowered from
   .92 at his word; the contrast is measured after every change to it and must
   stay far above 4.5:1 -- at .78 it is 10.3:1. */
.si-step__stage {
  position: relative; z-index: 1;
  font-size: var(--si-t-micro); font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: var(--si-ink); padding: .26rem .6rem; border-radius: 99px; line-height: 1.15;
  background: rgba(255, 255, 255, .78); border: 1px solid var(--si-line);
}
.si-step__card {
  position: relative;
  background: var(--si-surface); border: 1px solid var(--si-line-soft);
  border-radius: var(--si-radius-lg); padding: clamp(1.5rem, 2.6vw, 2rem); box-shadow: var(--si-shadow);
  display: flex; flex-direction: column; height: 100%;
}
/* NO `gap` on the card. The mockup staggers these five from tight to wide --
   14.4 / 18.4 / 12.8 / 24 / 27.2 -- and question and body belong close together
   while the tags and the foot stand well clear. One even gap turns a staggered
   card into a list (konzept-siassist, 2026-09-02). Each child brings its own
   distance below, which is why the numbers sit on the children and not here. */
.si-step__card > * { margin-top: 0; }
/* The partner's name carries weight, the role stays small beside it -- the
   mockup's .card__who: ONE baseline row with the two ends apart, wrapping only
   when the card gets narrow (not two stacked lines). Pulled into a single 14px
   footnote joined by a middot, the head had no order left and kipped under the
   question above it (konzept-siassist, 2026-09-01).

   The sizes are the declared steps, not the mockup's literal 1.16/.8rem: the
   sheet spends four sizes on purpose (ADR-0010, si-fundament section 1), and
   two new ones for one card head would be the first of several. 1.25rem is the
   nearest step up, .875rem is the declared meta line -- which is what a role
   is. */
/* The question is 1.25rem/400, the same declared step as the name beside it and
   the lighter weight of the two. Bootstrap's h3 gave it 28px/500, so it towered
   over a 20px head; the mockup puts the two almost level (18.24 against 18.56)
   and that is what makes the card quiet. It stays an h3 -- inside a card a
   heading may carry its own size (konzept-siassist, 2026-09-01). */
/* No top margin: the gap comes from .si-step__who's padding and its rule, the
   way the mockup builds it. Set here as well it came to 18px too much. */
/* 14px, and it is a DEPARTURE from the mockup, asked for by name: the mockup
   renders 0 there -- its own `.card__q { margin-top: 1.15rem }` is overridden
   further down -- and the question then sits on the rule above it, which looks
   wrong in the mockup too. konzept-siassist withdrew his own instruction of a
   few hours earlier for this (2026-09-08). It was 1.15rem before that, which is
   why this line has now carried three different values in one day.

   `.si-step__card h3` is (0,1,1) and beats `.si-step__card > *` (0,1,0) above --
   which is what makes the value arrive at all. */
.si-step__card h3 { margin-top: 14px; font-size: var(--si-t-q); font-weight: 400; line-height: 1.3; }
/* The card's running text: the mockup's .card__body. */
/* `flex: 1` is what puts the three feet on one line. The foot's own
   `margin-top: auto` -- the mockup's mechanism, and it is still written there --
   is dead: the plugin emits `m-0` and Bootstrap hangs !important on it. Growing
   the body text pushes the foot down instead, which is the move .si-cta__box p
   already makes in this sheet (konzept-siassist, 2026-09-08: feet at 670/634/634). */
.si-step__card > p { flex: 1; margin: .8rem 0 0; font-size: var(--si-t-body); line-height: 1.62; color: var(--si-ink-70); }
.si-step__who {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: .35rem 1rem; flex-wrap: wrap; margin: 0;
  padding-bottom: .9rem; border-bottom: 1px solid var(--si-line-soft);
}
.si-step__org { font-size: var(--si-t-name); font-weight: 500; letter-spacing: -.02em; color: var(--si-ink); }
.si-step__role { font-size: var(--si-t-link); font-weight: 500; color: var(--si-ink-70); }
/* The bottom margin is 1.15rem and it is a DEPARTURE from the mockup, asked for
   by Michael (2026-09-08): there the rule of the card foot sits directly on the
   tags, 0px, measured in both. 1.15rem is the foot's own padding-top, so the
   line now has the same air above it as below -- the number is taken from the
   card rather than invented.

   Used in exactly one place, the process card, so the scope needs no selector. */
.si-tags { display: flex; flex-wrap: wrap; gap: .4rem; margin: 1.5rem 0 1.15rem; padding: 0; list-style: none; }
.si-tag { font-size: var(--si-t-tag); font-weight: 500; color: var(--si-ink-70); background: rgba(47, 62, 58, .045); border-radius: var(--si-radius); padding: .34rem .62rem; }

/* B7 si-tlink -- the quiet text link. Six of them have no target yet, and
   those were carrying Bootstrap's `text-body-secondary`: the first foreign
   colour to fall into the page, and at 14px/400 it read as text somebody left
   lying rather than as a link. A switched-off link now keeps the size, the
   weight and the si palette of an active one and only loses its colour and its
   solid edge -- the dashed edge is where the target would be. The size is the
   declared .875rem rather than the mockup's .92rem, for the reason given at
   .si-step__who. */
/* Same arithmetic as .si-page .btn above: `ms-1` adds 4px that cannot be
   overridden, so the gap carries the rest. .2rem + 4 = 7.2. */
.si-tlink {
  display: inline-flex; align-items: center; gap: .2rem;
  font-size: var(--si-t-link); font-weight: 500;
  /* Not --bs-link-color (#C85A2E): that is the raw mark, and it carries type at
     3.98:1 on the section ground. Its ink variant is what type takes. */
  color: var(--si-terra-ink);
  border-bottom: 1px solid var(--si-line); padding-bottom: 2px;
  /* The switched-off link is a direct child of .si-step__card, which is a
     column flex container -- and a flex item's `inline-flex` blockifies to
     `flex` and then stretches. Without this the dashed edge ran the full 352.7px
     of the card instead of hugging its words. Harmless where the link is not a
     flex item. */
  align-self: flex-start;
  transition:
    border-color .3s var(--si-ease, cubic-bezier(.16, 1, .3, 1)),
    gap .3s var(--si-ease, cubic-bezier(.16, 1, .3, 1));
}
/* The sign steps forward on hover. One idiom for every live text link on the
   site -- Michael asked for one sign used everywhere rather than a chevron
   here and an arrow there (2026-09-08). The gap grows as well, so the arrow
   moves and the words stay put. */
.si-tlink .bi { transition: transform .25s var(--si-ease, cubic-bezier(.16, 1, .3, 1)); }
.si-tlink:hover { border-color: var(--si-gold); gap: .45rem; }
.si-tlink:hover .bi { transform: translateX(3px); }
.si-tlink[aria-disabled="true"] {
  color: var(--si-ink-70); border-bottom-style: dashed; cursor: default;
}

/* The card's foot: a rule the width of the card, the link under it. It is a
   wrapper of its own because the mockup's line runs the full width while the
   link is only as wide as its words -- a border on the link itself would be a
   line under two words. `margin-top: auto` pushes it to the bottom, so three
   cards of different length still line their feet up. */
.si-step__foot {
  margin-top: auto; padding-top: 1.15rem; border-top: 1px solid var(--si-line-soft);
}

/* B4 si-tiles -- nine tiles in three groups. The group colour is set ONCE per
   tile as --si-cat and read by the hexagon and the rule on the left edge; a
   tile carries its key, never a colour (delivery, section 4). */
/* Padding, not margin: the plugin carries a Bootstrap spacing class and those
   are !important. The mockup gives the filter clamp(2rem,4vw,2.75rem) from the
   head, and the grid 2rem from the filter; ours had 24 and 10. */
.si-tiles__filter { display: flex; flex-wrap: wrap; gap: var(--si-space-s); margin: 0; padding: .75rem 0 0; }
/* .75rem, not the 2.75 that stood here: the lead above now brings 2rem of its
   own, and the two together made 76px to the first chip. The mockup measures 44
   there (konzept-siassist), and 12 + 32 is that. */
.si-chip {
  display: inline-flex; align-items: center; gap: .45rem; font-size: var(--si-t-chip); font-weight: 500;
  border: 1px solid var(--si-line); border-radius: 99px; padding: .45rem .9rem;
  background: transparent; color: var(--si-ink-70); cursor: pointer;
}
.si-chip i { width: 8px; height: 8px; border-radius: 50%; background: var(--si-cat, var(--si-ink-45)); flex: 0 0 auto; }
.si-chip b { font-weight: 500; font-variant-numeric: tabular-nums; }
.si-chip[aria-pressed="true"] { color: var(--si-cat-ink, var(--si-ink)); background: var(--si-cat-wash, rgba(47, 62, 58, .045)); border-color: var(--si-cat, var(--si-ink-45)); }

/* A real grid, not Bootstrap columns. The filter sets `hidden` on the tile, and
   a tile inside a column leaves the column standing -- the space stays occupied
   and the grid does not close up. That is exactly what Michael saw. As direct
   grid children the tiles are the tracks, so hiding one removes its track and
   auto-fill re-lays the rest. */
.si-tiles__grid {
  padding-top: var(--si-space-l);
  display: grid;
  gap: var(--si-space-m);
  grid-template-columns: repeat(auto-fill, minmax(15.5rem, 1fr));
}

.si-tile,
.si-rel,
.si-na {
  position: relative; display: flex; flex-direction: column; height: 100%;
  background: var(--si-surface); border: 1px solid var(--si-line-soft);
  border-radius: var(--si-radius-lg); padding: clamp(1.4rem, 2.4vw, 1.9rem);
  box-shadow: var(--si-shadow);
  overflow: hidden; text-decoration: none; color: inherit;
}
.si-tile::before,
.si-rel::before,
.si-na::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--si-cat, var(--si-gold)); transform: scaleY(0); transform-origin: top;
  transition: transform .5s cubic-bezier(.16, 1, .3, 1);
}
.si-tile:hover::before, .si-rel:hover::before, .si-na:hover::before { transform: scaleY(1); }
.si-tile[hidden] { display: none; }
/* display: flex, or nothing is drawn. The row is a <span>, and so is the
   hexagon -- an inline box ignores width and height, so the 44px square came out
   as 2 x 22px and the mask had nothing to fill. Measured, not guessed. */
.si-tile__top { display: flex; align-items: flex-start; justify-content: space-between; gap: .75rem; }

.si-tile__foot { display: flex; }

.si-tile__hex {
  display: block;
  width: 44px; height: 44px; border-radius: var(--si-radius); flex: 0 0 auto;
  background: var(--si-cat-wash, #FDF4DC);
  border: 1px solid var(--si-cat-line, rgba(244, 180, 0, .45));
  position: relative;
}

/* The stencil sits inside the plate and is filled with the group colour --
   that is the whole point of a mask here: the shape comes from the file, the
   colour from the sheet, exactly as currentColor would have done inline. */
.si-tile__hex::before {
  content: ""; position: absolute; inset: 7px;
  background: var(--si-cat, var(--si-gold));
  -webkit-mask: var(--si-hex) center / contain no-repeat;
  mask: var(--si-hex) center / contain no-repeat;
}

/* --- the nine hexagons, as CSS masks --------------------------------------
   They stay symbols in the code and not pictures in the Filer (Michael,
   2026-09-01) -- but not as inline markup, which is where the first attempt
   went. The text plugin sanitises its body and removes `<svg>` outright, so an
   inline symbol never reaches the page.

   A mask does reach it, and it keeps the property the whole decision rested on:
   the shape is a stencil, `background: currentColor` fills it, so a tile still
   inherits its group colour from the stylesheet. konzept-siassist weighed this
   route on 2026-09-01 and set it aside only because it would have meant two
   mechanisms for twelve files -- the three drawings went to the Filer instead,
   so it is now the only mechanism for the nine that stayed.

   Each stencil is the mockup's path data, unchanged, url-encoded. */
.si-hex--innovation-scout { --si-hex: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M16%202.5%2028%209.5v13L16%2029.5%204%2022.5v-13z%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%2F%3E%3Ccircle%20cx%3D%2214.5%22%20cy%3D%2214.5%22%20r%3D%224.5%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%2F%3E%3Cpath%20d%3D%22M18%2018l4%204%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%20stroke-linecap%3D%22round%22%2F%3E%3C%2Fsvg%3E"); }
.si-hex--kompetenz-kompass { --si-hex: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M16%202.5%2028%209.5v13L16%2029.5%204%2022.5v-13z%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%2F%3E%3Cpath%20d%3D%22M11%2020l4.5-9%204.5%209-4.5-2.5z%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E"); }
.si-hex--green-skills-kompass { --si-hex: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M16%202.5%2028%209.5v13L16%2029.5%204%2022.5v-13z%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%2F%3E%3Cpath%20d%3D%22M16%2021.5c0-4%202-6.5%205.5-7.5-.5%204.5-2.5%207-5.5%207.5zM16%2021.5c0-4-2-6.5-5.5-7.5.5%204.5%202.5%207%205.5%207.5z%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.7%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E"); }
.si-hex--econa { --si-hex: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M16%202.5%2028%209.5v13L16%2029.5%204%2022.5v-13z%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%2F%3E%3Cpath%20d%3D%22M11%2020.5v-4M15%2020.5v-8M19%2020.5v-5.5M23%2020.5v-9%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%20stroke-linecap%3D%22round%22%2F%3E%3C%2Fsvg%3E"); }
.si-hex--future-skills-map { --si-hex: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M16%202.5%2028%209.5v13L16%2029.5%204%2022.5v-13z%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%2F%3E%3Cpath%20d%3D%22M10.5%2020.5l4-4%203%202.5%204-6.5%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3Ccircle%20cx%3D%2221.5%22%20cy%3D%2212.5%22%20r%3D%221.7%22%20fill%3D%22currentColor%22%2F%3E%3C%2Fsvg%3E"); }
.si-hex--job-architektur { --si-hex: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M16%202.5%2028%209.5v13L16%2029.5%204%2022.5v-13z%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%2F%3E%3Cpath%20d%3D%22M16%2012.5v3.5M11%2021v-2.5h10V21%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.7%22%20stroke-linecap%3D%22round%22%2F%3E%3Ccircle%20cx%3D%2216%22%20cy%3D%2211%22%20r%3D%221.7%22%20fill%3D%22currentColor%22%2F%3E%3Ccircle%20cx%3D%2211%22%20cy%3D%2222%22%20r%3D%221.7%22%20fill%3D%22currentColor%22%2F%3E%3Ccircle%20cx%3D%2221%22%20cy%3D%2222%22%20r%3D%221.7%22%20fill%3D%22currentColor%22%2F%3E%3C%2Fsvg%3E"); }
.si-hex--szenarioplanung { --si-hex: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M16%202.5%2028%209.5v13L16%2029.5%204%2022.5v-13z%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%2F%3E%3Cpath%20d%3D%22M10.5%2016.5h3.5l3.5-4.5h4.5M17.5%2021h4.5%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.7%22%20stroke-linecap%3D%22round%22%2F%3E%3Cpath%20d%3D%22M14%2016.5l3.5%204.5%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.7%22%20stroke-linecap%3D%22round%22%2F%3E%3C%2Fsvg%3E"); }
.si-hex--toolbox { --si-hex: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M16%202.5%2028%209.5v13L16%2029.5%204%2022.5v-13z%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%2F%3E%3Cpath%20d%3D%22M10.5%2012.5h11M10.5%2016h11M10.5%2019.5h7%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%20stroke-linecap%3D%22round%22%2F%3E%3C%2Fsvg%3E"); }
.si-hex--kompetenz-landkarte { --si-hex: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M16%202.5%2028%209.5v13L16%2029.5%204%2022.5v-13z%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.8%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2213%22%20r%3D%221.8%22%20fill%3D%22currentColor%22%2F%3E%3Ccircle%20cx%3D%2220%22%20cy%3D%2212%22%20r%3D%221.8%22%20fill%3D%22currentColor%22%2F%3E%3Ccircle%20cx%3D%2216%22%20cy%3D%2220%22%20r%3D%221.8%22%20fill%3D%22currentColor%22%2F%3E%3Cpath%20d%3D%22M12%2013l8-1-4%208z%22%20stroke%3D%22currentColor%22%20stroke-width%3D%221.4%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E"); }

.si-tile h3, .si-rel h3 { margin: 1.1rem 0 0; font-size: var(--si-t-card); font-weight: 500; letter-spacing: -.02em; line-height: 1.25; }
.si-tile p:not(.si-pident), .si-rel p:not(.si-pident) { margin: .7rem 0 0; font-size: var(--si-t-tile); color: var(--si-ink-70); flex: 1; }
.si-tile__foot {
  margin-top: 1.4rem; padding-top: .9rem; border-top: 1px solid var(--si-line-soft);
  display: flex; align-items: center; justify-content: space-between; gap: .75rem;
}
/* --si-ink-70, not the mockup's --ink-45: 3.03:1 is under the floor and
   Michael asked for it readable (2026-09-01). Size and line-height follow
   the mockup, the colour does not -- see the guard that says so. */
.si-tile__who { font-size: var(--si-t-who); line-height: 1.3; color: var(--si-ink-70); }
.si-tile__badge {
  font-size: var(--si-t-badge); font-weight: 600; letter-spacing: .1em; padding: .22rem .58rem;
  border-radius: 99px; color: var(--si-cat-ink, var(--si-ink)); background: var(--si-cat-wash, rgba(47, 62, 58, .045));
}
.si-tile__foot i { color: var(--si-cat, var(--si-gold)); }

/* One column, two from 760, three from 1100 -- the mockup's `.rel` and `.rel--3`
   (konzept-siassist measured them, 2026-09-08). It used to jump straight from one
   to three at 768, which put three 240px cards on a tablet. The top margin is the
   head group's gap: the eyebrow above belongs to this block. */
.si-rel-grid { display: grid; gap: var(--si-space-m); margin-top: var(--si-head-gap); }
@media (min-width: 760px) { .si-rel-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .si-rel-grid { grid-template-columns: repeat(3, 1fr); } }
/* The stacked section head: the lead under the heading, not beside it (mockup
   `.wrap` without `sec__grid`). 570px and not the delivery's first "30ch" --
   fundament sec 13, absolute numbers, because our ch is not the mockup's ch. */
/* `.si-page` in front, or `.si-psec h2` (0,1,1) beats the class (0,1,0) and the
   cap stays at its 22ch -- 396px, measured. Fifth time today. */
.si-page .si-psec__head { max-width: 570px; margin-top: 1rem; }
/* The head group's own gap, like everywhere else -- it was 0 here, and the
   lead touched the heading (Michael, 2026-09-08). */
.si-page .si-psec__head + .si-psec__lead { margin-top: var(--si-head-gap); }

/* --- the partner pages: number strip, people, screenshots ------------------
   Values from partner.md part A (konzept-siassist, 2026-09-08), measured in the
   rendered mockup at 1400px -- but written as LADDER RUNGS, not as those raw
   numbers. The ladder guard refused the raw set and it was right to: six sizes
   appeared that no rung declares. Five of them land within 0.32px of an existing
   rung and take it (13.6 and 14.08 -> --si-t-chip, 14.72 -> --si-t-link,
   15.2 -> --si-t-btn, 16.8 -> --si-t-quote), which is the same call
   konzept-siassist made three times today for differences of that size. The
   figure on a fact card is the exception: 25.6px is a display size with nothing
   near it, so it becomes a rung of its own rather than a number in a rule. */

/* The top margin is the head group's gap where an eyebrow stands above the
   strip (newsletter page, 24px) and the section's step where it follows text.
   One value: 24 reads correctly in both. */
.si-facts { display: grid; gap: .85rem; margin-top: var(--si-head-gap); }
@media (min-width: 700px) { .si-facts { grid-template-columns: repeat(3, 1fr); } }
.si-fact {
  background: var(--si-surface); border: 1px solid var(--si-line-soft);
  border-radius: var(--si-radius-lg); padding: 1.35rem 1.5rem; box-shadow: var(--si-shadow);
}
/* `.si-page p` (0,1,1) would take both of these, so both carry the page class --
   the trap that cost five corrections on "Ueber SIAssist" the same day. */
.si-page .si-fact__n { margin: 0; font-size: var(--si-t-num); font-weight: 300; letter-spacing: -.03em; color: var(--si-ink); }
.si-page .si-fact__t { margin: .35rem 0 0; font-size: var(--si-t-chip); color: var(--si-ink-70); }

.si-people { display: grid; gap: .85rem; margin-top: var(--si-space-m); }
@media (min-width: 760px) { .si-people { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); } }
.si-person {
  background: var(--si-surface); border: 1px solid var(--si-line-soft);
  border-radius: var(--si-radius-lg); padding: clamp(1.4rem, 2.4vw, 1.85rem);
  box-shadow: var(--si-shadow); display: grid; gap: .9rem;
}
.si-person__head { display: flex; align-items: center; gap: .9rem; }
.si-person__badge {
  width: 44px; height: 44px; flex: none; border-radius: 50%;
  background: var(--si-gold-wash); border: 1px solid var(--si-gold-wash-line);
  color: var(--si-gold-ink); font-size: var(--si-t-btn); font-weight: 500; letter-spacing: .02em;
  display: flex; align-items: center; justify-content: center;
}
.si-person__who { display: grid; }
.si-person__who b { font-size: var(--si-t-quote); font-weight: 500; letter-spacing: -.02em; color: var(--si-ink); }
.si-page .si-person__role { margin: 0; font-size: var(--si-t-chip); color: var(--si-ink-45); }
/* An address is content, so it wraps rather than pushing the card wide. */
.si-person__ways { display: grid; gap: .2rem; font-size: var(--si-t-link); overflow-wrap: anywhere; }
.si-person__ways a { color: var(--si-ink-70); text-decoration: none; border-bottom: 1px solid var(--si-line); }
.si-person__ways a:hover { color: var(--si-ink); border-color: var(--si-gold); }

.si-shots { display: grid; gap: 1rem; margin-top: var(--si-space-l); }
@media (min-width: 900px) {
  .si-shots { grid-template-columns: 1fr 1fr; }
  /* The first one runs across both columns -- delivery, part A/4. */
  .si-shot:first-child { grid-column: 1 / -1; }
}
.si-shot img {
  display: block; width: 100%; height: auto; background: #FFF;
  border: 1px solid var(--si-line-soft); border-radius: var(--si-radius-lg); box-shadow: var(--si-shadow);
}
.si-page .si-shot__cap { margin: .55rem 0 0; font-size: var(--si-t-chip); line-height: 1.4; color: var(--si-ink-45); }

/* The variant whose items open with a line of their own. In si_checks a marked
   opening stays IN the line; here it is a block above the body -- two different
   things the mockup keeps apart, so the sheet does too. */
.si-checks--lead .si-checks__lead { display: block; font-weight: 500; color: var(--si-ink); }

/* A subheading inside running text. Its size is a heading's, not emphasis's --
   which is why it is an h2 and not a bold paragraph (news.md part B). */
/* .75rem ON TOP of the grid gap, not instead of it: the delivery's "12px
   above" is a margin, and .si-prose is a grid whose gap already separates the
   blocks. 24 + 12 = 36 above a subheading, 24 between paragraphs. */
.si-page .si-prose__h { font-size: var(--si-t-num); font-weight: 300; color: var(--si-ink); margin: .75rem 0 0; }
.si-page .si-prose__h:first-child { margin-top: 0; }

/* The head of a news post, and the body under it. Absolute caps, fundament
   sec 13 -- news.md part B. The post has no second column: head and body stand
   at the content edge, not centred. */
.si-natop { max-width: 840px; }
.si-page .si-natop h1 { font-size: var(--si-h1); font-weight: 300; margin: 1.1rem 0 0; max-width: none; }
.si-page .si-natop__lead { font-size: var(--si-t-lead); color: var(--si-ink-70); max-width: 696px; margin: 1.35rem 0 0; }
/* `.si-page` in front, and it is load-bearing: `.si-prose` ties this on
   specificity (both 0,1,0) and stands 400 lines LATER, so it won -- the body
   measured 680px, its 68ch, instead of 816. Sixth time today that a correct-
   looking rule lost to one that merely came after it.

   The paragraph gap is the grid's `gap`, not a margin: .si-prose is a grid, and
   a margin would have been ADDED to the 1.05rem gap rather than replacing it. */
.si-page .si-prose--wide { max-width: 816px; margin-top: 2.75rem; gap: 1.5rem; }

/* --- the contact form -----------------------------------------------------
   The plugin is `cms_plugin_contact`, unchanged: it sends mail and carries the
   reCAPTCHA consent gate, and the mockup's form does neither. Everything here
   is scoped to `.si-page`, so the same plugin on an old page is untouched.

   What this CANNOT reach is the markup: the template uses Bootstrap's
   `form-floating`, so the label sits IN the field and shrinks on focus, where
   the mockup puts it above. Changing that means a second template for a shared
   plugin -- reported rather than done. Values from kontakt.md part B. */
.si-page .si-form {
  background: var(--si-surface); border: 1px solid var(--si-line-soft);
  border-radius: var(--si-radius-lg); padding: clamp(1.5rem, 3vw, 2.15rem);
  box-shadow: var(--si-shadow); max-width: 544px;
}
.si-page .si-form__fields { display: grid; gap: 1.1rem; }
.si-page .si-field { display: grid; gap: .45rem; }
.si-page .si-field > label { font-size: var(--si-t-chip); font-weight: 500; color: var(--si-ink); }
.si-page .si-form .form-control {
  font-size: var(--si-t-tile); background: var(--si-bg);
  border: 1px solid var(--si-line); border-radius: var(--si-radius);
  padding: .7rem .85rem;
}
.si-page .si-field__fine { margin: .15rem 0 0; font-size: var(--si-t-who); color: var(--si-ink-45); }
.si-page .si-form .contact-submit { margin-top: 1.35rem; }
.si-page .si-form .form-control:focus {
  border-color: transparent; box-shadow: 0 0 0 2px var(--si-gold); background: var(--si-bg);
}
.si-page .si-form textarea.form-control { min-height: 7rem; resize: vertical; }
/* The submit button takes the gold skin without carrying its class: the template
   is shared and writes `btn btn-secondary`. */
.si-page .si-form .contact-submit {
  background: var(--si-gold); border-color: var(--si-gold); color: var(--si-gold-on);
  font-size: var(--si-t-btn); font-weight: 500; padding: .85rem 1.5rem; border-radius: var(--si-radius);
}
/* The same hover as .si-btn--gold above -- it is the same button wearing the
   plugin's class instead of ours. */
.si-page .si-form .contact-submit:hover:not(:disabled) {
  background: var(--si-gold-ink); border-color: var(--si-gold-ink); color: #FFF;
}
.si-page .si-form__note { max-width: 544px; margin: 1rem 0 0; font-size: var(--si-t-chip); color: var(--si-ink-45); }

/* One sentence on a contact card, above the ways to reach the person. */
.si-page .si-person__line { margin: 0; font-size: var(--si-t-go); color: var(--si-ink-70); }
@media (min-width: 1100px) { .si-people { grid-template-columns: repeat(3, 1fr); } }

/* --- a legal text ----------------------------------------------------------
   One column, three levels, no ornament. Values from rechtstexte.md part B.
   720px is about 75 characters: a legal text is read, not skimmed.

   h3 is the third level -- 25.6/400 -- and it is the same size and the same role
   as the subheadings inside a news article: a heading that divides a flow of
   text rather than opening a section. */
/* No top margin of its own: the head section and this one already bring their
   own padding, and adding 48 on top made 172px where the delivery asks for 48.
   The number it lands on is reported rather than forced -- forcing it would
   mean taking the padding off one section, which breaks the page's rhythm for
   one page. */
.si-legal { max-width: 720px; }
.si-page .si-legal p { margin: 0 0 1.05rem; font-size: var(--si-t-tile); line-height: 1.62; color: var(--si-ink-70); }
.si-page .si-legal h2 { font-size: var(--si-h2); font-weight: 300; color: var(--si-ink); margin: var(--si-space-xl) 0 var(--si-head-gap); }
.si-page .si-legal h3 { font-size: var(--si-t-num); font-weight: 400; color: var(--si-ink); margin: var(--si-space-l) 0 .75rem; }
.si-page .si-legal :is(h2, h3):first-child { margin-top: 0; }
.si-legal ul, .si-legal ol { margin: 0 0 1.05rem; padding-left: 1.15rem; }
.si-page .si-legal li { font-size: var(--si-t-tile); line-height: 1.62; color: var(--si-ink-70); margin-bottom: .75rem; }
/* `overflow-wrap: anywhere` because a legal text quotes URLs in full, and one
   of them is 435px wide: at 360 the whole page could be pushed 99px sideways
   (measured on the Datenschutzerklaerung). A legal text cannot shorten its
   own links, so the setting has to allow the break. */
.si-legal a { color: var(--si-terra-ink); text-decoration: none; border-bottom: 1px solid var(--si-line);
  overflow-wrap: anywhere; }
.si-legal a:hover { border-color: var(--si-gold); }

/* --- the news card ---------------------------------------------------------
   Shell shared with .si-tile (see the selector lists above); innards its own --
   a header row instead of a symbol, no foot rule, and a lift on hover.
   Values from news.md part A. */
.si-na-grid { display: grid; gap: .9rem; margin-top: var(--si-space-l); }
@media (min-width: 820px) { .si-na-grid { grid-template-columns: 1fr 1fr; } }
.si-na { gap: .75rem; transition: transform .3s var(--si-ease, cubic-bezier(.16, 1, .3, 1)), border-color .3s; }
.si-na:hover { transform: translateY(-4px); border-color: var(--si-line); }
.si-na__head,
.si-report__head { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .8rem; }
/* The report head pushes its chip to the right edge. `width: 100%` is load-bearing:
   the card is `align-items: flex-start`, so without it the row is only as wide as
   its content and `space-between` has nothing to distribute. When the two marks no
   longer fit, `flex-wrap` drops the chip UNDER the eyebrow rather than out of the
   card. */
.si-report__head { width: 100%; justify-content: space-between; }
/* One rule, two selectors: the report card's chip IS the news card's chip, and
   writing it twice would be the second truth this sheet keeps taking out. */
.si-na__tag,
.si-report__tag {
  font-size: var(--si-t-micro); font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
  color: var(--si-gold-ink); background: var(--si-gold-wash);
  border: 1px solid var(--si-gold-wash-line); border-radius: 99px; padding: .22rem .6rem;
}
/* Tabular figures, so five dates under each other line up on the dot. */
.si-na__date { font-size: var(--si-t-micro); color: var(--si-ink-45); font-variant-numeric: tabular-nums; }
.si-page .si-na h3 { margin: 0; font-size: var(--si-t-q); font-weight: 500; letter-spacing: -.02em; line-height: 1.3; }
.si-page .si-na p { margin: 0; font-size: var(--si-t-tile); color: var(--si-ink-70); flex: 1; }
.si-na__go { display: flex; align-items: center; gap: .3rem; font-size: var(--si-t-go); font-weight: 500; color: var(--si-gold-ink); }
.si-na__go--off { color: var(--si-ink-45); border-bottom: 1px dashed currentColor; align-self: flex-start; }

/* --- the partner tile ------------------------------------------------------
   Shell shared with .si-tile above, innards its own: no hexagon, no family, and
   a foot that LEADS instead of naming who is behind it. The left edge stays gold:
   the mockup sets no category on these tiles either, so the fallback is the
   value -- not an omission. */
.si-rel__foot {
  margin-top: 1.4rem; padding-top: .9rem; border-top: 1px solid var(--si-line-soft);
  display: flex; align-items: center; gap: .55rem;
  font-size: var(--si-t-go); font-weight: 500; color: var(--si-cat, var(--si-gold));
}
/* No arrow while the target does not exist: it would promise a click the page
   cannot honour. The dashed rule is the same sign .si-tlink uses for it. */
/* The switched-off foot is the same shape as the live one, only muted -- it
   carries the arrow too since 2026-09-08. The dashed stub that stood here
   instead was a second vocabulary for 'not yet', and one sign everywhere was
   what Michael asked for. */
.si-rel__go--off, .si-na__go--off { opacity: .55; }

/* The three partner marks. Same component as the family mark, different
   vocabulary -- konzept-siassist, 2026-09-08. --si-cat rides along so the
   tile's left edge and the dot cannot drift apart. */
/* No `.si-rel .si-pident { color: inherit }` here, although it looks tidy: it is
   (0,2,0) and the three variants are (0,1,0), so it beat all three and every mark
   came out --si-ink. Measured, not reasoned. The dot already takes currentColor
   from the shared rule above. */

/* The three groups, each named once. */
.si-cat--innovation   { --si-cat: var(--si-gold);  --si-cat-ink: var(--si-gold-ink); --si-cat-wash: #FDF4DC; --si-cat-line: rgba(244, 180, 0, .45); }
.si-cat--analyse      { --si-cat: var(--si-ana);   --si-cat-ink: var(--si-ana-ink);  --si-cat-wash: #E7F1ED; --si-cat-line: rgba(66, 121, 106, .34); }
.si-cat--entscheidung { --si-cat: var(--si-dec);   --si-cat-ink: var(--si-dec-ink);  --si-cat-wash: #E5EEF4; --si-cat-line: rgba(58, 106, 140, .32); }

/* B5/6/8 si-split -- head left, list right. One form, three marks: a count, a
   bar, a check. Three components would be three truths for one grid. */
/* No max-width: the lead runs to the width of its own heading. The Scout
   settled the same question on 2026-09-01 -- there the element was
   is-sec__intro and Michael asked for the full width. Same thing, other sheet. */
/* No size of its own: the mockup's section leads are the base size, and 1.25rem
   is not a rung of its ladder. It read as a lead because it is grey and stands
   under a heading, not because it was 20px. */
/* 19px, because the mockup's section leads inherit ITS base of 19 and ours
   inherit 16 -- the same "no size of its own" produced two different sizes
   (konzept-siassist, 2026-09-08). The numbered section is the mockup's own
   exception: .appr__head p sets 1rem there, so --num keeps 16.
   Only the home page uses this class; the sub-pages have si-psec__lead. */
/* Bottom margin as well as top: the lead is the last line of a head group and
   whatever follows it is set differently -- a button, a card row, a filter bar.
   With none, the partner band's cards overlapped it by 16px and the buttons of
   the two split sections sat 18px under their text (Michael, 2026-09-08). */
.si-split__lead { font-size: var(--si-t-lead); color: var(--si-ink-70); margin: var(--si-head-gap) 0 var(--si-space-l); }
.si-split--num .si-split__lead { font-size: 1rem; }
/* The CTA is the last element of the head column and carried no spacing at all:
   the lead sets its own top margin, the button set none, so it sat flush under
   the paragraph -- 0px, measured in the draft by konzept-siassist on
   2026-09-08. The mockup groups head and button in one grid at gap: 1.1rem, so
   1.1rem is the delivered value; it is set here the way this sheet sets every
   other one, as a top margin on the element itself, like the lead above.
   Scoped to .si-split rather than to the button skin: si_split builds exactly
   one button and it is always this one. si_flow, si_cta and the contact card
   were measured in the same pass and are right as they stand -- a rule on
   .si-btn--gold would have moved those too. */
/* 0, not 1.1rem: the lead above it now carries the whole gap. Both together
   measured 50px where the section wants 32 (Michael, 2026-09-08). A button
   that does NOT follow a lead keeps this at 0 as well -- there is none on
   these pages, and the day one appears it should say its own distance. */
.si-split .btn { margin-top: 0; }
/* The measure belongs to the heading, not to the lead: with the head column
   grown from 4/12 to 5/12 and 6/12, a heading would otherwise run the whole
   width of it. The three values are the mockup's own (konzept-siassist,
   2026-09-01). The lead stays uncapped -- that was decided and does not move. */
.si-split--num h2   { font-size: var(--si-h2); max-width: 24ch; }
.si-split--bar h2   { font-size: var(--si-h2); max-width: 26ch; }
.si-split--check h2 { font-size: var(--si-h2); max-width: 22ch; }
/* .ins__grid is the one of the three that centres its two columns. */
.si-split--bar > .row { align-items: center; }
.si-split__list { display: grid; border-top: 1px solid var(--si-line); margin: 0; padding: 0; list-style: none; }
.si-split__list li {
  display: grid; grid-template-columns: auto 1fr; gap: var(--si-space-m); align-items: baseline;
  padding: .95rem .25rem; border-bottom: 1px solid var(--si-line-soft);
}
.si-split__list li::before { color: var(--si-ink-45); font-weight: 600; }
.si-split--num .si-split__list { counter-reset: si-split; }
.si-split--num .si-split__list li { counter-increment: si-split; }
.si-split--num .si-split__list li::before { content: counter(si-split, decimal-leading-zero); font-size: var(--si-t-micro); letter-spacing: .08em; font-variant-numeric: tabular-nums; }
/* NOT the same form with another mark. The delivery said "three sections, one
   component, three marks"; that holds for --num and --check, both ruled lists,
   and not for this one: the mockup's .topics are white cards with a 1px edge
   and a 6px radius, and no rules at all (konzept-siassist, 2026-09-01, who
   corrected their own delivery). The bar is a fixed 3 x 20, not a stretch --
   the cards are not all one height. */
.si-split--bar .si-split__list { border-top: 0; gap: .55rem; }
.si-split--bar .si-split__list li {
  align-items: center; gap: .85rem; font-size: var(--si-t-body);
  background: var(--si-surface); border: 1px solid var(--si-line-soft);
  border-radius: var(--si-radius); padding: .9rem 1.1rem;
}
.si-split--bar .si-split__list li::before {
  content: ""; width: 3px; height: 20px; background: var(--si-gold); border-radius: 2px;
}
.si-split--check .si-split__list li::before { content: "\f26e"; font-family: bootstrap-icons; color: var(--si-gold); }

/* The closing line is a foot, not a block: a rule above it, the sentence left,
   the button right on the same line -- the mockup's .flow__foot. It stacked,
   with the button below the sentence and no rule at all. The 820px breakpoint
   is the mockup's own; below it the two stack, which is what they should do. */
.si-flow__closing {
  border-top: 1px solid var(--si-line); padding-top: 1.75rem;
  display: grid; gap: 1.25rem; align-items: center;
}
@media (min-width: 820px) {
  .si-flow__closing { grid-template-columns: 1fr auto; }
}
/* Bootstrap's `p { margin-bottom: 1rem }` survives into the grid, and
   align-items centres the MARGIN box -- which put the sentence 8px above the
   button's centre. The gap between two items belongs to the container here,
   like everywhere else in this sheet. */
.si-flow__closing p { margin-bottom: 0; }

/* B7 si-partners -- three cards on the dark panel. Names as type, no logos:
   the same three marks twice on one page is repetition without gain. */
/* No radius and no padding of its own: it is a band across the window, and a
   band has no corners. The vertical rhythm comes from .si-sec like everywhere
   else, the width from the .container inside (konzept-siassist, 2026-09-01). */
.si-partners { background: var(--si-panel); color: var(--si-panel-ink); }
.si-partners h2, .si-partners .si-eyebrow { color: inherit; }
/* Two rules, and the pair is the point. `.si-page p` sets --si-ink-70 for every
   paragraph on the page, and on this ground that is dark green on dark green --
   so the panel needs a default of its own at the same weight (0,1,1). But that
   default then also beats `.si-partner__name` at (0,1,0), which is how the
   firm's name came to carry the ink of the sentence under it. Giving the name a
   second class is what lifts it clear.

   Both halves were only visible at the built page: removing the panel default
   made the name WORSE (1.81:1), because the rule it had been masking was the
   page-wide one. */
.si-partners p { color: var(--si-panel-ink-70); }
.si-partners .si-partner__name { color: var(--si-panel-ink); }
.si-partner {
  border: 1px solid var(--si-panel-line); border-radius: var(--si-radius-lg);
  padding: 1.35rem 1.5rem; background: rgba(255, 255, 255, .045);
  /* A hairline of light on the top edge -- on a dark ground that is the whole
     difference between a surface and a card. Its own value, like the hero's
     logo plates: --si-shadow lifts something off the page, this only draws an
     edge (konzept-siassist, 2026-09-02). */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .09);
  display: flex; flex-direction: column; height: 100%;
}
/* The brightest type on the card: it is the reason the card is there. */
.si-partner__name { font-size: var(--si-t-logo); font-weight: 500; letter-spacing: -.02em; margin: 0; }
.si-partner__what { margin: .45rem 0 0; font-size: var(--si-t-chip); color: var(--si-panel-ink-70); }
/* Gold on the dark panel: 6.08:1, the one place a raw mark carries type and
   the only one that passes (si-fundament.md, section 4). */
.si-partner__go {
  margin-top: auto; padding-top: .55rem;
  font-size: var(--si-t-go); font-weight: 500; color: var(--si-gold);
  display: inline-flex; align-items: center; gap: .55rem;
  /* Blockification, the same trap .si-tlink carries a note about: this is a flex
     item of the card, so `inline-flex` computes to `flex` and would stretch the
     full width of the card -- and the stroke would then sit at its far edge
     instead of after the words. */
  align-self: flex-start;
}
/* It carried the mockup's stroke until 2026-09-08 -- 20px, drawn at 60% and
   growing on hover. Michael asked for ONE sign across the site rather than a
   stroke here and an arrow on the link right below it, and the two sat on the
   same dark band a few pixels apart. So this takes the arrow like every other
   live text link, and the hover moves it the same way.
   The stroke is not "wrong" and it is the mockup's; being the only one of its
   kind is what made it go. */
.si-partner__go .bi { transition: transform .25s var(--si-ease, cubic-bezier(.16, 1, .3, 1)); }
.si-partner:hover .si-partner__go .bi { transform: translateX(3px); }

/* Link left, funding notice right, on one line -- the mockup's .pband__foot.
   Stacked, the white plate landed in the middle of the line. */
.si-partners__foot {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 1.25rem 2rem; padding-top: 1.6rem; border-top: 1px solid var(--si-panel-line);
}

/* On the dark band the link takes the panel's own line and ink -- as the mockup
   does, where .pband .tlink inherits --panel-ink. Both states needed it and for
   the same reason: the active one came out terracotta on dark green (2.65:1),
   the switched-off one would have read --si-ink-70, which is dark green on dark
   green. */
.si-partners .si-tlink { color: inherit; border-color: var(--si-panel-line); }
.si-partners .si-tlink[aria-disabled="true"] { color: var(--si-panel-ink-70); }

/* The funding logo is a JPEG and cannot be transparent, so it gets its own
   white plate rather than a white rectangle in a dark band. */
.si-partners__funding { background: var(--si-surface); border-radius: var(--si-radius); padding: var(--si-space-m); display: inline-flex; }
.si-partners__funding { max-width: 100%; }
/* The funding logo is the only image on the page without a cap, and it is
   13888x2000 -- at height:60px that is 417px, wider than a phone. It pushed
   89px past the window edge at 360 (konzept-siassist, 2026-09-08). Capping the
   HEIGHT rather than setting height:60px keeps the aspect ratio while the width
   is free to shrink. */
.si-partners__funding img { max-height: 60px; max-width: 100%; height: auto; width: auto; display: block; }

/* B9 si-cta -- two equal fields. */
.si-cta__pair { display: grid; gap: var(--si-space-m); }
/* align-items: flex-start is what keeps the button the width of its own words.
   Without it the two buttons here were the only ones on the page that stretched
   -- 586.7px against the 187-227px of the other five (konzept-siassist,
   2026-09-01). Paragraphs are unaffected: a text block sized by content still
   fills the container, because fit-content is capped by what is available. */
.si-cta__box { background: var(--si-surface); border: 1px solid var(--si-line-soft); border-radius: var(--si-radius-lg); padding: var(--si-space-l); box-shadow: var(--si-shadow); display: flex; flex-direction: column; align-items: flex-start; gap: .75rem; height: 100%; }
/* The button gets the mockup's SECOND value on top of the card's gap -- .75 + .85
   is the 26px that sets the action apart from the sentence above it, where one gap
   would space it like any other line (konzept-siassist, 2026-09-08). */
.si-cta__box .btn { margin-top: .85rem; }
/* The mockup's 1.2rem is not on the ladder; 1.25rem is the declared step above
   it, and Bootstrap's h3 (28px) was two steps too big for a card heading. */
.si-cta__box h3 { margin: 0; font-size: var(--si-t-card); font-weight: 500; }
.si-cta__box p { margin: 0; flex: 1; }

@media (min-width: 768px) {
  .si-cta__pair { grid-template-columns: 1fr 1fr; }
}

/* --- the rail, the nodes on it, and the chevron between the cards ---------- */

/* The ladder is written out instead of left to auto-fill, because auto-fill
   cannot see the difference that matters here. Bootstrap's .container steps
   540 -> 720 at 768, so the grid is 492px wide at EVERY width from 540 to 767 --
   a 600px window and a 700px one are the same number of columns to auto-fill,
   whatever the minmax. The mockup flips to two at 600 (konzept-siassist measured
   `.bento`, 2026-09-08), and only a media query can say that.

   It also keeps what auto-fill got wrong at the other end: alone it put FIVE
   251px tiles in a 1320px row and broke three of the nine titles over two lines.
   Below 600 auto-fill still governs and yields one column. */
@media (min-width: 600px) {
  .si-tiles__grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 992px) {
  .si-tiles__grid { grid-template-columns: repeat(3, 1fr); }
}

@media (min-width: 992px) {
  .si-flow__steps { grid-template-columns: repeat(3, 1fr); }

  /* The sign between two cards sits in the gap, on half the card's height. Not
     the mockup's rotated box -- bi-chevron-right, like every other sign on this
     page. */
  .si-step:not(:last-child) .si-step__card::after {
    content: "\f285";
    font-family: bootstrap-icons;
    position: absolute;
    top: 50%;
    right: calc(-1 * var(--si-space-l) / 2);
    transform: translate(50%, -50%);
    color: var(--si-gold);
    opacity: .75;
    line-height: 1;
  }
}

@media (min-width: 1000px) {
  .si-flow__rail {
    display: block;
    position: absolute;
    left: 0;
    right: 0;
    /* Half the node row minus half the line: the rail runs through the middle
       of the dots, and both come from --si-node-h. */
    top: calc(var(--si-steps-pad) + var(--si-node-h) / 2 - 1px);
    height: 2px;
    background: linear-gradient(90deg, #C85A2E 0%, #F4B400 50%, #2F3E3A 100%);
    opacity: .32;
    transform-origin: left;
  }

  /* It runs out from the left when the section is scrolled to. The generic
     .si-rv rule would fade and lift it instead, which is wrong for a line -- so
     the rail overrides both properties. Without JavaScript neither rule applies
     and the rail simply stands there, drawn. */
  .si-js .si-flow__rail.si-rv {
    opacity: .32;
    transform: scaleX(0);
    transition: transform 1.4s cubic-bezier(.16, 1, .3, 1);
  }

  .si-js .si-flow__rail.si-rv--in { transform: scaleX(1); }
}

/* ===========================================================================
   The sub-page layer

   The home page opens the site; these open a page. Same vocabulary, different
   rhythm -- the sections are tighter, they carry a hairline, and the head is a
   different animal from the hero. Values are the delivery's own, resolved from
   the mockup (konzept-siassist, "Loesungen", part A).
   =========================================================================== */

/* --- Breadcrumb ------------------------------------------------------------
   The separator is the sheet's chevron, not the mockup's inline <svg>: the text
   plugin drops <svg> outright. Half opacity, so it reads as punctuation. */
.si-crumb { padding-top: clamp(1.5rem, 3vw, 2.25rem); display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; font-size: var(--si-t-chip); color: var(--si-ink-45); }
/* --si-ink-70, not --si-ink-45: the breadcrumb is a link and 45 measures
   2.85:1, the lowest value on the site (Michael through konzept-siassist,
   2026-09-23).

   ⚠ DECIDED, do not re-open — the other half of the same decision: the site
   paints links in ONE orange, `--si-terra-ink` (#B85028, 4.68:1), set in
   `cms_core.css` line 49. The lighter #C85A2E is gone from every link; measured
   on 17 rendered pages afterwards, one orange remains and no link falls below
   4.68:1. Hover became the ink, because #a84924 sits 1.16:1 from the new
   resting colour and would read as the same colour. */
.si-crumb a { color: var(--si-ink-70); text-decoration: none; }
.si-crumb a:hover { color: var(--si-ink); }
.si-crumb .bi { opacity: .5; }
.si-crumb [aria-current="page"] { color: var(--si-ink); }

/* --- The family mark -------------------------------------------------------
   The dot takes its colour from the family class the tiles already use, so a
   family is named in exactly one place. */
.si-pident { display: flex; align-items: center; gap: .5rem; margin: 0; font-size: var(--si-t-tag); font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--si-ink-70); }
.si-pident__dot { width: 9px; height: 9px; border-radius: 50%; background: currentColor; }
/* Gold, not terracotta. The family's own token is --si-cat-ink, which every
   family already sets -- naming the colour a second time here is what let this
   one drift (konzept-siassist, 2026-09-08). */
.si-cat--innovation .si-pident__dot, .si-pident.si-cat--innovation { color: var(--si-cat-ink); }
.si-cat--analyse .si-pident__dot, .si-pident.si-cat--analyse { color: var(--si-ana-ink); }
.si-cat--entscheidung .si-pident__dot, .si-pident.si-cat--entscheidung { color: var(--si-dec-ink); }

/* --si-terra-ink (#B85028) and NOT the delivery's #C85A2E, which is --si-terra:
   that is the raw mark and carries type at 3.98:1, under the floor for a 12.2px
   uppercase label. Same call as .si-tlink two hundred lines up, and the same one
   the contrast guard already records for four other roles. The other two are the
   delivery's own values: #5C4A08 is --si-gold-ink (the delivery calls it
   --si-gold-wash-ink, a second name for a colour we have), #2F3E3A is --si-ink. */
.si-page .si-pident--tecintelli { color: var(--si-terra-ink); }
.si-page .si-pident--appose     { color: var(--si-gold-ink); }
.si-page .si-pident--fraunhofer { color: var(--si-ink); }
/* `.si-page` in front is what makes these work, and it took three measurements
   to find out. The mark is a <p>, so `.si-page p` (0,1,1) outranks a bare
   `.si-pident--appose` (0,1,0) and all three rendered --si-ink-70 -- the same
   value the base rule sets, which is why it looked like the base rule winning
   and sent me after source order first. It is the fourth appearance today of the
   trap in CLAUDE.md's Gotchas. Keep the block after `.si-pident` all the same:
   with the page class they are (0,2,0) and order no longer decides, but a later
   reader moving them back would restore half the bug. */


/* --- The page head ---------------------------------------------------------
   The two washes are the hero's, on the section itself -- no bg element. */
.si-phero {
  position: relative; overflow: hidden;
  padding: clamp(1.75rem, 4vw, 2.75rem) 0 clamp(2.5rem, 5vw, 3.75rem);
  background-image:
    radial-gradient(70% 90% at 88% 8%, rgba(244, 180, 0, .16), transparent 62%),
    radial-gradient(55% 70% at 2% 96%, rgba(209, 231, 221, .5), transparent 60%);
}
.si-phero h1 { font-size: var(--si-h1); max-width: 24ch; margin: 1rem 0 0; }
/* EcoNa's second line: smaller, and part of the same heading -- not an h2. */
.si-phero__second { display: block; font-size: .6em; }
/* `.si-page` in front is load-bearing, not decoration: `.si-page p` (0,1,1) beat
   the bare class (0,1,0), so this line said --si-ink and the page rendered
   --si-ink-70. It is the sentence the page is built around; at 1.6 and grey it
   read as a second-order lead (konzept-siassist, 2026-09-08). */
.si-page .si-phero__q { font-size: clamp(1.08rem, 1.7vw, 1.28rem); line-height: 1.4; color: var(--si-ink); max-width: 44ch; margin: 1.1rem 0 0; }
.si-phero__promise { color: var(--si-ink-70); max-width: 52ch; margin: 1rem 0 0; }
/* PADDING, not margin. The plugin emits `m-0` and Bootstrap hangs !important on
   it, so the margin that stood here was dead on arrival and the gold button sat
   on the baseline of the sentence above it -- 0px, on all ten pages
   (konzept-siassist, 2026-09-08). 2.4rem is the mockup's value. */
/* A row, because a page head may carry two actions -- gold first, pale beside
   it (partner.md part B: 13.6px between them). Flex and not a margin: the
   plugin emits m-0, as everywhere. */
.si-phero__cta { padding-top: 2.4rem; display: flex; flex-wrap: wrap; gap: .85rem; }
.si-phero__side { display: grid; gap: .9rem; align-content: start; justify-items: start; }
/* The ministry's picture in a page head wears the same plate as in the partner
   band: it is a JPEG and cannot be transparent, so without one its own white
   ground stands as a hard rectangle on the hero's wash. "Dasselbe wie auf der
   Startseite" (Michael, 2026-09-08) includes the plate it sits on there. */
.si-phero__plate {
  background: var(--si-surface); border-radius: var(--si-radius);
  padding: var(--si-space-s); max-width: 100%;
}
.si-phero__plate img { display: block; width: 100%; height: auto; }
/* From 960px the side column sits at the BOTTOM RIGHT of the head, against the
   baseline of the heading block beside it. The delivery says so -- "Seitenspalte
   417 px breit, ab 960 px rechtsbuendig" (loesungen.md part B, and again in
   partner.md) -- and I built only the width. Michael saw it on the contact page
   (2026-09-08); it was wrong on all four kinds of sub-page.

   `align-items: end` goes on the row, not on the column: the column cannot move
   itself to the bottom of a flex line, only the line can put it there.

   992 and not the delivery's 960, and the difference is measured: our columns
   are Bootstrap's `col-lg`, which stack below 992. Between 960 and 991 the
   delivery's number would have produced a column standing UNDER the heading and
   still right-aligned, which is neither shape. The rule follows where the
   columns actually sit beside each other. */
@media (min-width: 992px) {
  .si-phero .row { align-items: end; }
  .si-phero__side { justify-items: end; text-align: right; }
}
.si-byline { margin: 0; font-size: var(--si-t-chip); color: var(--si-ink-45); }
.si-byline b { display: block; font-size: 1rem; font-weight: 500; color: var(--si-ink); }
.si-soon { margin: .75rem 0 0; }
/* The mark is a PILL, and that is the one place this sheet allows one -- the
   foundation reserves pills for stage names and filter buttons, and "In
   Entwicklung" is a stage name. It had become the nearest existing tag instead,
   because the delivery named the mark without giving it values; measured
   12,16/500 flat grey where the mockup has 11,2/600 in gold on gold
   (konzept-siassist, 2026-09-08). */
.si-soon__tag {
  display: inline-block; padding: .28rem .68rem;
  border: 1px solid var(--si-gold-wash-line); border-radius: 99px;
  background: var(--si-gold-wash); color: var(--si-gold-ink);
  font-size: var(--si-t-soon); font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
}

/* --- A section of a sub-page ----------------------------------------------
   Tighter than .si-sec and with a hairline above; --plain drops the line for
   the opening section, which would otherwise draw one right under the head. */
.si-psec { padding-block: clamp(2.5rem, 5vw, 4rem); border-top: 1px solid var(--si-line-soft); }
.si-psec--plain { border-top: 0; }
.si-psec > .row { align-items: start; }
.si-psec h2 { font-size: var(--si-h2); max-width: 22ch; margin: 0; }
.si-psec__lead { color: var(--si-ink-70); max-width: 62ch; margin: 0 0 1.4rem; }

/* --- Running text, checked list, numbered list ----------------------------- */
.si-prose { display: grid; gap: 1.05rem; max-width: 68ch; }
.si-prose p { margin: 0; color: var(--si-ink-70); }

.si-checks { display: grid; gap: .9rem; max-width: 68ch; margin: 0; padding: 0; list-style: none; }
/* A checked list is a differently-set block, so whatever follows it keeps the
   section's distance -- 32px, fundament sec 18. It stood at 0 twice on
   "Ueber SIAssist" (Michael, 2026-09-08). The sibling selector fires only when
   something actually follows: a list that ends its section keeps its own
   spacing and does not push the section's padding out. */
.si-checks + * { margin-top: var(--si-space-l); }
.si-checks li { display: grid; grid-template-columns: auto 1fr; gap: .75rem; align-items: start; color: var(--si-ink-70); }
/* The tick is a pseudo-element, like .si-split--check: a decoration has no
   business in the content. */
.si-checks li::before { content: "\f26e"; font-family: bootstrap-icons; line-height: 1; color: var(--si-gold); transform: translateY(4px); }

.si-steps { display: grid; border-top: 1px solid var(--si-line); max-width: 74ch; margin: 0; padding: 0; list-style: none; counter-reset: si-steps; }
.si-steps li { display: grid; grid-template-columns: auto 1fr; gap: 1rem; align-items: baseline; padding: .95rem .25rem; border-bottom: 1px solid var(--si-line-soft); color: var(--si-ink-70); counter-increment: si-steps; }
/* Counted, never typed -- same rule as si_split--num and the Scout's chapters. */
.si-steps li::before { content: counter(si-steps, decimal-leading-zero); font-size: var(--si-t-micro); font-weight: 600; letter-spacing: .08em; font-variant-numeric: tabular-nums; color: var(--si-ink-45); }

/* --- The framed box (EcoNa) ------------------------------------------------ */
/* 666px and not 74ch. Our ch is not the mockup's ch -- the head groups of the
   home page made that expensive once already, so the width the mockup renders to
   is written as the number it renders to (konzept-siassist, 2026-09-08: we ran
   1272px where the mockup runs 666).

   The size is --si-t-link (14.72) and not the mockup's .93rem (14.88). The
   ladder guard refused the raw value, rightly: 0.16px is exactly the size of
   difference konzept-siassist himself ruled not worth a new rung
   (2026-09-08), and an undeclared value is how a ladder stops being one. */
.si-frame { background: var(--si-fill); border-radius: var(--si-radius-lg); padding: clamp(1.3rem, 2.2vw, 1.7rem); max-width: 666px; font-size: var(--si-t-link); }
.si-frame__label { margin: 0 0 .6rem; font-size: var(--si-t-micro); font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--si-ink-45); }
.si-frame p { margin: 0 0 .8rem; color: var(--si-ink-70); }
.si-frame p:last-child { margin-bottom: 0; }

/* --- The closing box -------------------------------------------------------
   A panel inside the track, not a band: _section and not _ground. A ground
   reaching the window would square its 12px corners off against the viewport. */
.si-close { padding-block: clamp(2.75rem, 6vw, 4.5rem); }
.si-close__in { background: var(--si-panel); border-radius: var(--si-radius-lg); padding: clamp(1.75rem, 4vw, 2.75rem);
}
.si-close__in h2 { font-size: var(--si-h2); max-width: 26ch; margin: 0; color: var(--si-panel-ink); }
/* 1.5rem above, not 1rem: the head group's gap, so this box does not sit at 16
   while every other heading on the page sits at 24 (konzept-siassist,
   2026-09-08 -- "sonst tauschen wir eine Uneinheitlichkeit gegen die naechste"). */
.si-close__in p { margin: var(--si-head-gap) 0 1.5rem; font-size: 1rem; color: var(--si-panel-ink-70); max-width: 56ch; }

/* AFTER the base rules above, not before them: this block and
   `.si-close__in p` tie on specificity, so the later one wins. Placed first, the
   paragraph kept its 1rem/1.5rem margins, they went into the grid row, and the
   button -- centred across the rows -- came out 12px off the text's middle.
   Measured twice before I looked at the order.

   Text left, button right, both on the middle line -- the mockup builds
   `.close__in` as a two-column grid (783/257 at 1400, align-items: center) and
   ours was a plain block, so the button dropped underneath (Michael, 2026-09-08).
   From 992 only: below it the two stack, which is right on a phone. */
@media (min-width: 992px) {
  .si-close__in {
    display: grid; grid-template-columns: 1fr auto; align-items: start;
    column-gap: var(--si-space-xl);
  }
  /* The three are direct children -- heading, sentence, button -- with no
     wrapper around the text, so the columns are assigned by hand. Left to the
     grid's own order the sentence would have gone into the button's column. */
  .si-close__in h2, .si-close__in p { grid-column: 1; }
  /* Two things here, and both were measured wrong first.

     `span 2`, not `1 / -1`: the rows are IMPLICIT (nothing declares
     grid-template-rows) and -1 counts the last line of the EXPLICIT grid, which
     is line 1 -- so `1 / -1` silently became one row and the button centred
     against the heading alone, 46px too high.

     And the container aligns its items to START, not center. With `center` every
     item floats in the middle of its row, including the sentence -- and the
     button, spanning both rows, made those rows taller than the text. The button
     then centred against rows that were not the text: 12px out. Items at the top,
     button centred across their span, and the two middles are the same. */
  .si-close__in .btn { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
  /* The sentence's margins become the grid's row gap. As margins they sat INSIDE
     the row, so the button -- centred across both rows -- came out 12px above the
     text's own middle. Measured; as a gap the rows are exactly the two elements
     and the centre is true. */
  .si-close__in { row-gap: var(--si-head-gap); }
  .si-close__in p { margin: 0; }
}


.si-tiles {
  background: linear-gradient(180deg, transparent, var(--si-sol-band) 14%, var(--si-sol-band) 86%, transparent);
  border-block: 1px solid var(--si-line-soft);
}

/* The note under the tile grid is ONE line -- sentence and link beside each
   other, both quiet. Ours stacked them and painted the link terracotta; the
   mockup lets it inherit (konzept-siassist, 2026-09-08).

   --si-ink-70 and not the mockup's --ink-45: a whole sentence takes ink-70, a
   label without sentence structure takes ink-45 (konzept-siassist, 2026-09-08,
   after this sheet had briefly carried both). ink-45 is 3.03:1. */
.si-tiles__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.75rem;
  font-size: var(--si-t-note); color: var(--si-ink-70);
}
.si-tiles__foot p { margin: 0; color: inherit; }
.si-tiles__foot .si-tlink { font-size: inherit; color: inherit; }

/* The closing line of the numbered section, same voice as the note above. */
/* 1.4rem above it: the closing sentence sat flush on the numbered list, 0px
   (Michael, 2026-09-08). The value is the mockup's own -- `.appr__out` carries
   margin-top: 22.4px there, measured -- so it is taken, not chosen. */
.si-page .si-split__out { font-size: var(--si-t-note); color: var(--si-ink-70); margin-top: 1.4rem; }

/* Only the hero's eyebrow. `.si-page p` (0,1,1) outranks `.si-eyebrow` (0,1,0),
   so it took --si-ink-70; in the mockup it is --ink-45. The other five are
   --ink-70 there too, because .flow__head p and its siblings do the same --
   so this is one rule for one place, not a sweep.

   ⚠ DECIDED, do not re-open (Michael through konzept-siassist, 2026-09-23).
   This line measures 2.85:1 against the section ground, below the 4.5:1 that
   11.5px type needs, and it stays that way deliberately. Fifteen of the site's
   eighteen eyebrows render at --si-ink-70 (5.1:1); this one and the two INSIGHTS
   cards are the exceptions and are meant to be. */
.si-hero .si-eyebrow { color: var(--si-ink-45); }

/* The box text in the closing section: .97rem, not the 1rem it inherited. */
.si-cta__box p { font-size: var(--si-t-tile); }

/* A list of text links, one per line. The delivery of the two webinar posts asks
   for 12px between them (news-webinare.md, part A).

   The rule sits on the WRAPPER, and it has to: `.si-tlink` is `inline-flex`
   everywhere on these pages -- inside running text, beside buttons, in tile feet
   -- and making it a block would break all three. Measured before this existed:
   three of the four links stood on one line and the fourth wrapped, and where
   the break fell moved with the window width.

   `justify-items: start` so a link is as wide as its words and its underline
   ends with them, not at the column edge. */
.si-links {
  display: grid;
  justify-items: start;
  gap: 12px;
}

/* --- The article flow of a news post ---------------------------------------
   Everything under the post head sits in ONE column, and only `.si-prose--wide`
   carried a top margin there: it has `margin-top: 2.75rem`, which is the 44 the
   flow is built on. Every other block was written to be the single child of a
   section of its own -- EcoNa's frame is exactly that -- so the section did the
   spacing and nobody noticed the component has none. In a news post they follow
   each other directly and stood at 0 (Michael, 2026-09-09).

   `.si-natop ~` is the scope, and it is the precise one: the post head exists on
   no other page, so this reaches the article flow and nothing else. A block that
   is the first child of its section is untouched -- which is why EcoNa's frame
   does not move.

   No new value. 44 is `.si-prose--wide`'s own margin, 24 is the gap a subheading
   already has to its first paragraph, 20 binds a button to its box and 12 is the
   gap inside the link list. */
.si-page .si-natop ~ :is(.si-steps, .si-checks, .si-frame, .btn) { margin-top: 2.75rem; }

/* ⚠ The two blocks of this flow that are PLUGIN elements carry
   djangocms-frontend's `m-0`, and Bootstrap's spacing utilities are
   `!important` -- so a plain margin on them is dead on arrival. Only another
   `!important` beats one; the navbar's Kontakt button says the same thing forty
   lines up, for the same reason.

   Padding was the first answer here and it is the wrong one twice over. On
   `.si-links` it works but measures as 0 between the boxes, so the gap is real
   and invisible to anyone checking it. On `.si-invite` it does not work at all:
   the block has a coloured surface, and padding would extend the wash instead of
   setting it apart -- the gold panel sat flush against the link list
   (konzept-siassist, measured on the published posts, 2026-09-09).

   One mechanism for both, so the flow measures the way it looks. */
.si-page .si-natop ~ :is(.si-links, .si-invite) { margin-top: 2.75rem !important; }

/* A button belongs to the box above it and must not be pushed away from it. */
.si-page .si-natop ~ .si-frame + .btn { margin-top: 1.25rem; }

/* A subheading belongs to what it announces. With 44 it would stand further from
   its own list than from the paragraph above it, so a prose block that ENDS in a
   subheading keeps the 24 it uses inside itself. */
.si-page .si-natop ~ .si-prose:has(> .si-prose__h:last-child) + :is(.si-steps, .si-checks, .si-frame, .si-links) {
  margin-top: 1.5rem;
}

/* The loud light box of an article flow (si_invite). Michael, 2026-09-09: the
   contact block "geht etwas verloren" as a 666px frame with the button beside
   it -- and the dark version he asked for first was taken back in the same
   hour, because the post would then end with two dark panels.

   So it keeps everything that made it visible except the darkness: the width of
   its column instead of the text measure, a surface instead of a hairline box,
   and the button inside.

   No new colour. --si-gold-wash and --si-gold-wash-line are the two tokens the
   news card's label chip already carries; this is the same accent used as a
   surface. */
.si-page .si-invite {
  background: var(--si-gold-wash);
  border: 1px solid var(--si-gold-wash-line);
  border-radius: var(--si-radius-lg);
  padding: clamp(1.75rem, 4vw, 2.75rem);
}
.si-page .si-invite h2 { font-size: var(--si-t-num); font-weight: 400; max-width: 30ch; margin: 0; color: var(--si-ink); }
.si-page .si-invite p { margin: var(--si-head-gap) 0 1.5rem; color: var(--si-ink-70); max-width: 56ch; }

/* From 820px the button stands BESIDE the text, not under it (Michael,
   2026-09-09). 820 is not a new breakpoint -- it is the one at which the card
   grid already goes to two columns.

   `align-items: start` on the container and `align-self: center` on the button
   alone: `align-items: center` would centre EVERY item, which floated a whole
   section once already (2026-09-08). And `grid-row: 1 / span 2`, not `1 / -1` --
   that counts explicit lines only, and with none declared it collapsed to a
   single row the last time it was written that way.

   The paragraph loses its bottom margin here: it was the gap to a button
   underneath, and there is none underneath any more. */
@media (min-width: 820px) {
  .si-page .si-invite {
    display: grid;
    grid-template-columns: 1fr auto;
    column-gap: 2rem;
    align-items: start;
  }
  .si-page .si-invite h2,
  .si-page .si-invite p { grid-column: 1; }
  /* The paragraph gives up its 56ch here. In one column that cap is what keeps a
     line readable; in two, the button's edge is the measure -- and with the cap
     the text stopped 404px short of the button at 1970, so the "gap" read as
     436 instead of 32 (measured 2026-09-09). */
  .si-page .si-invite p { margin-bottom: 0; max-width: none; }
  .si-page .si-invite .btn { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
}

/* The Use Case page carries the article flow of a news post without being one:
   no si_natop, so the rules above cannot reach it. `.si-uc` is the same flow
   under a second anchor -- the values are not repeated, the selector list is.

   Written out rather than added to the selectors above with a comma, because the
   two scopes are different things: one is "inside a news post", the other is
   "inside this page's article". A shared selector would tie them together and
   the next page of this kind would have to join the same list. */
.si-page .si-uc :is(.si-steps, .si-checks, .si-frame, .si-facts, .btn) { margin-top: 2.75rem; }
/* ⚠ `.si-na-grid` belongs in the !important list and not the one above: it is a
   PLUGIN element and carries `m-0`. Measured at 0 before it was moved -- the
   fourth time this sheet has paid for that trap, and the first time I caught it
   in the same hour. The others here (.si-steps, .si-checks, .si-frame,
   .si-facts) are markup a text plugin writes, so a plain margin holds. */
/* ⚠ .si-reports joins the !important list, and it is the FIFTH element to need
   it: every one of these is a plugin element carrying `m-0`. Measured at 0
   before it was moved. */
.si-page .si-uc :is(.si-links, .si-invite, .si-na-grid, .si-reports) { margin-top: 2.75rem !important; }
.si-page .si-uc .si-frame + .btn { margin-top: 1.25rem; }
.si-page .si-uc .si-prose:has(> .si-prose__h:last-child) + :is(.si-steps, .si-checks, .si-frame, .si-facts, .si-links) {
  margin-top: 1.5rem;
}

/* si_steps as cards. A trial Michael asked for on the Use Case page -- „ja
   versuche es erstmal so" -- and therefore a CLASS on the existing component and
   not a component of its own: the data, the counter and the <span> wrapper are
   unchanged, and a second component would make a trial permanent.

   The list loses its rules and its rows: `.si-steps li` is a grid of
   `auto 1fr`, which puts the number beside the text. In a card the number sits
   ABOVE it, so the item becomes a block and the ::before a block with it. */
.si-page .si-steps--cards {
  display: grid;
  gap: 1rem;
  grid-template-columns: 1fr;
  border-top: 0;
  max-width: none;
}
@media (min-width: 820px) { .si-page .si-steps--cards { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1200px) {
  .si-page .si-steps--cards { grid-template-columns: repeat(3, 1fr); }
  /* Four cards stay at two columns: three across leaves one alone on the second
     row, and a 2x2 block reads as a set where 3+1 reads as a leftover. The
     delivery asks for 1 · 2 · 2 for the four (konzept-siassist, 2026-09-10).
     `:has(> li:nth-child(4):last-child)` says "exactly four", not "at least" --
     it is the fourth item AND the last. */
  .si-page .si-steps--cards:has(> li:nth-child(4):last-child) { grid-template-columns: repeat(2, 1fr); }
}

/* Dark, so the two sets lift off the page (Michael, 2026-09-10: „sodass sie
   dunkel sind und sich damit etwas mehr abheben"). No new colour: --si-panel and
   its two inks are what si_close and the process band already use.

   No border. The hairline was there to separate a white card from a white page;
   on the dark ground it would draw a line around a shape that already stands for
   itself, and --si-panel-line is meant for divisions INSIDE a panel. The shadow
   goes for the same reason -- it is a shadow of the light layer.

   The number is gold: on the dark ground it is the card's mark, the way the dot
   and the number carry the process band. */
.si-page .si-steps--cards li {
  display: block;
  background: var(--si-panel);
  border: 0;
  border-radius: var(--si-radius-lg);
  padding: clamp(1.15rem, 2.2vw, 1.5rem);
  color: var(--si-panel-ink-70);
  transition: transform .25s cubic-bezier(.16, 1, .3, 1);
}
.si-page .si-steps--cards li:hover { transform: translateY(-4px); }
/* The number stands above the title, the way the process band sets its stops. */
.si-page .si-steps--cards li::before {
  display: block;
  margin-bottom: .75rem;
  color: var(--si-gold);
}
/* The title takes the panel's full ink, the sentence its 72% -- the same two
   steps the newsletter panel uses for its heading and its line.
   
   Through the TOKEN, not through a rule on `strong`. `.si-page strong` reads
   `var(--si-ink)` and is the one place emphasis is set, which a guard holds --
   it caught the first version of this, correctly. Redefining the token inside
   the card is the sheet's own mechanism and leaves that single rule intact. */
.si-page .si-steps--cards li { --si-ink: var(--si-panel-ink); }

/* The two Insights report cards. Michael, 2026-09-10: the frames were too pale.
   Measured then: 4% ink, no border, and 666px wide against a text column of 816
   -- narrower than the running text around them, so nothing carried them.

   The surface is the tile's, the chip is the news card's (it shares that rule),
   the heading is --si-t-num at 400. No gold ground: the initiative box holds
   that on this page, and two gold surfaces would compete. Not dark either: the
   two step sets are. */
.si-page .si-reports { display: grid; gap: .9rem; }
@media (min-width: 820px) { .si-page .si-reports { grid-template-columns: 1fr 1fr; } }
.si-page .si-report {
  display: flex; flex-direction: column; align-items: flex-start; gap: .75rem; height: 100%;
  background: var(--si-surface);
  border: 1px solid var(--si-line);
  border-radius: var(--si-radius-lg);
  padding: clamp(1.35rem, 2.6vw, 1.75rem);
  transition: transform .3s cubic-bezier(.16, 1, .3, 1), border-color .3s;
}
/* No shadow: with one the pair read as too dominant beside the two dark step
   sets (Michael, 2026-09-10). The hairline carries the card on its own -- which
   is what the tiles of the solutions overview do as well. */
.si-page .si-report:hover { transform: translateY(-4px); }
/* ⚠ The colour has to be repeated here, and that is a symptom, not a choice:
   `.si-eyebrow` declares --si-ink-45 at (0,1,0) and `.si-page p` sets --si-ink-70
   at (0,1,1), so every eyebrow that is a <p> loses. Measured across the site --
   nearly all of them render at ink-70, not at the 45 the sheet says.

   ⚠ DECIDED, do not re-open (Michael through konzept-siassist, 2026-09-23). The
   two INSIGHTS cards measure 3.03:1 on their white ground and stay light on
   purpose, as does the hero line on the home page (2.85:1). The discrepancy
   between what this sheet declares and what renders is therefore NOT a defect
   waiting to be fixed: ink-70 everywhere else is the accessible outcome, and
   these three are the deliberate exceptions. */
.si-page .si-report .si-eyebrow { margin: 0; color: var(--si-ink-45); }
/* The tile heading's size, and it is 19.2 -- the delivery says 18.56, which is
   --si-t-name, the line that carries a card's ORGANISATION. Named intent beats a
   number read off the wrong element; reported rather than silently split. */
.si-page .si-report h3 { margin: 0; font-size: var(--si-t-card); font-weight: 500; color: var(--si-ink); }
.si-page .si-report p { margin: 0; color: var(--si-ink-70); }


/* ===========================================================================
   The editable vocabulary -- classes for pages built from STANDARD plugins
   ===========================================================================
   Every rule below attaches to a class on the element that carries it. None of
   them crosses a plugin boundary with `+`, `~`, `>` or `:nth-child`, and that is
   the whole point: django CMS wraps each plugin in edit mode, which breaks every
   sibling and child relation. Measured on 2026-09-22: the old vocabulary shifted
   all 26 blocks of the Use Case page and lost 161px of page height in edit mode.

   The spacing rhythm therefore lives on the CONTAINER as a `gap`, not on the
   blocks as margins. A gap survives the wrappers, because the wrapper takes the
   block's place in the flow. It also sidesteps Bootstrap's `m-0 !important`,
   which killed five margin rules in this sheet before.
   =========================================================================== */

.si-page .si-e-article {
  display: flex;
  flex-direction: column;
  gap: 2.75rem;
  /* The first block needs the same distance from the page head that every other
     block has from its predecessor. A `gap` does not apply before the first
     child, so it is padding -- ON TOP of the section's own, which is why the
     clamp is repeated instead of replaced. Writing `padding-top: 2.75rem` alone
     swallowed the section padding and moved the whole page up by 20px. */
  padding-top: calc(clamp(2.5rem, 5vw, 4rem) + 2.75rem);
}

/* A heading that introduces the block right below it stands closer to it. There
   is no `+` here: the tighter distance is a property of the heading, chosen by
   whoever places it -- which is what makes it editable. */
/* ⚠ The -20px below a heading belongs to the ARTICLE, where the blocks are laid
   out with a gap. On a page that lays them out one after another the heading
   carries what `.si-prose__h` carried: .75rem above and nothing below. Ancestry
   is safe to select on -- edit mode wraps plugins, it does not reparent them. */
.si-page .si-e-article .si-e-h { margin: 0 0 -20px; }
.si-page .si-e-h {
  font-size: var(--si-t-num); font-weight: 300; color: var(--si-ink);
  /* .75rem above and nothing below -- what `.si-prose__h` carries. The -20px
     underneath belongs to the ARTICLE and is set above, scoped to it: there the
     blocks are laid out with a 44px gap and a heading has to pull the block
     below it up to 24. Everywhere else that subtraction is simply wrong, and it
     cost a news post 20px. */
  margin: .75rem 0 0;
}
/* Kept as a no-op: the shorter distance is on every heading now, so the extra
   class says nothing. It stays valid so pages that carry it do not break. */
.si-page .si-e-h--tight { margin-bottom: -20px; }
/* A heading that follows another heading takes the 12px the old prose block gave
   its headings from the inside (`.si-prose__h { margin: .75rem 0 0 }`). One place
   on the Use Case page, and a class the editor sets rather than a rule guessing
   what came before. */
/* ⚠ Two classes, and the article rule above carries three -- so it wins and
   sets margin-top back to 0. The sub-heading needs the same weight to keep its
   12px: it cost the Use Case page 12px through its whole lower half. */
.si-page .si-e-article .si-e-h--sub { margin-top: .75rem; }
.si-page .si-e-h--sub { margin-top: .75rem; }

/* Running text: one text plugin, plain paragraphs, no markup of ours inside. */
/* ⚠ The distance BETWEEN paragraphs must live on the paragraphs, never as a gap
   on this box. In edit mode the text plugin's content moves one level down into
   the editor root, so the box has a single child and a gap has nothing to space
   -- measured: the block came out 17px shorter, and everything below it moved up
   with it. A margin on the paragraph travels with the paragraph. */
/* `p:last-child` IS safe in this box, on one precondition: it holds a single
   text plugin and nothing else, so the last paragraph is the last child in the
   page and in the editor root alike. Add a second plugin here and the rule
   quietly stops applying -- that is exactly what happens in a card. */
/* ⚠ 68ch is the DEFAULT text column, 816px only the wide variant. Mine was
   816 for both, which is a wider line and therefore a different number of lines:
   at 1280px a paragraph came out 77px where production has 102. The measure that
   found it was an element diff, not a guess -- the guess before it was wrong. */
.si-page .si-e-text { max-width: 68ch; }
/* The distance between paragraphs belongs to the VARIANT, like the width does:
   the narrow column spaces at 1.05rem, the wide one at 1.5. Using 1.5 for both
   put 7.2px too much between every pair on a solution page, and using 1.05 for
   both left a five-paragraph block 29px short on the Use Case page. Both were
   measured; neither was guessed. */
.si-page .si-e-text p { margin: 0 0 1.05rem; color: var(--si-ink-70); }
.si-page .si-e-text--wide p { margin-bottom: 1.5rem; }
.si-page .si-e-text p:last-child { margin-bottom: 0; }

/* ⚠ A card only fills its row's height if its COLUMN is a flex container. The
   column is a block by default, so `height: 100%` on the card resolves against
   an auto height and does nothing -- the cards in a row then differ, which is
   what Michael saw on "KI entlang der Bauwertschöpfung" (04 taller than 05, 06).
   The class goes on the column, so no rule has to know where the card sits. */
/* ⚠ And the ROW has to stretch its columns. Something in this sheet sets
   `align-items: start` on rows, so a column is only as tall as its content and
   the card has nothing to fill. Both halves are needed -- the stretching row
   and the flex column -- which is why fixing only the column changed nothing. */
.si-page :is(.si-e-cards, .si-e-checks, .si-e-facts, .si-e-news, .si-e-reports) { align-items: stretch; }
.si-page .si-e-cardcol { display: flex; }
.si-page .si-e-cardcol > * { width: 100%; }

/* Card rows. The Bootstrap row carries the gutters; the card carries the look. */
/* ⚠ Vertical spacing between card rows is `row-gap`, NOT Bootstrap's
   `--bs-gutter-y`. The gutter is a top margin on every column plus a negative
   top margin on the row -- and the negative margin shifts the whole row up, so
   the distance AFTER it grows by exactly that much. Measured on the converted
   page: 14px too little before a card row and 14px too much after it.
   A `row-gap` sits between the rows of cards and touches neither edge. */
.si-page .si-e-cards { --bs-gutter-x: .9rem; --bs-gutter-y: 0; row-gap: 1rem; }
.si-page .si-e-card {
  height: 100%;
  background: var(--si-surface);
  border: 1px solid var(--si-line);
  border-radius: var(--si-radius-lg);
  /* No shadow. `.card` brings one along in this sheet, and neither the report
     cards nor the dark step cards had one -- both carry themselves. */
  box-shadow: none;
  transition: transform .3s cubic-bezier(.16, 1, .3, 1), border-color .3s;
}
.si-page .si-e-card:hover { transform: translateY(-4px); }
/* ⚠ `p:last-child` does NOT work in a card, and the reason is worth keeping. It
   holds only while the text plugin is the ONLY plugin in its box: then its last
   paragraph really is the last child in both modes. A card also holds a link, so
   in the page the link is last and every paragraph keeps its margin -- while in
   edit mode the paragraphs sit in their own editor root and the last one loses
   it. Measured: 6px per news card.
   So every paragraph keeps its margin and the box takes it off its own padding.
   Deterministic, because it never asks which child is last. */
.si-page .si-e-card {
  /* ⚠ padding 0 on the card itself. The sheet gives `.card` 32px, and with the
     card body's own padding on top the text column lost 112px and wrapped a
     line earlier than the same words do today -- 89px per card, measured. */
  padding: 0;
  --si-e-pad: clamp(1.35rem, 2.6vw, 1.75rem);
  --si-e-para: .35rem;
}
.si-page .si-e-card .card-body { padding: var(--si-e-pad); padding-bottom: calc(var(--si-e-pad) - var(--si-e-para)); }
/* ⚠ The label line of a card is its own PARAGRAPH, not a `<strong>` with block
   behaviour. Two reasons, and the second is the stronger one:
   - the sheet has exactly ONE emphasis rule (`.si-page strong`), and the guard
     in test_components_si.py refuses a second. It caught this rule on
     2026-09-22, as it caught the dark step cards on 2026-09-10.
   - two paragraphs are what an editor produces by pressing Return. Markup that
     depends on `<br>` inside one paragraph is markup a human has to know about. */
.si-page .si-e-card p { margin: 0 0 var(--si-e-para); color: var(--si-ink-70); }

/* The dark set, as on the Use Case page. --si-ink is redefined INSIDE the card so
   the one emphasis rule of this sheet keeps working unchanged. */
.si-page .si-e-card--dark {
  background: var(--si-panel); border: 0;
  color: var(--si-panel-ink-70);
  --si-ink: var(--si-panel-ink);
  --si-e-pad: clamp(1.15rem, 2.2vw, 1.5rem);
  /* The label and the sentence sit on consecutive lines here, as they did when
     they were one paragraph with a `<br>`. Two paragraphs with no gap render the
     same and are what an editor types. */
  --si-e-para: 0rem;
}
.si-page .si-e-card--dark p { color: var(--si-panel-ink-70); }

/* --- boxes that hold ONE text plugin ---------------------------------------
   ⚠ Their paragraph must carry no margin of its own. Bootstrap gives every `p`
   a bottom margin of 1rem; in the page the box's own rules happened to cover it,
   in edit mode the paragraph sits one level deeper and the cover misses -- 16px
   per box, measured on the eyebrow and the promise of the page head. */
.si-page :is(.si-e-eyebrow, .si-e-promise, .si-e-check, .si-e-step, .si-e-report__head) p { margin: 0; }

/* The 24px below it is what the page head is spaced by; without it the headline
   moved up 8px, because its own 16px margin then decided the distance. The
   !important is the `m-0` trap again -- eighth time in this sheet. */
.si-page .si-e-eyebrow { max-width: 816px; margin-bottom: 24px !important; }
.si-page .si-e-eyebrow p {
  font-size: var(--si-t-micro); font-weight: 600; letter-spacing: .16em;
  text-transform: uppercase;
  /* ink-70, as production renders it. The sheet DECLARES ink-45 on `.si-eyebrow`
     and loses to `.si-page p` everywhere -- the finding of 2026-09-10, still
     open. Matching production here keeps this page in line with the other 25;
     the site-wide decision is Michael's (konzept-siassist, 2026-09-22). */
  color: var(--si-ink-70);
}
/* ⚠ The distance to the headline above belongs to THIS box and needs the
   !important. The promise used to be a bare <p>, whose margin nobody touched;
   as a plugin it carries `m-0` with Bootstrap's own !important, so the gap fell
   to 0 -- konzept-siassist measured it on the published page. Seventh time. */
.si-page .si-e-promise { margin-top: 1rem !important; }
.si-page .si-e-promise p { color: var(--si-ink-70); max-width: 52ch; }

/* Checklist: a row of full-width columns, each one item with the gold tick. The
   tick is a pseudo element of the COLUMN, so it needs no markup in the text. */
.si-page .si-e-checks { --bs-gutter-y: 0; --bs-gutter-x: 0; row-gap: .9rem; max-width: 68ch; }
/* ⚠ `column-gap`, not `gap`. `gap` applies to ROWS as well, and an entry that
   carries a link below its text then put 18px between the two while the next
   entry stood 14px away -- the link read as belonging to the entry below it
   (Michael, 2026-09-23). The column gap is the distance to the mark and stays;
   the row distance belongs to whatever sits on the second line. */
.si-page .si-e-check {
  display: grid; grid-template-columns: auto 1fr; column-gap: .75rem; row-gap: 0; align-items: start;
  max-width: 68ch; color: var(--si-ink-70);
}
.si-page .si-e-check::before {
  content: "\f26e"; font-family: bootstrap-icons; line-height: 1;
  color: var(--si-gold); transform: translateY(4px);
}

/* Numbered cards. The counter runs over the cards of ONE row; a counter reads
   document order, so the wrappers of edit mode do not disturb it. */
.si-page .si-e-numbered { counter-reset: si-e-num; }
.si-page .si-e-card--num { counter-increment: si-e-num; position: relative; }
.si-page .si-e-card--num .card-body::before {
  content: counter(si-e-num, decimal-leading-zero);
  display: block; font-size: var(--si-t-micro); font-weight: 600; letter-spacing: .08em;
  font-variant-numeric: tabular-nums; color: var(--si-gold); margin-bottom: .75rem;
}

/* Fact cards: the first paragraph is the name. `:first-child` is safe here --
   it stays INSIDE one text plugin, where the editor keeps the paragraphs as
   siblings (measured). It never crosses a plugin boundary. */
.si-page .si-e-facts { --bs-gutter-x: .85rem; --bs-gutter-y: 0; row-gap: .85rem; }
/* ⚠ The fact box sits INSIDE the column, never on it. Two things go wrong when
   the class is on the column, and both were visible: the box then spans the
   column's gutter as well, so the tiles touch -- and a column that is a flex
   container turns the text plugin's paragraphs into flex items side by side.
   A Spacing plugin in the column is the box; the column only stretches it. */
.si-page .si-e-fact {
  background: var(--si-surface); border: 1px solid var(--si-line-soft);
  border-radius: var(--si-radius-lg); padding: 1.35rem 1.5rem; box-shadow: var(--si-shadow);
}
.si-page .si-e-fact p { margin: .35rem 0 0; font-size: var(--si-t-chip); color: var(--si-ink-70); }
/* `:first-child` stays INSIDE one text plugin, where the editor keeps the
   paragraphs as siblings -- measured. It never crosses a plugin boundary. */
.si-page .si-e-fact p:first-child {
  margin: 0; font-size: var(--si-t-num); font-weight: 300; letter-spacing: -.03em; color: var(--si-ink);
}

/* Report cards: head and body are the card's own parts, so the chip and the
   eyebrow need no markup inside the text. */
.si-page .si-e-report .card-header {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: .5rem .8rem; background: none; border: 0; padding: clamp(1.35rem, 2.6vw, 1.75rem) clamp(1.35rem, 2.6vw, 1.75rem) 0;
}
/* The old report card was a flex column with a .75rem gap between ALL its
   parts. A gap cannot do that here -- in edit mode the paragraphs move into the
   editor root and one gap has to stand for four. So the same .75rem becomes the
   paragraph's margin and the heading's, and the card body takes it off its own
   bottom padding. Same rhythm, no dependence on how many children there are. */
.si-page .si-e-report { --si-e-para: .75rem; }
.si-page .si-e-report .card-body { padding-top: .75rem; }
.si-page .si-e-chip {
  font-size: var(--si-t-micro); font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
  color: var(--si-gold-ink); background: var(--si-gold-wash);
  border: 1px solid var(--si-gold-wash-line); border-radius: 99px; padding: .22rem .6rem;
}
.si-page .si-e-card__h { font-size: var(--si-t-card); font-weight: 500; color: var(--si-ink); margin: 0 0 .75rem; }

/* News cards */
.si-page .si-e-news { --bs-gutter-x: .9rem; --bs-gutter-y: 0; row-gap: .9rem; }
/* The news card keeps the softer hairline, the page shadow and the ROOMIER
   padding it had as `.si-na` -- 1.9rem against the other cards' 1.75, which is
   4px of card height at 1504px. */
.si-page .si-e-news-card {
  --si-e-para: .75rem; --si-e-pad: clamp(1.4rem, 2.4vw, 1.9rem);
  border-color: var(--si-line-soft); box-shadow: var(--si-shadow);
}

/* The plain numbered list of the closing statement */
.si-page .si-e-steps { --bs-gutter-y: 0; --bs-gutter-x: 0; counter-reset: si-e-step; border-top: 1px solid var(--si-line); max-width: 74ch; }
.si-page .si-e-step {
  display: grid; grid-template-columns: auto 1fr; gap: 1rem; align-items: baseline;
  padding: .95rem .25rem; border-bottom: 1px solid var(--si-line-soft);
  color: var(--si-ink-70); counter-increment: si-e-step;
}
.si-page .si-e-step::before {
  content: counter(si-e-step, decimal-leading-zero);
  font-size: var(--si-t-micro); font-weight: 600; letter-spacing: .08em;
  font-variant-numeric: tabular-nums; color: var(--si-ink-45);
}

/* The breadcrumb separator is a text plugin holding a single character, not an
   icon in markup: an editor can type it. */
.si-page .si-e-crumb p { margin: 0; color: var(--si-ink-45); }


/* --- the vocabulary of the solution detail pages ---------------------------
   Same principle as above: a class on a plugin, nothing structural, and no
   markup inside a text plugin that a human would have to type. */

/* The category line with its coloured dot. The dot was a `<span>` in the text;
   it is a pseudo element now, so the text plugin holds one plain paragraph. */
.si-page .si-e-pident p {
  display: flex; align-items: center; gap: .5rem; margin: 0;
  font-size: var(--si-t-tag); font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--si-ink-70);
}
.si-page .si-e-pident p::before {
  content: ""; width: 9px; height: 9px; border-radius: 50%; background: currentColor; flex: none;
}
.si-page .si-e-pident.si-cat--innovation p { color: var(--si-cat-ink); }
.si-page .si-e-pident.si-cat--analyse p { color: var(--si-ana-ink); }
.si-page .si-e-pident.si-cat--entscheidung p { color: var(--si-dec-ink); }

/* The byline: who made it, and what it is. Two paragraphs, because the first
   line used to be a `<b>` -- and an editor's bold is `<strong>`, which this
   sheet reserves for its one emphasis rule. `:first-child` is safe here: it
   stays inside a single text plugin. */
.si-page .si-e-byline p { margin: 0; font-size: var(--si-t-chip); color: var(--si-ink-45); }
.si-page .si-e-byline p:first-child { font-size: 1rem; font-weight: 500; color: var(--si-ink); }

/* The quiet box. Its label is the first paragraph of the same text plugin. */
.si-page .si-e-frame {
  background: var(--si-fill); border-radius: var(--si-radius-lg);
  padding: clamp(1.3rem, 2.2vw, 1.7rem); max-width: 666px; font-size: var(--si-t-link);
}
.si-page .si-e-frame p { margin: 0 0 .8rem; color: var(--si-ink-70); }
.si-page .si-e-frame p:last-child { margin-bottom: 0; }
/* ⚠ No margin here. The old sheet sets .6rem on `.si-frame__label` (0,1,0) and
   .8rem on `.si-frame p` (0,1,1) -- and the p rule wins, so production renders
   12.8px, not 9.6. Copying the DECLARED value made the box 3px short. The
   specificity trap again, and this time it decides what production looks like. */
.si-page .si-e-frame p:first-child {
  font-size: var(--si-t-micro); font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--si-ink-45);
}

/* The tile of a "Weitere Lösungen" row. The hexagon plate, the name, the line
   and the foot were one text plugin with four nested spans; each is its own
   plugin now, and the plate is a Spacing whose class names the symbol. */
.si-page .si-e-tile__hex {
  display: block; width: 44px; height: 44px; border-radius: var(--si-radius); flex: 0 0 auto;
  background: var(--si-cat-wash, #FDF4DC);
  border: 1px solid var(--si-cat-line, rgba(244, 180, 0, .45));
  position: relative;
}
.si-page .si-e-tile__hex::before {
  content: ""; position: absolute; inset: 7px;
  background: var(--si-cat, var(--si-gold));
  -webkit-mask: var(--si-hex) center / contain no-repeat;
  mask: var(--si-hex) center / contain no-repeat;
}
.si-page .si-e-tile__h { margin: 1.1rem 0 0; font-size: var(--si-t-card); font-weight: 500; color: var(--si-ink); }
/* The arrow is drawn, not typed: it was an `<i class="bi">` inside the text. */
/* `margin-top: auto` pushes the foot to the bottom of the tile, which is what
   made all tiles of a row end on one line. The !important is the `m-0` trap. */
.si-page .si-e-tile__foot {
  display: flex; align-items: center; justify-content: space-between; gap: .75rem;
  margin-top: 1.4rem !important; padding-top: .9rem;
  border-top: 1px solid var(--si-line-soft);
}
.si-page .si-e-tile__foot p { margin: 0; font-size: var(--si-t-who); line-height: 1.3; color: var(--si-ink-70); }
.si-page .si-e-tile__foot::after {
  content: "\f138"; font-family: bootstrap-icons; color: var(--si-cat, var(--si-gold));
}

/* The lead sentence under a section heading. `max-width` matters: without it the
   box takes the whole column and the line length changes. */
.si-page .si-e-lead p { margin: 0 0 1.4rem; color: var(--si-ink-70); max-width: 62ch; }
/* No top margin. Production gives one only after a `si-psec__head`, and a
   solution page has none -- my unconditional 24px was a structural rule turned
   into an always-rule, which is the opposite of what this vocabulary is for. */

/* The guiding question of a page head. */
.si-page .si-e-q { margin-top: 1.1rem !important; }
.si-page .si-e-q p {
  margin: 0; font-size: clamp(1.08rem, 1.7vw, 1.28rem); line-height: 1.4;
  color: var(--si-ink); max-width: 44ch;
}

/* A headline whose second line is part of the H1 itself.

   Production writes `<h1>EcoNa<span class="si-phero__second">…</span></h1>`, and
   the span is markup no editor can type. One Heading plugin holding both lines
   separated by a line break says the same thing to a reader and to a search
   engine -- `white-space: pre-line` turns the break into a break, and
   `::first-line` gives the FIRST line the headline size while the element itself
   carries the smaller one. Nothing of ours inside the text.

   The small size is the closing-band rung, 30.4 against production's 30.24 --
   the nearest declared step rather than a calculation the sheet has not
   declared. 0.16px at every width from 1146px up, where both clamps sit at
   their cap. */
.si-page .si-e-h1--two {
  white-space: pre-line;
  font-size: clamp(1.4rem, 2.5vw, 1.9rem);
  /* 1.08, the ratio production renders on both lines: 54.432/50.4 and
     32.659/30.24. Measured on the live page, not read off a rule. */
  line-height: 1.08;
  /* ⚠ `max-width: 24ch` on `.si-phero h1` is measured in the element's OWN font,
     and this element carries the small size -- the same 24ch is then a much
     narrower column and the second line wrapped three times instead of once.
     40ch is 24 scaled by the size ratio. */
  max-width: 40ch;
}
.si-page .si-e-h1--two::first-line { font-size: var(--si-h1); }

/* The wide variant is a WIDTH and nothing else. It carried a margin for one
   round, from a guess about the 42px of a solution page that the element diff
   then refuted -- and on the Use Case page that guess added 44px to each of 17
   blocks: 748px of page. A guess that survives into a rule is expensive. */
.si-page .si-e-text--wide { max-width: 816px; }

/* The breadcrumb's separator and its last entry. Both were markup in a text
   plugin -- an `<i class="bi">` and a `<span aria-current>` -- and in edit mode
   each of them becomes an editor root, which cost 16px on every page. The
   separator is drawn, the last entry is a plain paragraph. */
.si-page .si-e-crumb__sep {
  display: inline-flex; align-items: center;
}
.si-page .si-e-crumb__sep::before {
  content: "\f285"; font-family: bootstrap-icons; line-height: 1; color: var(--si-ink-45); opacity: .5;
}
.si-page .si-e-crumb__now p { margin: 0; color: var(--si-ink); }

/* --- news posts -----------------------------------------------------------
   The head of a post and the head of a news card carried tag, date, heading and
   lead in one text plugin. Each is its own plugin now; the chip and the date are
   the first two paragraphs of one text, which keeps them editable as text. */
.si-page .si-e-natop__head { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .8rem; }
/* ⚠ `flex: 0 0 auto`, and it is load-bearing. `.si-page .si-na p` gives every
   paragraph in a news tile `flex: 1` -- that is what makes the teaser grow and
   push the foot down. Before the conversion the category and the date were
   `<span>`s and the rule did not reach them; as paragraphs they are caught by
   it, and the chip stretched to half the card (287px where its word needs 96).
   The head row decides how its own children behave, which is why the fix sits
   here and not as a width on the chip. */
.si-page :is(.si-e-natop__head, .si-e-na__head) p { margin: 0; flex: 0 0 auto; }
.si-page :is(.si-e-natop__head, .si-e-na__head) p:first-child {
  font-size: var(--si-t-micro); font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
  color: var(--si-gold-ink); background: var(--si-gold-wash);
  border: 1px solid var(--si-gold-wash-line); border-radius: 99px; padding: .22rem .6rem;
}
.si-page :is(.si-e-natop__head, .si-e-na__head) p:last-child {
  font-size: var(--si-t-micro); color: var(--si-ink-45); font-variant-numeric: tabular-nums;
}
.si-page .si-e-natop__lead p {
  margin: 0; font-size: var(--si-t-lead); color: var(--si-ink-70); max-width: 696px;
}
.si-page .si-e-natop__lead { margin-top: 1.35rem !important; }
.si-page .si-e-na__head { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .8rem; }
.si-page .si-e-na__h { margin: 0; font-size: var(--si-t-q); font-weight: 500; letter-spacing: -.02em; line-height: 1.3; }

.si-page .si-e-natop__h { font-size: var(--si-h1); font-weight: 300; margin: 1.1rem 0 0; max-width: none; }

/* The distance above a block that does NOT sit in a gap container. The Use Case
   article spaces its blocks with `gap`; a news post or a solution page lays them
   out one after another, and there the 2.75rem has to be a margin -- with the
   `m-0 !important` override, ninth time. The converter adds this class where the
   old block carried `si-prose--wide`, which is where production has it. */
.si-page .si-e-top { margin-top: 2.75rem !important; }
/* 1.25rem: the distance production puts between the quiet box and the button
   that follows it (`.si-natop ~ .si-frame + .btn`). A sibling rule cannot be
   kept -- edit mode breaks it -- so the value becomes a class the converter sets
   where production has it. Read off the live page rather than derived from our
   scale: 20px is simply a step we did not have yet (konzept-siassist). */
.si-page .si-e-top--tight { margin-top: 1.25rem !important; }
/* 2rem: what production puts between a checklist and whatever follows it
   (`.si-checks + *`). Another sibling rule that edit mode breaks, so it becomes
   a class the converter sets. */
.si-page .si-e-top--list { margin-top: 2rem !important; }
/* The head gap: production gives a lead 24px when it follows a section heading
   (`.si-psec__head + .si-psec__lead`) and nothing when it does not. Third
   sibling rule turned into a class the converter sets. */
.si-page .si-e-top--head { margin-top: var(--si-head-gap) !important; }

/* The "Mehr erfahren" line of a news card. The arrow was an `<i>` in the text
   and is drawn now; the words stay a paragraph an editor can change. */
.si-page .si-e-na__go { display: flex; align-items: center; gap: .3rem; }
.si-page .si-e-na__go p {
  margin: 0; font-size: var(--si-t-go); font-weight: 500; color: var(--si-gold-ink);
}
.si-page .si-e-na__go::after {
  content: "\f138"; font-family: bootstrap-icons; line-height: 1;
  font-size: var(--si-t-go); color: var(--si-gold-ink);
}

/* The distance BETWEEN the pieces of one prose block. Production lays the block
   out as a grid with `gap: 1.5rem`, so a heading in the middle of it stands
   24px + its own .75rem below the text: exactly the 36px a news post was short.
   Splitting the block into plugins loses the gap, so each piece after the first
   carries it. */
.si-page .si-e-gap { margin-top: 1.5rem !important; }
/* A heading takes the gap AND its own .75rem on top -- 2.25rem. The !important
   of the gap would otherwise swallow the heading's margin, which is how the
   distance came out 12px short. */
.si-page .si-e-h.si-e-gap { margin-top: 2.25rem !important; }

/* --- Fact cards (about pages) -------------------------------------------- */
/* Three figures with a caption each. The row is a grid row, so the gutter
   variables carry the .85rem production sets on `.si-facts`. */
/* ⚠ NO margin of its own. The class also sits on the card rows of the Use Case
   page, which bring their own distance -- an unconditional 24px here moved that
   page 48px, three weeks after it had been measured at 0. The distance is set
   by the converter where production has it (`si-e-top--head`). */
.si-page .si-e-facts { --bs-gutter-x: .85rem; --bs-gutter-y: 0; row-gap: .85rem; }
.si-page .si-e-fact {
  width: 100%;
  background: var(--si-surface); border: 1px solid var(--si-line-soft);
  border-radius: var(--si-radius-lg); padding: 1.35rem 1.5rem; box-shadow: var(--si-shadow);
}
/* Both carry `.si-page`: `.si-page p` (0,1,1) would otherwise take them. */
.si-page .si-e-fact p { margin: .35rem 0 0; font-size: var(--si-t-chip); color: var(--si-ink-70); }
.si-page .si-e-fact p:first-child {
  margin: 0; font-size: var(--si-t-num); font-weight: 300; letter-spacing: -.03em; color: var(--si-ink);
}

/* --- Person card (about pages) ------------------------------------------- */
/* The badge spans both rows, name and role stack beside it. A grid rather than
   the flex production uses, because name and role are two plugins here and a
   flex row would put them side by side. */
.si-page .si-e-phead { display: grid; grid-template-columns: auto 1fr; column-gap: .9rem; align-items: center; }
.si-page .si-e-pbadge {
  grid-row: 1 / span 2; width: 44px; height: 44px; border-radius: 50%;
  background: var(--si-gold-wash); border: 1px solid var(--si-gold-wash-line);
  display: flex; align-items: center; justify-content: center;
}
.si-page .si-e-pbadge p {
  margin: 0; font-size: var(--si-t-btn); font-weight: 500; letter-spacing: .02em; color: var(--si-gold-ink);
}
.si-page .si-e-pname { grid-column: 2; align-self: end; }
.si-page .si-e-pname p {
  margin: 0; font-size: var(--si-t-quote); font-weight: 500; letter-spacing: -.02em; color: var(--si-ink);
}
.si-page .si-e-prole { grid-column: 2; align-self: start; }
.si-page .si-e-prole p { margin: 0; font-size: var(--si-t-chip); color: var(--si-ink-45); }
.si-page .si-e-pways { display: grid; gap: .2rem; font-size: var(--si-t-link); overflow-wrap: anywhere; }
.si-page .si-e-pways a { color: var(--si-ink-70); text-decoration: none; border-bottom: 1px solid var(--si-line); }
.si-page .si-e-pways a:hover { color: var(--si-ink); border-color: var(--si-gold); }

/* The caption under a screenshot. `!important` because every frontend plugin
   emits Bootstrap's `m-0`, which would otherwise eat the distance. */
.si-page .si-e-shotcap { margin-top: .55rem !important; }
.si-page .si-e-shotcap p { margin: 0; font-size: var(--si-t-chip); line-height: 1.4; color: var(--si-ink-45); }

/* A checklist entry that opens with a line of its own. Production carried a
   class on the `<b>`; here plain bold does it, so the entry can be typed. */
.si-page .si-e-check--lead b { display: block; font-weight: 500; color: var(--si-ink); }

/* --- Partner tile (about pages, overview) -------------------------------- */
/* The paragraph grows so the foot sits at the bottom of the tile, exactly as
   `.si-rel p { flex: 1 }` does in production -- here the growing element is the
   plugin's own box, not the paragraph inside it. */
.si-page .si-e-rel__h {
  margin: 1.1rem 0 0; font-size: var(--si-t-card); font-weight: 500;
  letter-spacing: -.02em; line-height: 1.25; color: var(--si-ink);
}
.si-page .si-e-rel__t { flex: 1; }
.si-page .si-e-rel__t p { margin: .7rem 0 0; font-size: var(--si-t-tile); color: var(--si-ink-70); }
.si-page .si-e-rel__foot {
  display: flex; align-items: center; gap: .55rem;
  margin-top: 1.4rem !important; padding-top: .9rem; border-top: 1px solid var(--si-line-soft);
}
.si-page .si-e-rel__foot p {
  margin: 0; font-size: var(--si-t-go); font-weight: 500; color: var(--si-cat, var(--si-gold));
}
.si-page .si-e-rel__foot::after {
  content: "\f138"; font-family: bootstrap-icons; font-size: var(--si-t-go);
  color: var(--si-cat, var(--si-gold));
}
.si-page .si-e-rel__foot--off { opacity: .55; }

/* The small print under a form. */
.si-page .si-e-formnote { max-width: 544px; margin-top: 1rem !important; }
.si-page .si-e-formnote p { margin: 0; font-size: var(--si-t-chip); color: var(--si-ink-45); }

/* The one line about a person, between the role and the ways to reach them. */
.si-page .si-e-pline p { margin: 0; font-size: var(--si-t-go); color: var(--si-ink-70); }

/* No distance of its own: what stands above already brought it. */
.si-page .si-e-top--0 { margin-top: 0 !important; }

/* --- Legal text ----------------------------------------------------------- */
/* One text plugin, styled from without: the document inside carries no classes
   of its own, so it stays what an editor types. `:first-child` is safe here --
   it selects inside ONE plugin's body, which edit mode keeps whole. */
.si-page .si-e-legal { max-width: 720px; }
.si-page .si-e-legal p { margin: 0 0 1.05rem; font-size: var(--si-t-tile); line-height: 1.62; color: var(--si-ink-70); }
.si-page .si-e-legal h2 {
  font-size: var(--si-h2); font-weight: 300; color: var(--si-ink); margin: var(--si-space-xl) 0 var(--si-head-gap);
}
.si-page .si-e-legal h3 {
  font-size: var(--si-t-num); font-weight: 400; color: var(--si-ink); margin: var(--si-space-l) 0 .75rem;
}
.si-page .si-e-legal :is(h2, h3):first-child { margin-top: 0; }
.si-page .si-e-legal :is(ul, ol) { margin: 0 0 1.05rem; padding-left: 1.15rem; }
.si-page .si-e-legal li { font-size: var(--si-t-tile); line-height: 1.62; color: var(--si-ink-70); margin-bottom: .75rem; }
.si-page .si-e-legal a {
  color: var(--si-terra-ink); text-decoration: none; border-bottom: 1px solid var(--si-line);
  overflow-wrap: anywhere;
}
.si-page .si-e-legal a:hover { border-color: var(--si-gold); }

/* --- The home page -------------------------------------------------------- */
/* Same values as the component vocabulary above, on plugin elements: every
   margin needs `!important` because each frontend plugin emits Bootstrap's
   `m-0`, and every colour needs `.si-page` in front because `.si-page p` is
   (0,1,1) and a bare class is (0,1,0). */
/* ⚠ `ch` is relative to the element's OWN font-size. Production sets both on
   the paragraph; here the width sits on the plugin's box, so the size has to
   sit there too -- otherwise 46ch is measured at 16px and the lead takes an
   extra line (measured: 156px against 125px). */
.si-page .si-e-hero__lead {
  max-width: 46ch; margin-top: 1.6rem !important; font-size: clamp(1.05rem, 1.7vw, 1.22rem);
}
.si-page .si-e-hero__lead p { margin: 0; font-size: inherit; color: var(--si-ink-70); }

/* The headline that carries a marked word: the h1 stays inside the text
   plugin, the class sits on the box. Typography comes from `.si-hero h1`. */
.si-page .si-e-h1 h1 { margin: 0; }

/* The same measures the component sheet gives `.si-split__lead` per section.
   A rule of its own rather than another name inside the `:is()` list up there:
   the guard on that rule reads the first selector that mentions the class, and
   extending the list made it read this one instead. */
:is(.si-flow, .si-flow > div) > .si-e-split__lead { max-width: 672px; }
:is(.si-tiles, .si-tiles > div) > .si-e-split__lead { max-width: 720px; }
:is(.si-cta, .si-cta > div) > .si-e-split__lead { max-width: 624px; }
:is(.si-partners, .si-partners > div) > .si-e-split__lead { max-width: 720px; }
.si-page .si-e-split__lead { margin: var(--si-head-gap) 0 var(--si-space-l) !important; }
.si-page .si-e-split__lead p { margin: 0; font-size: var(--si-t-lead); color: var(--si-ink-70); }
.si-page .si-split--num .si-e-split__lead p { font-size: 1rem; }

/* The list stays a list. The section's own modifier still decides the mark,
   because it sits on a plugin above this one. */
.si-page .si-e-split__list :is(ul, ol) {
  display: grid; border-top: 1px solid var(--si-line); margin: 0; padding: 0; list-style: none;
}
.si-page .si-e-split__list li {
  display: grid; grid-template-columns: auto 1fr; gap: var(--si-space-m); align-items: baseline;
  padding: .95rem .25rem; border-bottom: 1px solid var(--si-line-soft);
  /* No font-size: production's entry inherits the page's 16px, and setting
     --si-t-body here made every row a pixel short. Only the bar variant sets
     one, and it does so below. */
  color: var(--si-ink-70);
}
.si-page .si-e-split__list li p { margin: 0; }
.si-page .si-e-split__list li::before { color: var(--si-ink-45); font-weight: 600; }
.si-page .si-split--num .si-e-split__list :is(ul, ol) { counter-reset: si-split; }
.si-page .si-split--num .si-e-split__list li { counter-increment: si-split; }
.si-page .si-split--num .si-e-split__list li::before {
  content: counter(si-split, decimal-leading-zero);
  font-size: var(--si-t-micro); letter-spacing: .08em; font-variant-numeric: tabular-nums;
}
.si-page .si-split--bar .si-e-split__list :is(ul, ol) { border-top: 0; gap: .55rem; }
.si-page .si-split--bar .si-e-split__list li {
  align-items: center; gap: .85rem; border-bottom: 0; font-size: var(--si-t-body);
  background: var(--si-surface); border: 1px solid var(--si-line-soft);
  border-radius: var(--si-radius); padding: .9rem 1.1rem;
}
.si-page .si-split--bar .si-e-split__list li::before {
  content: ""; width: 3px; height: 20px; background: var(--si-gold); border-radius: 2px;
}
.si-page .si-split--check .si-e-split__list li::before {
  content: "\f26e"; font-family: bootstrap-icons; color: var(--si-gold);
}

/* The bottom margin is the one `.si-page p` gives the paragraph in production;
   here the paragraph has none, so the box carries it. */
.si-page .si-e-split__out { margin: 1.4rem 0 1rem !important; }
.si-page .si-e-split__out p { margin: 0; font-size: var(--si-t-note); color: var(--si-ink-70); }

.si-page .si-e-flow__cap { text-align: center; }
.si-page .si-e-flow__cap p {
  margin: 0; font-size: var(--si-t-chip); font-weight: 500; line-height: 1.3; color: var(--si-ink);
}
.si-page .si-e-flow__cap p + p {
  margin-top: .25rem; font-size: var(--si-t-micro); font-weight: 400; color: var(--si-ink-70);
}
.si-page .si-e-flow__arrow { color: var(--si-gold); justify-self: center; line-height: 1; }
/* `display: block` and `line-height: 1` on the mark itself: as an inline box it
   took the line's leading and stood 18px where production has 16. */
.si-page .si-e-flow__arrow::before {
  content: "\f285"; font-family: bootstrap-icons; display: block; line-height: 1;
}
@media (max-width: 819.98px) { .si-page .si-e-flow__arrow { transform: rotate(90deg); } }

.si-page .si-e-stepnode { display: flex; align-items: center; gap: .9rem; height: var(--si-node-h); flex: 0 0 auto; }
.si-page .si-step--1 .si-e-stepnode { color: var(--si-terra); }
.si-page .si-step--2 .si-e-stepnode { color: var(--si-gold); }
.si-page .si-step--3 .si-e-stepnode { color: var(--si-panel); }
.si-page .si-e-stepdot {
  position: relative; width: 14px; height: 14px; border-radius: 50%;
  background: var(--si-bg); border: 2px solid currentColor; flex: 0 0 auto;
}
.si-page .si-e-stepdot::after { content: ""; position: absolute; inset: 2px; border-radius: 50%; background: currentColor; }
.si-page .si-e-stepnum p {
  margin: 0; font-size: var(--si-t-micro); font-weight: 600; letter-spacing: .16em; color: var(--si-ink-70);
}
.si-page .si-e-stepstage {
  position: relative; z-index: 1;
  padding: .26rem .6rem; border-radius: 99px;
  background: rgba(255, 255, 255, .78); border: 1px solid var(--si-line);
}
.si-page .si-e-stepstage p {
  margin: 0; font-size: var(--si-t-micro); font-weight: 600; letter-spacing: .1em;
  text-transform: uppercase; color: var(--si-ink); line-height: 1.15;
}
.si-page .si-e-stepwho {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: .35rem 1rem; flex-wrap: wrap;
  padding-bottom: .9rem; border-bottom: 1px solid var(--si-line-soft);
}
.si-page .si-e-stepwho p { margin: 0; font-size: var(--si-t-name); font-weight: 500; letter-spacing: -.02em; color: var(--si-ink); }
.si-page .si-e-stepwho p + p { font-size: var(--si-t-link); letter-spacing: 0; color: var(--si-ink-70); }

/* Tags are a list an editor types; the pills are the sheet's. */
.si-page .si-e-tags { margin: 1.5rem 0 1.15rem !important; }
.si-page .si-e-tags ul { display: flex; flex-wrap: wrap; gap: .4rem; margin: 0; padding: 0; list-style: none; }
.si-page .si-e-tags li {
  font-size: var(--si-t-tag); font-weight: 500; color: var(--si-ink-70);
  background: rgba(47, 62, 58, .045); border-radius: var(--si-radius); padding: .34rem .62rem;
}
.si-page .si-e-tags li p { margin: 0; }

.si-page .si-e-partner p { margin: 0; font-size: var(--si-t-logo); font-weight: 500; letter-spacing: -.02em; }
.si-page .si-partners .si-e-partner p { color: var(--si-panel-ink); }
.si-page .si-e-partner p + p {
  margin-top: .45rem; font-size: var(--si-t-chip); font-weight: 400; letter-spacing: 0; color: var(--si-panel-ink-70);
}

/* A link on the dark card takes the panel's ink, not the terra of the light
   ground: terra on `--si-panel` measures 2.25:1. Same answer `.si-partners
   .si-tlink` already gives for the same ground. */
.si-page .si-e-card--dark .si-tlink { color: var(--si-panel-ink); border-color: var(--si-panel-line); }

/* --- The link at the foot of a card (Use Case, process cards) -------------- */
/* Michael, 2026-09-23: the link sits at the bottom right and level across a row,
   however long the text above it is. The card body is a plugin of its own and
   carries the class, so nothing here depends on a sibling's position -- edit
   mode shows what the visitor sees. `!important` on the margin because every
   frontend plugin emits Bootstrap's `m-0`. */
.si-page .si-e-cardfoot { display: flex; flex-direction: column; height: 100%; }
.si-page .si-e-card__go { margin-top: auto !important; align-self: flex-end; }

/* --- The link under a checklist entry (Use Case, technology fields) -------- */
/* It leaves the sentence and starts a line of its own. `.si-e-check` is a
   two-column grid with the mark in the first cell, so the link is told to take
   the text column; without that it would land under the mark.

   .35rem is read off `.si-fact__t`, the one pair this sheet already has of a
   second line that belongs to the line above it -- not a step invented for this
   case. It leaves 5.6px to its own text against the 14.4px `row-gap` of
   `.si-e-checks` to the next entry: grouped by the numbers, not by taste. */
.si-page .si-e-check__go {
  grid-column: 2;
  /* ⚠ `justify-self`, not `align-self`. In a GRID the inline axis is
     justify-self and its default is `stretch`, so the link -- 652px wide where
     its words are a fraction of that -- drew its own underline across the whole
     column. That line read as a separator between the entries and lit up gold
     when the link was hovered, because it WAS the link (Michael, 2026-09-23).
     `.si-tlink` carries `align-self: flex-start` for the flex case; this is the
     grid counterpart. */
  justify-self: start;
  margin-top: .35rem !important;
}

/* The rule that separates the entries. It belongs to the ENTRY, so it does not
   move when the link is hovered, and hovering the link changes only the link.
   The .95rem above and below it are production's own, read off
   `.si-split__list li` -- the one separated list this site already has. */
.si-page .si-e-check--sep { padding-bottom: .95rem; border-bottom: 1px solid var(--si-line-soft); }
.si-page .si-e-checks--sep { row-gap: .95rem; }
