---
title: Cloud Framework
description: "Anleitungen, Vorlagen und Trails Schritt für Schritt für den Weg zu STACKIT und den Betrieb, von STACKIT-Teams, Partnern und Fachleuten in sechs Frameworks."
lastUpdated: false
editUrl: false
tableOfContents: false
prev: false
next: false
hideLinkCard: true
footerType: minimal
sidebar:
  label: Overview
  order: 0
  attrs:
    data-icon: dashboard
head:
  - tag: style
    content: |
      h1#_top { display: none !important; }
      .content-panel-wrapper:first-of-type { display: none !important; }
      .main-pane { container-type: inline-size; }
      
      /* Outer Wrapper */
      .scf-hero-wrapper {
        position: relative;
        width: 100cqw !important;
        /* Cap the width so the height it implies (width / 1632:800 aspect) never overflows the
           viewport on very wide / short screens, where width-only scaling cut off the mountain's
           base. min() keeps normal screens at full width; the vh term only bites when it's smaller. */
        max-width: min(100cqw, calc(85vh * 1632 / 800)) !important;
        left: 50%;
        transform: translateX(-50%);
        margin-top: -1.5rem !important;
        margin-bottom: 2rem !important;
      }
      /* The translateX above makes this wrapper its own stacking context, so the
         Get Started menu (position:absolute inside it) can only ever stack against its
         siblings here - it cannot rise above the framework-card section that follows in
         the DOM. On mobile the content box is static and the menu opens downward into
         that section's band, so the cards painted over it. Lift the whole hero above the
         card section, but only while the menu is open, so nothing else is affected and
         no layout moves (the menu stays position:absolute and shifts no cards). */
      .scf-hero-wrapper:has(.scf-cta[open]) {
        z-index: 50;
      }
      
      /* Text Content Box */
      .scf-hero-content-box {
        position: absolute;
        top: 2%;
        left: max(2rem, 8%);
        max-width: 480px;
        z-index: 20;
        display: flex;
        flex-direction: column;
        gap: 8px;
        pointer-events: none;
      }
      .scf-hero-content-box .scf-hero-actions { pointer-events: auto; }

      /* The header logo now carries the "Cloud Framework" wordmark, so repeating it
         as a hero headline is redundant on screen. Hide it visually but keep it in
         the DOM: the page title (h1#_top) is display:none above, so this is the
         page's only real heading for search engines and screen readers. */
      .scf-hero-title {
        position: absolute !important;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
      }

      .scf-hero-desc {
        color: var(--nds-mode-color-foreground-neutral-default, #E2E8EE);
        font-family: var(--nds-mode-font-family-body, 'DIN 2014'), sans-serif;
        font-size: var(--nds-viewport-font-size-body-default, 16px);
        font-weight: 400;
        line-height: var(--nds-viewport-line-height-body-default, 24px);
        margin: 0;
      }
      .scf-hero-actions {
        display: flex;
        align-items: flex-start;
        gap: var(--nds-viewport-spacing-component-100, 16px);
        flex-wrap: wrap;
        margin-top: 8px;
      }

      /* Get Started is the primary CTA, but it forks into two journeys - using the
         framework, or contributing to it - so it opens a small menu instead of
         navigating straight away. The trigger is a <summary>, which makes the whole
         disclosure pure CSS: no script, and therefore no MDX script escaping either.
         It keeps the cyan CTA fill and borrows the map buttons' size (16px / 43px)
         and hover language (radar ping, cyan glow, lift). These rules are unlayered,
         so they win over the shared button lib's @layer astro-ui-components without
         !important. The .btn base of that lib is scoped to a/button elements, so the
         face restates the few box properties it needs from the same NDS tokens. */
      .scf-cta { position: relative; }
      .scf-cta-face {
        position: relative;
        isolation: isolate;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: var(--nds-viewport-spacing-component-050, 8px);
        min-height: 43px;
        padding: var(--nds-viewport-spacing-component-050-responsive, 8px)
                 var(--nds-viewport-spacing-component-100-responsive, 16px);
        border-radius: var(--nds-viewport-border-radius-component-medium, 8px);
        background: var(--nds-mode-color-background-cta-rest, #00c2cc);
        color: var(--nds-mode-color-foreground-on-cta-default, #101820);
        font-family: var(--nds-mode-font-family-body, 'DIN 2014'), sans-serif;
        font-size: 16px;
        font-weight: var(--nds-mode-font-weight-body-medium, 500);
        line-height: 1.2;
        white-space: nowrap;
        cursor: pointer;
        list-style: none;
        transition: background 0.2s ease-in-out, color 0.2s ease-in-out,
                    box-shadow 0.2s ease-in-out, filter 0.2s ease-in-out,
                    transform 0.15s ease-out;
      }
      .scf-cta-face::-webkit-details-marker { display: none; }
      .scf-cta-face:hover { background: var(--nds-mode-color-background-cta-hover, #00b0b9); }
      /* The map buttons carry an arrow because they navigate. This one opens a menu,
         so it carries a chevron that flips while the menu is open. */
      .scf-cta-chevron {
        width: 16px;
        height: 16px;
        flex-shrink: 0;
        transition: transform 0.2s ease;
      }
      .scf-cta[open] .scf-cta-chevron { transform: rotate(180deg); }
      /* Ring lives behind the button and only becomes visible once it has expanded
         past the cyan edge onto the dark hero - it reads as the CTA radiating out. */
      .scf-cta-face::before {
        content: '';
        position: absolute;
        inset: 0;
        border-radius: inherit;
        border: 1px solid rgba(76, 219, 228, 0.5);
        opacity: 0;
        pointer-events: none;
        z-index: -1;
      }
      .scf-cta-face:hover::before,
      .scf-cta-face:focus-visible::before {
        animation: scf-btn-ping 1.8s ease-out infinite;
      }
      .scf-cta-face:hover,
      .scf-cta-face:focus-visible {
        transform: translateY(-2px);
        box-shadow: 0px 0px 10px rgba(255,255,255,0.08), 0px 4px 12px rgba(0,0,0,0.3);
        filter: drop-shadow(0 0 3px rgba(76, 219, 228, 0.35)) drop-shadow(0 0 9px rgba(76, 219, 228, 0.18));
      }
      .scf-cta-face:focus-visible {
        outline: 2px solid #FFFFFF;
        outline-offset: 2px;
      }

      /* The menu itself: one row per journey, each with a line that says who it is
         for. It sits over the mountain, so it needs its own opaque surface. Above
         1200px the hero content box is absolutely positioned over the artwork, so
         the menu drops straight DOWN out of the button into open space. Below 1200px
         the content box goes static and the framework-card grid follows right under
         it - a downward menu lands in the cards - so the @media block below flips it
         to open to the RIGHT of the button instead. */
      .scf-cta-menu {
        position: absolute;
        top: calc(100% + 8px);
        left: 0;
        z-index: 30;
        width: min(340px, 88vw);
        max-height: calc(100vh - 8rem);
        overflow-y: auto;
        padding: 6px;
        display: flex;
        flex-direction: column;
        gap: 2px;
        background: var(--nds-mode-color-background-neutral-surface-default-rest, #18232c);
        border: 1px solid var(--nds-mode-color-border-neutral-subtle-rest, #2e3c48);
        border-radius: var(--nds-viewport-border-radius-container, 16px);
        box-shadow: 0px 18px 40px -18px rgba(0,0,0,0.85);
        animation: scf-cta-menu-in 0.18s ease-out;
      }
      /* Direction-neutral: the menu opens downward on wide screens and to the right
         on narrow ones (see the @media block), so the intro is a plain fade + a hair
         of lift that reads either way rather than a directional slide. */
      @keyframes scf-cta-menu-in {
        from { opacity: 0; transform: translateY(3px); }
        to { opacity: 1; transform: none; }
      }
      .scf-cta-option {
        display: grid;
        grid-template-columns: auto 1fr auto;
        gap: 12px;
        align-items: center;
        padding: 10px;
        border-radius: 8px;
        text-decoration: none !important;
        color: var(--nds-mode-color-foreground-neutral-default, #E2E8EE);
        transition: background 0.2s ease-in-out;
      }
      .scf-cta-option:hover,
      .scf-cta-option:focus-visible {
        background: rgba(0, 194, 204, 0.10);
        outline: none;
      }
      .scf-cta-option:focus-visible { box-shadow: 0 0 0 2px rgba(0, 194, 204, 0.6); }
      .scf-cta-option-icon {
        width: 26px;
        height: 26px;
        flex-shrink: 0;
        color: var(--nds-mode-color-foreground-primary-on-neutral, #00c2cc);
      }
      .scf-cta-option-label {
        display: block;
        font-weight: 600;
        font-size: 15px;
        line-height: 1.25;
      }
      .scf-cta-option-desc {
        display: block;
        font-size: 13px;
        line-height: 1.35;
        color: var(--nds-mode-color-foreground-neutral-subtle, #9da5ac);
      }
      .scf-cta-option-go {
        width: 14px;
        height: 14px;
        flex-shrink: 0;
        color: var(--nds-mode-color-foreground-neutral-subtle, #4a6072);
      }
      .scf-cta-option:hover .scf-cta-option-go {
        color: var(--nds-mode-color-foreground-primary-on-neutral, #00c2cc);
      }
      @media (prefers-reduced-motion: reduce) {
        .scf-cta-face { transition: none; }
        .scf-cta-face:hover, .scf-cta-face:focus-visible { transform: none; }
        .scf-cta-face:hover::before,
        .scf-cta-face:focus-visible::before { animation: none; }
        .scf-cta-chevron { transition: none; }
        .scf-cta-menu { animation: none; }
      }

      /* Map & SVG Isolation */
      /* inline-size container so the icon chips below 1200px can size themselves
         in cqw of the MAP, not the viewport: the sidebar comes and goes across
         the band (the map is 432px wide at an 800px window but 712px at 760px),
         so any viewport-based size is wrong somewhere. */
      .scf-interactive-map { position: relative; width: 100%; container-type: inline-size; }
      .scf-hero-graphic { width: 100% !important; margin: 0 !important; }
      .scf-hero-graphic svg { width: 100% !important; height: auto !important; display: block; max-width: none !important; }

      /* Light mode gets its own sky. The scene is drawn for a dark ground: its sky fades
         from transparent to teal, so on a white page the top stays white, and that is
         exactly where the summits are. The snow faces (#F0FBFC) stood against the page at
         a contrast of 1.00 to 1.09, four mountains lost their left flank and the Data and AI
         rope seemed to hang in the air. scf_sky_day stays transparent behind the intro text
         and reaches a pale teal at summit height. Dark mode keeps the drawn sky, and so does
         high contrast, which stamps data-theme="dark".
         The gulls are drawn light for the dark sky. Here they keep the darker line. */
      :root[data-theme='light'] #scf_sky { fill: url(#scf_sky_day); fill-opacity: 1; }
      :root[data-theme='light'] .scf-bird { stroke: #145155; }
      
      /* General SVG interactive paths.
         Anti-flicker setup: each anchor holds the visible <g> plus an
         invisible, static <use class="scf-hit"> clone. The clone is painted
         after the group, so within a region's own footprint it is the
         topmost hit layer: the visible group can lift without moving the
         area under the cursor (which made hover flip-flop at group edges,
         trail <-> migration).
         The group must NOT be pointer-events:none, even though the clone is
         what we hover. WebKit resolves a <use> clone's hit-testing against
         the REFERENCED element, so a pointer-events:none group makes the
         clone untouchable too and the whole map goes dead in Safari (Blink
         honours the <use>'s own pointer-events:all, which is why it only
         broke there). Leaving the group hittable costs nothing: its clone
         covers it, so the group is only ever hit in the few px it lifts
         beyond the clone - inside the same region, while already hovered. */
      .scf-interactive {
        transition: filter 0.3s cubic-bezier(0.25,1,0.5,1);
        cursor: pointer;
      }
      .scf-interactive > g {
        transition: transform 0.3s cubic-bezier(0.25,1,0.5,1);
        transform-origin: center;
        transform-box: fill-box;
      }
      .scf-interactive > use.scf-hit {
        opacity: 0;
        pointer-events: all;
      }
      .scf-interactive:hover {
        filter: brightness(1.4) drop-shadow(0px 10px 15px rgba(0,0,0,0.4));
      }
      .scf-interactive:hover > g {
        transform: translateY(-5px) scale(1.02);
      }
      
      /* HTML Overlay Buttons */
      .scf-btn-overlay {
        position: absolute;
        --magnet-x: 0px;
        --magnet-y: 0px;
        transform: translate(calc(-50% + var(--magnet-x)), calc(-50% + var(--magnet-y)));
        isolation: isolate;
        z-index: 10;
        display: flex;
        min-width: max-content;
        max-width: 160px;
        min-height: 43px;
        padding: 8px 16px;
        justify-content: center;
        align-items: center;
        text-align: center;
        gap: 8px;
        border-radius: 8px;
        background: #25323D;
        color: #E2E8EE;
        font-family: 'DIN 2014', sans-serif;
        font-size: 16px;
        line-height: 1.2;
        text-decoration: none !important;
        box-sizing: border-box;
        white-space: normal;
        transition: background 0.2s ease-in-out, color 0.2s ease-in-out, box-shadow 0.2s ease-in-out, filter 0.2s ease-in-out, transform 0.15s ease-out, opacity 0.3s ease;
      }
      .scf-btn-overlay svg { width: 16px; height: 16px; fill: currentColor; flex-shrink: 0; }
      /* Each button also carries the destination's own icon (the one the sidebar
         and the card grid use). It only shows in chip mode below 1200px. */
      .scf-btn-overlay .scf-btn-icon { display: none; }

      /* Radar-ping: a faint ring expands out of the button and fades, on a loop
         while hovered/focused - reads as "this is a live spot on the map",
         not just a bigger label. */
      .scf-btn-overlay::before {
        content: '';
        position: absolute;
        inset: 0;
        border-radius: inherit;
        border: 1px solid rgba(76, 219, 228, 0.5);
        opacity: 0;
        pointer-events: none;
        z-index: -1;
      }
      .scf-btn-overlay:hover::before, .scf-btn-overlay:focus-visible::before {
        animation: scf-btn-ping 1.8s ease-out infinite;
      }
      @keyframes scf-btn-ping {
        0% { transform: scale(1); opacity: 0.35; }
        100% { transform: scale(1.35); opacity: 0; }
      }

      .scf-btn-overlay:hover, .scf-btn-overlay:focus-visible {
        background: #2E3C48;
        color: #FFFFFF;
        box-shadow: 0px 0px 10px rgba(255,255,255,0.08), 0px 4px 12px rgba(0,0,0,0.3);
        filter: drop-shadow(0 0 3px rgba(76, 219, 228, 0.35)) drop-shadow(0 0 9px rgba(76, 219, 228, 0.18));
        outline: none;
      }
      @media (prefers-reduced-motion: reduce) {
        .scf-btn-overlay:hover::before, .scf-btn-overlay:focus-visible::before { animation: none; }
      }
      
      /* Forward Sync: HTML Button Hover triggers SVG Path Highlight */
      .scf-interactive-map:has(#btn-arch:hover) a.scf-interactive[href*="architecture"],
      .scf-interactive-map:has(#btn-adopt:hover) a.scf-interactive[href*="adoption"],
      .scf-interactive-map:has(#btn-adv:hover) a.scf-interactive[href*="advisory"],
      .scf-interactive-map:has(#btn-mig:hover) a.scf-interactive[href*="migration"],
      .scf-interactive-map:has(#btn-isv:hover) a.scf-interactive[href*="isv"],
      .scf-interactive-map:has(#btn-data:hover) a.scf-interactive[href*="data-and-ai"],
      .scf-interactive-map:has(#btn-trail:hover) a.scf-interactive[href*="trails"],
      .scf-interactive-map:has(#btn-assets:hover) a.scf-interactive[href*="assets"],
      .scf-interactive-map:has(#btn-contributors:hover) a.scf-interactive[href*="contributors"] {
        filter: brightness(1.4) drop-shadow(0px 10px 15px rgba(0,0,0,0.4));
      }
      .scf-interactive-map:has(#btn-arch:hover) a.scf-interactive[href*="architecture"] > g,
      .scf-interactive-map:has(#btn-adopt:hover) a.scf-interactive[href*="adoption"] > g,
      .scf-interactive-map:has(#btn-adv:hover) a.scf-interactive[href*="advisory"] > g,
      .scf-interactive-map:has(#btn-mig:hover) a.scf-interactive[href*="migration"] > g,
      .scf-interactive-map:has(#btn-isv:hover) a.scf-interactive[href*="isv"] > g,
      .scf-interactive-map:has(#btn-data:hover) a.scf-interactive[href*="data-and-ai"] > g,
      .scf-interactive-map:has(#btn-trail:hover) a.scf-interactive[href*="trails"] > g,
      .scf-interactive-map:has(#btn-assets:hover) a.scf-interactive[href*="assets"] > g,
      .scf-interactive-map:has(#btn-contributors:hover) a.scf-interactive[href*="contributors"] > g {
        transform: translateY(-5px) scale(1.02);
      }

      /* Things that belong to a mountain have to ride its hover: a station standing
         on it, and the cut that hides the rope and cabin behind it. Otherwise the
         rising slope swallows the station, and the cut drifts off the ridge and
         opens a gap between the rope and the mountain.

         They get the mountain's transform EXACTLY, not an approximation. The
         mountain lifts 5px and also scales 1.02 about its own fill-box centre, and
         that scale moves its edge sideways as well - about 2px at the height the
         rope meets the ridge. A plain translateY looked right vertically and was
         off horizontally by that much, which is visible as a gap. transform-box:
         view-box lets the origin be written in viewBox units, so each element can
         borrow the centre of the mountain it belongs to:
           advisory_framework    bbox -2.1..849.9 x 465.6..821.6  -> 423.9 643.6
           data_and_ai_framework bbox  -65..334   x  652..837     -> 134.5 744.5 */
      #gondola_valley_station, #scf_dai_station_mid, #scf_dai_ridge_clip path {
        transition: transform 0.3s cubic-bezier(0.25,1,0.5,1);
        transform-box: view-box;
      }
      #gondola_valley_station, #scf_dai_ridge_clip path {
        transform-origin: 423.9px 643.6px;
      }
      #scf_dai_station_mid {
        transform-origin: 134.5px 744.5px;
      }
      .scf-interactive-map:has(a.scf-interactive[href*="advisory"]:hover) #gondola_valley_station,
      .scf-interactive-map:has(#btn-adv:hover) #gondola_valley_station,
      .scf-interactive-map:has(a.scf-interactive[href*="advisory"]:hover) #scf_dai_ridge_clip path,
      .scf-interactive-map:has(#btn-adv:hover) #scf_dai_ridge_clip path {
        transform: translateY(-5px) scale(1.02);
      }

      .scf-interactive-map:has(a.scf-interactive[href*="data-and-ai"]:hover) #scf_dai_station_mid,
      .scf-interactive-map:has(#btn-data:hover) #scf_dai_station_mid {
        transform: translateY(-5px) scale(1.02);
      }

      /* The chimney smoke sits outside the migration group (see the SVG: inside, the
         mountain's hit clone ran an invisible copy of it that no pause could reach) and
         rides the mountain's hover the same way. Its pivot is baked into the geometry, so
         the origin here is 0 0 of its own coordinate system. */
      #chimney_smoke {
        transition: transform 0.3s cubic-bezier(0.25,1,0.5,1);
        transform-origin: 0 0;
      }
      .scf-interactive-map:has(a.scf-interactive[href*="migration"]:hover) #chimney_smoke,
      .scf-interactive-map:has(#btn-mig:hover) #chimney_smoke {
        transform: translateY(-5px) scale(1.02);
      }

      /* The old Advisory-to-Architecture gondola is painted after those two
         mountains and after Adoption, so its rope spans in front of them. That is
         the intended depth - the cable crosses the valley, those peaks sit behind
         it - but on hover the mountain brightens and the lines across it start to
         read as being on top of it. They step back while that mountain is lit. */
      #gondola_line, #gondola_cabin, #gondola_cabin_2 {
        transition: opacity 0.3s cubic-bezier(0.25,1,0.5,1);
      }
      .scf-interactive-map:has(a.scf-interactive[href*="adoption"]:hover) :is(#gondola_line, #gondola_cabin, #gondola_cabin_2),
      .scf-interactive-map:has(#btn-adopt:hover) :is(#gondola_line, #gondola_cabin, #gondola_cabin_2),
      .scf-interactive-map:has(a.scf-interactive[href*="architecture"]:hover) :is(#gondola_line, #gondola_cabin, #gondola_cabin_2),
      .scf-interactive-map:has(#btn-arch:hover) :is(#gondola_line, #gondola_cabin, #gondola_cabin_2) {
        opacity: 0.15;
      }

      /* Enhanced Hover specifically for Trails (Dark Outline/Glow) */
      a.scf-interactive[href*="trails"]:hover,
      .scf-interactive-map:has(#btn-trail:hover) a.scf-interactive[href*="trails"] {
        filter: brightness(1.3) drop-shadow(0px 0px 12px rgba(255,255,255,0.2)) drop-shadow(0px 8px 12px rgba(0,0,0,0.6)) !important;
        z-index: 5;
      }
      a.scf-interactive[href*="trails"]:hover > g,
      .scf-interactive-map:has(#btn-trail:hover) a.scf-interactive[href*="trails"] > g {
        transform: translateY(-8px) scale(1.05) !important;
      }

      /* Reverse Sync: SVG Path Hover triggers HTML Button State */
      .scf-interactive-map:has(a.scf-interactive[href*="architecture"]:hover) #btn-arch,
      .scf-interactive-map:has(a.scf-interactive[href*="adoption"]:hover) #btn-adopt,
      .scf-interactive-map:has(a.scf-interactive[href*="advisory"]:hover) #btn-adv,
      .scf-interactive-map:has(a.scf-interactive[href*="migration"]:hover) #btn-mig,
      .scf-interactive-map:has(a.scf-interactive[href*="isv"]:hover) #btn-isv,
      .scf-interactive-map:has(a.scf-interactive[href*="data-and-ai"]:hover) #btn-data,
      .scf-interactive-map:has(a.scf-interactive[href*="trails"]:hover) #btn-trail,
      .scf-interactive-map:has(a.scf-interactive[href*="assets"]:hover) #btn-assets,
      .scf-interactive-map:has(a.scf-interactive[href*="contributors"]:hover) #btn-contributors {
        background: #4C6072;
        color: #FFFFFF;
        box-shadow: 0px 0px 15px rgba(255,255,255,0.15), 0px 4px 12px rgba(0,0,0,0.3);
      }

      /* Responsiveness Breakpoints */
      @media(max-width: 1200px) {
        .scf-hero-content-box { position: static; padding: 0 1rem 1.5rem 1rem; max-width: 100%; pointer-events: auto; }
        .scf-hero-content-box h2, .scf-hero-content-box p { pointer-events: auto; }
        /* Content box is static now and the card grid sits right below it, so the
           menu can no longer open downward - it flips to open beside the button.
           Width is clamped to the room left to the right of the button inside the
           content column (100cqw already excludes the docs sidebar); the 32px
           covers the 8px gap plus a right margin. */
        .scf-cta-menu {
          top: 0;
          left: calc(100% + 8px);
          width: min(340px, calc(100cqw - 100% - 32px));
        }
        /* Below the standard width the pills used to shrink into cramped labels
           (down to 12px text). Instead each button collapses into a round icon
           chip, so the map keeps its clickable spots without the text. The label
           survives as the aria-label on the link.

           The chip wears the card marker's colours so the map and the card grid
           speak one language: #162938 fill, cyan ring, cyan icon. The fill is
           opaque although the card marker uses .92 - on a card that sits on a
           flat #162938 plate so it reads solid, but over the artwork the .92 let
           the mountain draw a visible wedge across the chip.

           Sizes are in cqw of the MAP, not the viewport: the sidebar comes and
           goes across this band (the map is 432px wide in an 800px window but
           712px in a 760px one), so any viewport-based size is wrong somewhere.
           5.5cqw is the 40px that looked right on a 732px map; the clamp floor
           keeps a tappable target on the smallest maps.

           The ring grows with the chip and carries a soft dark glow. Both are
           needed because the ring is drawn straight onto teal artwork: where a
           chip crossed a dark mountain a thin ring dissolved into it while the
           same ring popped against the snow, so one chip looked sharp on one
           side and soft on the other. The glow has no hard spread - that just
           reads as a second grey ring. #btn-portal already uses the same trick
           to read against the cloud. */
        .scf-btn-overlay {
          padding: 0;
          min-height: 0;
          max-width: none;
          width: clamp(24px, 5.5cqw, 44px);
          height: clamp(24px, 5.5cqw, 44px);
          border-radius: 50%;
          background: #162938;
          border: clamp(1.5px, 0.28cqw, 2px) solid #4CDBE4;
          color: #4CDBE4;
          box-shadow: 0 0 8px 1px rgba(6, 20, 30, 0.32);
          /* The cards' marker rule, taken verbatim: the ring's bottom edge floats
             2px above the tip (card-contributors: marker cy 306.5 vs spire apex
             329.5 = r + 2). Translating -100% instead of -50% keeps that true at
             every size the clamp produces. */
          transform: translate(calc(-50% + var(--magnet-x)), calc(-100% - 2px + var(--magnet-y)));
        }
        .scf-btn-overlay .scf-btn-label, .scf-btn-overlay .scf-btn-arrow { display: none; }
        .scf-btn-overlay .scf-btn-icon { display: block; width: clamp(13px, 2.75cqw, 22px); height: clamp(13px, 2.75cqw, 22px); }
        /* Restated because the shared hover rule replaces the whole box-shadow
           and the whole transform. */
        .scf-btn-overlay:hover, .scf-btn-overlay:focus-visible {
          box-shadow: 0 0 10px 1px rgba(6, 20, 30, 0.34), 0 4px 14px rgba(6, 20, 30, 0.3);
          transform: translate(calc(-50% + var(--magnet-x)), calc(-100% - 2px + var(--magnet-y))) scale(1.12);
        }
        /* Portal and Marketplace lead off the framework, so their ring is slate instead of
           the cyan every internal chip wears. The fill and the dark glow behind the
           ring stay: they are what keeps a chip readable over both snow and teal,
           and the point here is the colour, not the legibility. */
        #btn-portal, #btn-market { border-color: #9FB6C4; color: #9FB6C4; }
        /* Two chips are centred on their point instead of hanging above a tip:
           the cloud wears the signet like a badge in the middle of its shape, and
           the marketplace sits diagonally beside the stall rather than on it, so
           it never covers the little building. Both therefore keep the resting
           position from the inline style and need no override below. */
        #btn-portal, #btn-market { transform: translate(calc(-50% + var(--magnet-x)), calc(-50% + var(--magnet-y))); }
        #btn-portal:hover, #btn-portal:focus-visible,
        #btn-market:hover, #btn-market:focus-visible {
          transform: translate(calc(-50% + var(--magnet-x)), calc(-50% + var(--magnet-y))) scale(1.12);
        }
        /* Chip centres sit on the measured apex of each landmark, the same rule
           the framework cards use for their summit markers: mountain chips on
           the summit tip, contributors centred on the church spire, assets on the
           rucksack top. Migration has no sharp tip,
           its top is a flat ridge from x1151 to x1227, so its chip takes the
           right shoulder to keep clear air to the hut chip. Trails and portal
           keep their resting spots: the trail head lies right beside the hut,
           and the cloud chip is already centred. The pill positions above
           1200px are untouched; !important because those are inline styles. */
        #btn-adv { left: 33.58% !important; top: 58.25% !important; }
        #btn-adopt { left: 48.59% !important; top: 54.75% !important; }
        #btn-arch { left: 63.17% !important; top: 46.38% !important; }
        #btn-mig { left: 75.18% !important; top: 63% !important; }
        #btn-data { left: 11.89% !important; top: 81.5% !important; }
        #btn-isv { left: 81.7% !important; top: 78.38% !important; }
        #btn-contributors { left: 28.19% !important; top: 85.25% !important; }
        #btn-assets { left: 59.74% !important; top: 82.5% !important; }
        /* The marketplace chip sits closer to the stall than its pill does: the
           pill has to clear a wide label, the chip is a small circle and can tuck
           into the corner diagonally above the awning without covering it. */
        #btn-market { left: 85.29% !important; top: 85.25% !important; }
      }
      /* Cloud Floating Animation (the new export draws the cloud at its final
         position, so no base offset - just the gentle drift) */
      #cloud {
        animation: scf-cloud-float 8s ease-in-out infinite alternate;
        transform-origin: center;
        transform-box: fill-box;
      }

      @keyframes scf-cloud-float {
        0% {
          transform: translate(0, -20px);
        }
        100% {
          transform: translate(-15px, 0);
        }
      }

      /* Background haze band: a very slow, tiny parallax drift (much slower and
         smaller than the foreground #cloud) so the mid-scene sky gains depth
         and feels alive. The amplitude stays small enough to read as
         atmosphere rather than motion. */
      #background_clouds {
        transform-origin: center;
        transform-box: fill-box;
        animation: scf-bgcloud-drift 80s ease-in-out infinite alternate;
      }

      @keyframes scf-bgcloud-drift {
        0% {
          transform: translate(0, 0);
        }
        100% {
          transform: translate(14px, -4px);
        }
      }

      /* Gondola ride: the cabin runs a real aerial-tramway circuit. It climbs
         to the Architecture-side top station on the BACK (upper) cable
         (Vector 804) and returns towards Advisory on the FRONT (lower) cable
         (Vector 805). The two ropes converge at the station and spread ~9px
         apart at the bottom, so the cabin rides a touch higher going up than
         coming down. It also shrinks with distance (scale 1 near Advisory,
         ~0.63 at the far Architecture station) and now pulls right up to the
         station. It waits 2s at each end, both hidden behind the Advisory
         summit at the bottom (its layer sits below advisory_framework), so the
         jump between the front-cable bottom and back-cable bottom is invisible.
         Each ride leg eases in/out (per-keyframe animation-timing-function) so
         it doesn't snap; the holds stay linear since nothing moves in them.
         scale needs transform-box: fill-box so it pivots on the cabin itself. */
      #gondola_cabin,
      #gondola_cabin_2 {
        transform-origin: center;
        transform-box: fill-box;
        animation: scf-gondola-ride 52s linear infinite;
      }

      /* Second cabin, half a cycle behind (-26s of the 52s loop): while one
         climbs the back cable the other rides down the front cable, so both
         ropes are always in use and the up-back / down-front circuit reads at
         a glance instead of looking like a single tram. */
      #gondola_cabin_2 {
        animation-delay: -26s;
      }

      @keyframes scf-gondola-ride {
        /* bottom hold, hidden behind Advisory, on the BACK cable, full size */
        0% {
          transform: translate(-101px, 11.2px) scale(1);
          animation-timing-function: linear;
        }
        3.846% {
          transform: translate(-101px, 11.2px) scale(1);
          animation-timing-function: ease-in-out;
        }
        /* top station near Architecture: arrives close, shrunk with distance */
        50% {
          transform: translate(290px, -61.1px) scale(0.63);
          animation-timing-function: linear;
        }
        53.846% {
          transform: translate(290px, -61.1px) scale(0.63);
          animation-timing-function: ease-in-out;
        }
        /* back down on the FRONT cable towards Advisory, full size; the jump
           to 0% (back-cable bottom) is hidden behind the Advisory summit */
        100% {
          transform: translate(-101px, 21.4px) scale(1);
        }
      }

      /* Gentle pendulum sway around the grip (top-centre), so the cabins hang
         from the rope instead of feeling rigid. Nested inside the ride: the
         outer group rides (translate/scale), this inner body only tilts. */
      .scf-cabin-body {
        transform-origin: top;
        transform-box: fill-box;
        animation: scf-cabin-sway 3.8s ease-in-out infinite;
      }
      #gondola_cabin_2 .scf-cabin-body {
        animation-delay: -1.9s;
      }
      @keyframes scf-cabin-sway {
        0%, 100% { transform: rotate(-1.6deg); }
        50% { transform: rotate(1.6deg); }
      }

      /* Data & AI line: one cabin on one span, from behind the Advisory ridge
         down to the station on the Data & AI plateau and back. It waits at both
         ends. On the Advisory leg it shrinks with distance and slips behind the
         flank, which is what the two clip wrappers in the SVG are for. */
      #scf_dai_cabin {
        animation: scf-dai-ride 46s ease-in-out infinite;
      }
      /* offset against the other cabins so nothing swings in unison */
      #scf_dai_cabin .scf-cabin-body {
        animation-delay: -2.4s;
      }
      @keyframes scf-dai-ride {
        0% { transform: translate(541px, 483.7px) scale(0.62); }
        5% { transform: translate(541px, 483.7px) scale(0.62); }
        50% { transform: translate(215px, 620.4px) scale(1); }
        55% { transform: translate(215px, 620.4px) scale(1); }
        100% { transform: translate(541px, 483.7px) scale(0.62); }
      }

      /* Slope life: a skier carving down the Data & AI mesa, a snowboarder
         dropping off the ISV summit, and a chairlift ferrying up the
         migration flank towards the hut. Decorative only: pointer-events
         none keeps the mountain hover intact underneath (same for the
         gondola). */
      #skier, #snowboarder, #chairlift, #balloon, #gondola_cabin, #gondola_cabin_2, #gondola_line, #gondola_valley_station, #chimney_smoke, #birds, #scf_dai_lift, #market_ground, #scf_goat {
        pointer-events: none;
      }
      /* Hot air balloon: rises out from behind the ISV ridge. It is painted just
         before isv_framework, so that ridge hides its start and its restart, while
         it still sits in front of migration_framework - that peak used to cut
         through it mid-flight, which is why it was moved forward in the first
         place. From there it climbs up and to the right, receding into the
         distance, until it exits the artwork past the top-right corner. */
      #balloon {
        transform-origin: center;
        transform-box: fill-box;
        /* linear, not ease-in-out: a balloon leaving the frame does not brake.
           Only the lift-off is eased, see the keyframes. */
        animation: scf-balloon-ride 40s linear infinite;
        transition: filter 0.3s ease;
      }

      @keyframes scf-balloon-ride {
        /* A balloon has no propulsion. Vertically the burner gives it a steady
           climb rate, horizontally it only goes where the wind takes it, and wind
           picks up with altitude. So the rise is linear at about 10 view-box units
           per percent of the loop from lift-off onwards, while the sideways drift
           grows from 0.5 to 5 units per percent. The old curve did the opposite:
           one ease-in-out over the whole flight, so it accelerated away from the
           ground and then slowed down again on the way out of frame.

           Start and end sit low enough that the whole envelope is behind the ISV
           ridge: measured, that silhouette runs from y 665 at the balloon's left
           edge down to y 734 at its right, so the top has to clear 734. */
        0% { transform: translate(-3px, 163px) scale(0.62); opacity: 1;
             animation-timing-function: ease-in; }
        /* Lift-off: it leaves the ground slowly and settles into its climb. */
        10% { transform: translate(2px, 96px) scale(0.615);
              animation-timing-function: linear; }
        25% { transform: translate(16px, -57px) scale(0.58); }
        40% { transform: translate(42px, -210px) scale(0.54); }
        55% { transform: translate(80px, -363px) scale(0.5); }
        70% { transform: translate(130px, -516px) scale(0.46); }
        85% { transform: translate(192px, -669px) scale(0.41); }
        /* Fully out of frame here, so the fade never shows and the jump back to
           the start is hidden by the ridge. */
        90% { transform: translate(218px, -720px) scale(0.39); opacity: 1; }
        91% { opacity: 0; }
        100% { transform: translate(-3px, 163px) scale(0.62); opacity: 0; }
      }

      /* Gentle buoyant sway so the balloon rocks as it drifts instead of
         rising perfectly rigid. Nested inside the ride: the outer #balloon
         climbs/scales, this inner body only tilts around its centre. A period
         off from the cabin sway (5.5s vs 3.8s) keeps it from feeling synced. */
      .scf-balloon-body {
        /* The basket hangs under the envelope, so the pair tips about a point up
           in the envelope, not about the middle of the drawing. And a balloon in
           free flight moves with the air: no relative wind, so almost nothing to
           rock it. What is left is a slow drift, hence 14s and barely a degree,
           where this used to swing 2 degrees every 5.5s like something being
           blown about. */
        transform-origin: 50% 32%;
        transform-box: fill-box;
        animation: scf-balloon-sway 14s ease-in-out infinite;
      }
      @keyframes scf-balloon-sway {
        0%, 100% { transform: rotate(-1.1deg); }
        50% { transform: rotate(1.1deg); }
      }

      #skier { animation: scf-ski-run 10s linear infinite; }
      @keyframes scf-ski-run {
        0% { transform: translate(0, 0); opacity: 0; }
        5% { transform: translate(-7px, 7px); opacity: 1; }
        25% { transform: translate(-37px, 42px); }
        45% { transform: translate(-78px, 68px); }
        65% { transform: translate(-106px, 110px); }
        85% { transform: translate(-143px, 130px); }
        93% { transform: translate(-152px, 146px); opacity: 1; }
        98%, 100% { transform: translate(-158px, 152px); opacity: 0; }
      }

      /* Snowboarder journey (one 24s loop, in sync with the lift chair):
         board the chair at the bottom of the migration flank, ride up
         (shrinking with distance), hop off at the top station, jump right
         onto the ISV summit and carve down the ISV face (growing as it
         comes closer). Scale/rotate need fill-box so they pivot around the
         figure itself. */
      #snowboarder, #lift_chair {
        transform-origin: center;
        transform-box: fill-box;
      }

      #snowboarder { animation: scf-board-journey 24s linear infinite; }
      /* The descent is laid out on the terrain, not guessed. 46-63% rides the ISV
         mountain's left ridge, staying just inside the edge (the ridge runs
         1332,627 -> 1197,674 -> 1180,766 in artwork units). At 63% he pops off the
         lip: 63-67% he flies out over the slope, tilt levelling in the air, and
         lands at 71% back on the fall line. 71-95% runs out to the drag lift's base, which is exactly
         where 0% starts, so the loop closes without a jump cut. */
      @keyframes scf-board-journey {
        0% { transform: translate(-287px, 192px) scale(1) rotate(14deg); opacity: 1; }
        38% { transform: translate(-173px, -66px) scale(0.7) rotate(14deg); opacity: 1; }
        40.5% { transform: translate(-130px, -82px) scale(0.72) rotate(4deg); }
        43% { transform: translate(-60px, -58px) scale(0.74) rotate(-4deg); }
        46% { transform: translate(0px, 0px) scale(0.76) rotate(0deg); }
        50% { transform: translate(-32px, 11px) scale(0.78) rotate(-6deg); }
        54% { transform: translate(-63px, 23px) scale(0.8) rotate(-10deg); }
        58% { transform: translate(-90px, 38px) scale(0.82) rotate(-14deg); }
        61% { transform: translate(-102px, 56px) scale(0.84) rotate(-20deg); }
        63% { transform: translate(-108px, 70px) scale(0.85) rotate(-26deg); }
        65% { transform: translate(-128px, 78px) scale(0.86) rotate(-10deg); }
        67% { transform: translate(-152px, 90px) scale(0.87) rotate(-6deg); }
        69% { transform: translate(-170px, 104px) scale(0.88) rotate(-16deg); }
        71% { transform: translate(-184px, 116px) scale(0.89) rotate(-26deg); }
        75% { transform: translate(-206px, 136px) scale(0.92) rotate(-24deg); }
        80% { transform: translate(-232px, 154px) scale(0.96) rotate(-20deg); }
        87% { transform: translate(-264px, 176px) scale(1.01) rotate(-12deg); opacity: 1; }
        92% { transform: translate(-284px, 188px) scale(1.05) rotate(0deg); }
        95% { transform: translate(-287px, 192px) scale(1.07) rotate(0deg); opacity: 0; }
        100% { transform: translate(-287px, 192px) scale(1) rotate(14deg); opacity: 0; }
      }

      #lift_chair { animation: scf-lift-ride 24s linear infinite; }
      @keyframes scf-lift-ride {
        0% { transform: translate(-27px, 62px) scale(1); opacity: 1; }
        38% { transform: translate(87px, -198px) scale(0.7); opacity: 1; }
        42% { transform: translate(87px, -198px) scale(0.7); opacity: 0; }
        100% { transform: translate(-27px, 62px) scale(1); opacity: 0; }
      }

      /* Empty T-bars so the drag lift is never bare: a continuous procession
         up the same cable, one offset half a cycle so one is always mid-ascent
         while the other resets. Same start/end transforms as the loaded chair
         so they share the cable line; the transform interpolates linearly (the
         12%/88% stops only fade opacity, hiding the top-to-bottom reset). */
      #lift_chair_a, #lift_chair_b {
        transform-origin: center;
        transform-box: fill-box;
        animation: scf-lift-run 9s linear infinite;
      }
      #lift_chair_b { animation-delay: -4.5s; }
      @keyframes scf-lift-run {
        0% { transform: translate(-27px, 62px) scale(1); opacity: 0; }
        12% { opacity: 1; }
        88% { opacity: 1; }
        100% { transform: translate(87px, -198px) scale(0.7); opacity: 0; }
      }

      /* Chimney smoke: a thin wisp rising from the hut on the migration flank,
         three soft puffs staggered a third of the cycle apart so it reads as a
         continuous curl. Each grows and drifts slightly left (matching the
         cloud drift) as it rises, then fades. */
      .scf-smoke {
        transform-origin: center;
        transform-box: fill-box;
        animation: scf-smoke-rise 5s ease-out infinite;
      }
      .scf-smoke-2 { animation-delay: -1.67s; }
      .scf-smoke-3 { animation-delay: -3.33s; }
      @keyframes scf-smoke-rise {
        0% { transform: translate(0, 0) scale(0.5); opacity: 0; }
        20% { opacity: 0.42; }
        100% { transform: translate(-9px, -46px) scale(1.6); opacity: 0; }
      }

      /* Wind in the pines (pilot on the #trees cluster only): each tree tilts a
         hair around its own base, split into three phase groups so the cluster
         shimmers organically instead of swaying in lockstep. Amplitude is tiny
         (a flat triangle looks wobbly if overdone); origin: bottom keeps the
         trunk planted. */
      #trees > path {
        transform-box: fill-box;
        transform-origin: bottom;
        animation: scf-tree-sway 4.5s ease-in-out infinite;
      }
      #trees > path:nth-child(4n + 1) { animation-delay: -0.6s; }
      #trees > path:nth-child(4n + 2) { animation-delay: -1.9s; }
      #trees > path:nth-child(4n + 3) { animation-delay: -3.1s; }
      @keyframes scf-tree-sway {
        0%, 100% { transform: rotate(-0.8deg); }
        50% { transform: rotate(0.8deg); }
      }

      /* A pair of gulls soaring across the open sky above the peaks (kept left
         of the cloud). The group glides left to right in a shallow arc and
         fades at each end; each bird gives a slow, subtle wing-flap, offset so
         they don't beat in unison. */
      #birds {
        animation: scf-birds-glide 34s linear infinite;
      }
      @keyframes scf-birds-glide {
        0% { transform: translate(0, 0); opacity: 0; }
        10% { opacity: 0.6; }
        50% { transform: translate(250px, -16px); opacity: 0.6; }
        90% { opacity: 0.6; }
        100% { transform: translate(500px, 4px); opacity: 0; }
      }
      .scf-bird {
        transform-box: fill-box;
        transform-origin: center;
        animation: scf-bird-flap 1.6s ease-in-out infinite;
      }
      .scf-bird-2 { animation-delay: -0.8s; }
      @keyframes scf-bird-flap {
        0%, 100% { transform: scaleY(0.85); }
        50% { transform: scaleY(1.18); }
      }


      /* The goat. She comes in at the bottom right where the ISV flank meets
         the frame, crosses the whole foot of the mountain behind the market stall,
         turns on the spot to the left of it and climbs the left shoulder to the summit
         snow cap, where she stands for about twenty seconds and fades out. The
         jump back to the start happens while she is invisible, so she never
         walks back down.

         The long way round is the whole point, and it is not taste. The overlay
         buttons are fixed pixels while the artwork is fluid, so in view-box
         units they GROW as the window narrows: at a 1201px window the gap
         between the ISV button and the Marketplace button is down to 24 units.
         Measured against the built page, a goat climbing the ridge is fully
         hidden behind the Marketplace button for 3.75 to 5.5 seconds at every
         width, and below 1280px she is cut for more than half the climb. This
         route keeps its distance from both button centres, and those grow
         outwards: at no width is more than 21 per cent of her covered, never
         half, never gone. */
      #scf_goat .scf-goat-ride {
        animation: scf-goat-climb 50s ease-in-out infinite;
      }
      #scf_goat .scf-goat-hop {
        animation: scf-goat-hop 50s linear infinite;
      }
      /* Opacity sits on its own group above the movement. Fading and moving on
         the same element would fight over the transform during the reset. */
      #scf_goat .scf-goat-fade {
        animation: scf-goat-vanish 50s linear infinite;
      }
      #scf_goat .scf-goat-idle {
        transform-box: fill-box;
        transform-origin: bottom center;
        animation: scf-goat-breathe 4.6s ease-in-out infinite;
      }
      /* The turn at the switchback. The flip is a jump, not a tween: scaling x
         through zero squeezes the flat artwork to a line and reads as a card
         being turned over. She flips at the top of a hop on the spot instead. */
      #scf_goat .scf-goat-turn {
        transform-box: fill-box;
        transform-origin: center;
        animation: scf-goat-turn 50s linear infinite;
      }
      /* The beard sits next to the <use>, not inside the <symbol>. Animated
         inside the symbol it made the browser rebuild the use copy on every frame,
         which cost half the scene's main thread time (195 against 98 ms per
         second, measured 24.09.2026). Keep it out when the goat is redrawn. */
      .scf-goat-beard {
        transform-box: fill-box;
        transform-origin: top center;
        animation: scf-goat-beard 3.1s ease-in-out infinite;
      }

      /* Seven legs with a hold on each. The four across the foot are level, the
         three up the shoulder are short and steep. The last hold is the summit
         and runs until she fades; the reset sits between 89 and 94 per cent,
         where she is already invisible.

         The x offsets after the turn carry a 7.2 unit correction: mirroring
         flips the artwork inside its box, so her hooves land on the other side
         of the box centre and the translate has to take that back. In the hold
         at the switchback the shift is 3.2 units and lands in the same frame as
         the flip, measured so her hooves come down where they left the ground. */
      @keyframes scf-goat-climb {
        0%, 4% { transform: translate(272px, 146px); }
        8%, 11.5% { transform: translate(176px, 135px); }
        15.5%, 19% { transform: translate(80px, 124px); }
        23%, 26.5% { transform: translate(-16px, 113px); }
        30.5%, 32.5% { transform: translate(-112px, 102px); animation-timing-function: steps(1, start); }
        33%, 35% { transform: translate(-108.8px, 102px); }
        39%, 42% { transform: translate(-85.2px, 51px); }
        45.5%, 48.5% { transform: translate(-45.2px, 19px); }
        52%, 89% { transform: translate(-7.2px, 0); }
        94%, 100% { transform: translate(272px, 146px); }
      }
      /* One hop per leg, flat while she stands, plus one on the spot for the turn. */
      @keyframes scf-goat-hop {
        0%, 4%, 8%, 11.5%, 15.5%, 19%, 23%, 26.5%, 30.5%, 31.5%, 33.5%, 35%, 39%, 42%, 45.5%, 48.5%, 52%, 89%, 100% { transform: translateY(0); }
        6%, 13.5%, 21%, 28.5%, 37%, 43.75%, 50.25% { transform: translateY(-8px); }
        32.5% { transform: translateY(-6px); }
      }
      /* She turns inside the hold at the switchback, and turns back while she is
         invisible so the next loop starts facing the right way. */
      @keyframes scf-goat-turn {
        0%, 32.5% { transform: scaleX(1); animation-timing-function: steps(1, start); }
        33%, 90% { transform: scaleX(-1); }
        93%, 100% { transform: scaleX(1); }
      }
      @keyframes scf-goat-vanish {
        0%, 84% { opacity: 1; }
        88%, 95% { opacity: 0; }
        100% { opacity: 1; }
      }
      @keyframes scf-goat-breathe {
        0%, 100% { transform: scaleY(1); }
        50% { transform: scaleY(1.035); }
      }
      @keyframes scf-goat-beard {
        0%, 100% { transform: rotate(-5deg); }
        50% { transform: rotate(5deg); }
      }

      @media (prefers-reduced-motion: reduce) {
        #cloud, #background_clouds, #gondola_cabin, #gondola_cabin_2,
        .scf-cabin-body, .scf-balloon-body,
        #skier, #snowboarder, #lift_chair, #lift_chair_a, #lift_chair_b,
        #balloon { animation: none; }
        /* Park the balloon clear of the ridge it now starts behind: at its Figma
           default it would sit half buried in the ISV mountain. */
        #balloon { transform: translate(55px, -120px) scale(0.53); }
        /* Park the two empty T-bars mid-cable so the lift still reads as
           populated when motion is off (otherwise they rest at the base,
           stacked on the loaded chair). */
        #lift_chair_a { transform: translate(13px, -29px) scale(0.9); }
        #lift_chair_b { transform: translate(50px, -115px) scale(0.8); }
        /* Park the loaded chair and its rider together, mid-ascent. Both ride
           linearly over the same 0-38% leg, so the same fraction of each keeps
           them attached; without this the chair rests at the base and the rider
           sits at his Figma default, stranded well off the cable. */
        #lift_chair { transform: translate(33px, -75px) scale(0.84); }
        #snowboarder { transform: translate(-227px, 56px) scale(0.84) rotate(14deg); }
        /* Smoke is motion by nature; hide it entirely rather than freeze a puff. */
        #chimney_smoke { display: none; }
        #trees > path { animation: none; }
        #birds { display: none; }
        /* Also halt the hidden groups and their child animations: display:none
           does not stop keyframes in every engine (WebKit keeps ticking), so
           name them explicitly. */
        #birds, .scf-smoke, .scf-bird { animation: none; }
        /* Park both cabins on the rope. With the ride disabled a cabin would
           otherwise sit at its SVG default, ~5.6px below the cable; give each a
           static on-cable resting spot (two spots so both stay visible). */
        #gondola_cabin { transform: translate(0, -5.6px); }
        #gondola_cabin_2 { transform: translate(53.8px, -14.9px); }
        /* Same for the Data & AI cabin: park it out on the long span rather
           than at its SVG default, which sits nowhere near the rope. */
        #scf_dai_cabin { animation: none; transform: translate(378px, 552px) scale(0.81); }
        /* Park her standing on the summit and visible, facing the way she
           arrived. That is where the loop ends, and the only spot that reads as
           arrived rather than halfway. These repeat the id of the rules above on
           purpose: a class-only selector loses to them and she would keep
           climbing. */
        #scf_goat .scf-goat-ride, #scf_goat .scf-goat-hop,
        #scf_goat .scf-goat-fade, #scf_goat .scf-goat-idle,
        #scf_goat .scf-goat-turn,
        .scf-goat-beard { animation: none; }
        #scf_goat .scf-goat-ride { transform: translate(-7.2px, 0); }
        #scf_goat .scf-goat-turn { transform: scaleX(-1); }
        #scf_goat .scf-goat-fade { opacity: 1; }
      }

      /* Contributors village: parked a touch lower so the hover lift
         (translateY(-5px) on the anchor) never opens a gap under the houses,
         and the house windows light up while the village or its overlay
         button is hovered. */
      #start {
        translate: 0 6px;
      }

      #start [id="Rectangle 1080"],
      #start [id="Rectangle 1081_2"],
      #start [id="Ellipse 707"] {
        transition: fill 0.3s ease, fill-opacity 0.3s ease;
      }

      a.scf-interactive[href*="contributors"]:hover [id="Rectangle 1080"],
      a.scf-interactive[href*="contributors"]:hover [id="Rectangle 1081_2"],
      a.scf-interactive[href*="contributors"]:hover [id="Ellipse 707"],
      .scf-interactive-map:has(#btn-contributors:hover) [id="Rectangle 1080"],
      .scf-interactive-map:has(#btn-contributors:hover) [id="Rectangle 1081_2"],
      .scf-interactive-map:has(#btn-contributors:hover) [id="Ellipse 707"] {
        fill: #ffd76a;
        fill-opacity: 1;
      }



      /* The cloud links to the STACKIT Portal. It carries the same kind of overlay
         button as every other landmark, with the outbound arrow the Marketplace uses,
         because both lead off the framework. A baked-in text label could not say that, and it
         had to fight the cloud's radial fill, which runs from a dim middle out to a
         pale rim. */
      /* Every other button sits on a bright mountain. This one sits inside the cloud,
         which is the darkest ground on the map. Both outbound pills are defined the
         same way and let 28 per cent of their ground through, so at 1600px the Portal
         pill measured luminance 32 against the Marketplace pill at 44. The ground was
         corrected rather than the pill: the two radial gradients of #cloud started
         fully transparent in the middle, so what showed through there was the night
         sky and not the cloud. Their stops start at 0.1 now and the two pills sit
         within four points of each other. A fresh Figma export of the cloud drops that
         again, the stop opacities have to be raised by hand.
         The halo settles the button into the cloud instead of fencing it in: a soft
         glow in the button's own colour rather than an edge, and only the label is
         left standing. Hover puts the edge back.
         An earlier attempt drew a light hairline and it read as a bright rim wherever
         the cloud behind it happened to be dark.
         The halo has to scale with the BUTTON, not with the artwork. The button is laid
         out in pixels while the cloud scales with the viewBox, so measured across widths
         it covers anywhere between 102 and 256 viewBox units. em follows the font size
         set by the breakpoints above. A gradient painted into the SVG could not.
         Light mode keeps the shadow: the cloud is white there and the button is dark, so
         a halo in its colour becomes a storm patch without ever blending in.
         High contrast keeps it too. A mode chosen for legibility should not hand out a
         control that dissolves into its background on purpose. */
      #btn-portal {
        --portal-rest-shadow: 0 4px 18px rgba(6, 20, 30, 0.55), 0 0 0 1px rgba(6, 20, 30, 0.35);
        box-shadow: var(--portal-rest-shadow);
      }
      :root[data-theme='dark']:not(.theme--high-contrast) #btn-portal {
        --portal-rest-shadow: 0 0 1.625em 0.875em #25323D;
      }
      /* Below this width the button nearly fills the cloud, 63px inside 85px at 768,
         so the halo would swallow the whole shape including its cyan rim. */
      @media(max-width: 900px) {
        :root[data-theme='dark']:not(.theme--high-contrast) #btn-portal {
          --portal-rest-shadow: 0 4px 18px rgba(6, 20, 30, 0.55), 0 0 0 1px rgba(6, 20, 30, 0.35);
        }
      }
      /* The shared .scf-btn-overlay:hover rule loses to the id above, so the hover
         shadow has to be stated again here to actually replace the resting one. */
      #btn-portal:hover,
      #btn-portal:focus-visible {
        box-shadow: 0px 0px 10px rgba(255,255,255,0.08), 0px 4px 12px rgba(0,0,0,0.3);
      }

      .scf-interactive-map:has(#btn-portal:hover) a.scf-interactive[href*="portal.stackit.cloud"] {
        filter: brightness(1.4) drop-shadow(0px 10px 15px rgba(0,0,0,0.4));
      }
      .scf-interactive-map:has(#btn-portal:hover) a.scf-interactive[href*="portal.stackit.cloud"] > g {
        transform: translateY(-5px) scale(1.02);
      }
      .scf-interactive-map:has(a.scf-interactive[href*="portal.stackit.cloud"]:hover) #btn-portal {
        background: #4C6072;
        color: #FFFFFF;
        box-shadow: 0px 0px 15px rgba(255,255,255,0.15), 0px 4px 12px rgba(0,0,0,0.3);
      }

      /* Portal and Marketplace are the two buttons that lead off the framework. They
         already carry the outbound arrow instead of the forward one; the colour now
         says the same thing before anyone reads the label. The pill is translucent
         and outlined where the framework pills are solid, so it lets the mountain
         through instead of sitting on it, and the label is muted with it. Hover is
         deliberately left alone, so the
         affordance still matches every other button on the map. Guarded by its own
         query because an id selector would otherwise flatten the chip ring below
         1200px. */
      @media(min-width: 1201px) {
        #btn-portal, #btn-market {
          background: rgba(18, 26, 34, 0.72);
          border: 1px solid rgba(226, 232, 238, 0.3);
          color: #B8C6D0;
        }
        #btn-portal .scf-btn-arrow, #btn-market .scf-btn-arrow { opacity: 0.75; }
      }

      /* Marketplace: the open stall at the foot of the ISV mountain. It sits there
         because that is where the vendors are, and it is its own landmark rather
         than a seventh framework, so like the cloud it leads off the framework and its
         button carries the outbound arrow instead of the forward one. The hut on
         the migration flank carried this link until 1 Sep and is a prop of that
         mountain again. Hover lights the inside of the stall - it is open, and the
         crates on the counter read as silhouettes against the warm light. A glow
         around the building would wash out on the teal face, so the light sits in
         the back panel itself. */
      .scf-market-link .scf-house-glass {
        transition: fill 0.3s ease, filter 0.3s ease;
      }

      .scf-market-link:hover .scf-house-glass,
      .scf-market-link:focus-visible .scf-house-glass,
      .scf-interactive-map:has(#btn-market:hover) .scf-house-glass,
      .scf-interactive-map:has(#btn-market:focus-visible) .scf-house-glass {
        fill: #ffd76a;
        filter: drop-shadow(0 0 3px rgba(255, 215, 106, 0.85));
      }

      /* The stall is a link too, so its button couples with it exactly like a
         mountain and its button do. */
      .scf-interactive-map:has(#btn-market:hover) a.scf-market-link {
        filter: brightness(1.4) drop-shadow(0px 10px 15px rgba(0,0,0,0.4));
      }
      .scf-interactive-map:has(#btn-market:hover) a.scf-market-link > g {
        transform: translateY(-5px) scale(1.02);
      }
      .scf-interactive-map:has(a.scf-market-link:hover) #btn-market {
        background: #4C6072;
        color: #FFFFFF;
        box-shadow: 0px 0px 15px rgba(255,255,255,0.15), 0px 4px 12px rgba(0,0,0,0.3);
      }

      /* The balloon links to schwarz-digits.de and opens in a new tab. It has no overlay
         button, so the SVG link itself carries the name and stays in the tab order. It
         sits in the decorative pointer-events:none list above; this rule comes later with
         the same specificity, so it wins. */
      #balloon { pointer-events: auto; cursor: pointer; }
      /* Hover and focus fire the burner: a warm glow, the amber of the village windows.
         filter, not transform, so it composes with the ride and the sway. The glow is also
         the focus mark, which is why the outline can go. */
      .scf-balloon-link { -webkit-tap-highlight-color: transparent; outline: none; }
      .scf-balloon-link:hover #balloon,
      .scf-balloon-link:focus-visible #balloon {
        filter: drop-shadow(0 0 9px rgba(255, 200, 92, 0.9)) brightness(1.05);
      }
      /* A link that flies away under the cursor is hard to hit, so the flight holds
         while it is hovered. */
      .scf-balloon-link:hover #balloon,
      .scf-balloon-link:hover .scf-balloon-body {
        animation-play-state: paused;
      }
      /* Keyboard focus can arrive while the balloon is behind the ISV ridge or already
         out of frame. It then jumps to the spot reduced motion parks it at, which is
         always in view, and flies on from the start once focus leaves. */
      .scf-balloon-link:focus-visible #balloon {
        animation: none;
        opacity: 1;
        transform: translate(55px, -120px) scale(0.53);
      }

      /* The mountain used to be the whole page: nothing sat below it, so scrolling was
         locked and the footer hidden. The framework cards live under it now, so the page
         scrolls again. The footer stays hidden: its legal links are in the left sidebar,
         and the cards are meant to read as the end of the page. */
      footer.minimal-footer { display: none !important; }

      /* The six frameworks in the two clusters the sidebar already groups them into: the
         base frameworks a reader starts from, then the scenario frameworks built on them.
         Three to a row, so a cluster IS a row and the grouping needs no explaining.
         Keep the order in step with sidebarClusters in docs.config.ts. */
      .scf-fw-cards {
        /* Geometry copied from .scf-hero-wrapper on purpose, cap included, so the block
           has exactly the same left and right edge as the mountain above it. The
           centring only works while the element is a full 100cqw wide: left: 50% is
           measured against the 800px prose column, not against the content pane, and on
           a narrower box that offset no longer cancels out - it drifted 532px to the
           right at 1920px before. The width cap therefore sits on the rows below, never
           here. */
        position: relative;
        width: 100cqw;
        max-width: min(100cqw, calc(85vh * 1632 / 800));
        left: 50%;
        transform: translateX(-50%);
        margin: 0 0 3rem;
        padding: 0 1rem;
        box-sizing: border-box;
      }

      /* 3 x 324px card + 2 x 24px gap: the size the cards were drawn at. Centred under
         the mountain rather than stretched to its full width, which on a wide screen
         would blow the card's own type up past the page's type scale. */
      .scf-fw-cluster,
      .scf-fw-row {
        max-width: 1020px;
        margin-inline: auto;
      }

      /* Section headings for the three clusters. Sized and coloured like the STACKIT
         product-overview captions ("Developer Tools"): a real section heading. */
      .scf-fw-cluster {
        /* margin-block only: the shorthand would reset the margin-inline: auto above
           and the captions would jump back to the left edge of the full-width block. */
        margin-block: 3rem 1.5rem;
        font-family: var(--nds-mode-font-family-heading, 'Univia Pro'), sans-serif;
        font-size: 2rem;
        font-weight: 500;
        line-height: 1.2;
        color: #c2cfdb;
      }
      /* #c2cfdb is a dark-mode value; in light mode fall back to the theme text token. */
      :root[data-theme='light'] .scf-fw-cluster {
        color: var(--nds-mode-color-foreground-neutral-default, #1a2b38);
      }
      .scf-fw-row + .scf-fw-cluster { margin-top: 4rem; }

      .scf-fw-row {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: 24px;
        margin-block: 0;
        padding: 0;
        list-style: none;
      }
      @media (max-width: 900px) {
        .scf-fw-row { grid-template-columns: repeat(2, 1fr); }
        .scf-fw-cluster { font-size: 1.625rem; }
      }
      @media (max-width: 600px) {
        .scf-fw-row { grid-template-columns: 1fr; }
        /* The menu opens beside the button, so on a phone the button has to give the
           menu room - trim it down here. */
        .scf-cta-face { font-size: 14px; padding: 8px 12px; min-height: 40px; }
        .scf-cta-chevron { width: 14px; height: 14px; }
        .scf-cta-option { padding: 9px 8px; gap: 10px; }
        .scf-cta-option-icon { width: 22px; height: 22px; }
        .scf-cta-option-label { font-size: 14px; }
        .scf-cta-option-desc { font-size: 12px; }
      }

      .scf-fw-card {
        display: block;
        border-radius: 16px;
        text-decoration: none !important;
        transition: transform 0.25s ease, box-shadow 0.25s ease;
      }
      /* Inline, not an <img>: CSS cannot reach inside an image, and the summit marker has
         to answer a hover. The artwork is the same file either way. */
      .scf-fw-card svg {
        display: block;
        width: 100%;
        height: auto;
      }

      /* The marker answers its card the way a mountain answers its button on the map
         above: it lifts, brightens and sends out one ring. Same 1.8s ease-out as
         scf-btn-ping, so both effects read as one language. */
      .scf-summit-body {
        transform-box: fill-box;
        transform-origin: center;
        transition: transform 0.25s ease, filter 0.25s ease;
      }
      .scf-fw-card:hover .scf-summit-body,
      .scf-fw-card:focus-visible .scf-summit-body {
        transform: translateY(-4px) scale(1.08);
        filter: brightness(1.35) drop-shadow(0px 0px 10px rgba(76, 219, 228, 0.55));
      }
      .scf-summit-ping {
        transform-box: fill-box;
        transform-origin: center;
      }
      .scf-fw-card:hover .scf-summit-ping,
      .scf-fw-card:focus-visible .scf-summit-ping {
        animation: scf-summit-ping 1.8s ease-out infinite;
      }
      @keyframes scf-summit-ping {
        0% { transform: scale(1); opacity: 0.55; }
        100% { transform: scale(1.7); opacity: 0; }
      }
      .scf-fw-card:hover,
      .scf-fw-card:focus-visible {
        transform: translateY(-4px);
        box-shadow: 0px 12px 28px rgba(0, 0, 0, 0.35);
      }
      .scf-fw-card:focus-visible {
        outline: 2px solid var(--nds-mode-color-border-focus-default, #00C2CC);
        outline-offset: 3px;
      }
      @media (prefers-reduced-motion: reduce) {
        .scf-fw-card,
        .scf-summit-body { transition: none; }
        .scf-fw-card:hover,
        .scf-fw-card:focus-visible,
        .scf-fw-card:hover .scf-summit-body,
        .scf-fw-card:focus-visible .scf-summit-body { transform: none; }
        .scf-fw-card:hover .scf-summit-ping,
        .scf-fw-card:focus-visible .scf-summit-ping { animation: none; }
      }

      /* The artwork is drawn for a dark ground: an opaque navy plate, white type and a
         teal glow for depth. On a light page that reads as nine dark slabs under a bright
         mountain scene. Dark mode stays the base and light is the only override, the same
         way the diagrams under migration/files handle it.
         Letting the plate drop away so the artwork floats on the page was tried first,
         because that is how the mountain scene above manages without a light variant. It
         does not carry here: the scene has no clip and its silhouette may run out freely,
         while a card is clipped to a rounded rectangle. Migration, Data and AI and ISV
         fill that rectangle edge to edge, so they turned into dark blocks instead of
         merging. A light plate is the one answer that holds across all nine.
         The hooks are class attributes in the nine SVGs. They are inline via set:html, so
         these rules reach inside them. Keep the anchors when re-exporting from Figma. */
      /* White, not a tinted surface: the plate is the same colour as the page, so the
         border alone has to say where a card begins. That is why it takes the site border
         token rather than the softer value the diagrams use, which measures 1.4:1 against
         white and all but disappears. */
      :root[data-theme='light'] .scf-fw-card .scf-card-plate { fill: #FFFFFF; }
      :root[data-theme='light'] .scf-fw-card .scf-card-edge {
        stroke: var(--nds-mode-color-border-neutral-default-rest, #BEC8D1);
      }
      /* The scrim darkens the top of the illustration so it recedes behind the navy. On a
         light plate there is nothing to recede into, and it would only grey the artwork. */
      :root[data-theme='light'] .scf-fw-card .scf-card-scrim { display: none; }
      /* The glow keeps its geometry and flips its direction. On the navy plate it is opaque
         at the upper left and fades out towards the lower right, so recolouring it alone
         would have laid the tint across the top of the card, which is the opposite of what
         a light card wants. Swapping the two opacities turns it around: nothing at the top,
         a soft tone settling towards the bottom, so the card reads as white and still has a
         base to stand on. The two plate gradients are the only ones named paint0 and paint1,
         everything above that number belongs to the illustration, which is why the id
         prefix is a safe handle. */
      :root[data-theme='light'] .scf-fw-card linearGradient[id^='paint0'] stop:first-child {
        stop-color: #FFFFFF;
        stop-opacity: 0;
      }
      :root[data-theme='light'] .scf-fw-card linearGradient[id^='paint0'] stop:last-child {
        stop-color: #CDECF0;
        stop-opacity: 1;
      }
      /* Measured on the plate, not chosen by eye: the neutral tokens resolve to #464b50 and
         #888e93 in light mode, and the subtle one gives the description 3.1:1, which fails
         AA. These two come from the migration overview diagram instead and reach 15.1:1
         and 6.4:1, and they keep a heading apart from its body copy. */
      :root[data-theme='light'] .scf-fw-card .scf-card-title { fill: #16232C; }
      :root[data-theme='light'] .scf-fw-card .scf-card-desc  { fill: #4C5D69; }
      /* The summit marker is a dark disc with a cyan ring, both tuned for the navy plate.
         The cyan is the dark-surface accent, on a light plate it goes thin, so the
         light-surface accent of the same brand takes over. The ring and the glyph carry no
         class: they are the only elements that use the accent as a plain fill or stroke
         attribute, everywhere else in the artwork it is a gradient stop. */
      :root[data-theme='light'] .scf-fw-card .scf-card-marker-disc { fill: #E3F6F7; }
      :root[data-theme='light'] .scf-fw-card [stroke='#4CDBE4'] {
        stroke: var(--nds-brand-color-accent-light-contrast-090, #009EA8);
      }
      :root[data-theme='light'] .scf-fw-card g[fill='#4CDBE4'] {
        fill: var(--nds-brand-color-accent-light-contrast-090, #009EA8);
      }
      /* The base shadow is built for a dark page and turns into a smudge on a light one. */
      :root[data-theme='light'] .scf-fw-card:hover,
      :root[data-theme='light'] .scf-fw-card:focus-visible {
        box-shadow: 0px 12px 28px rgba(22, 35, 44, 0.12);
      }

      /* Each card carries both language versions of its description as real text, and the
         page language picks one. The titles are the same word in both trees, so they exist
         only once. Written as a language switch rather than a second set of card files:
         the artwork is the expensive part and has to stay single-source, so a re-export
         from Figma lands in one place instead of two.
         |= and not =: Starlight stamps the full language tag, en-GB and de-DE, so an
         exact match would never fire and every page would keep the English text. */
      .scf-fw-card .scf-lang-de { display: none; }
      html[lang|='de'] .scf-fw-card .scf-lang-en { display: none; }
      html[lang|='de'] .scf-fw-card .scf-lang-de { display: inline; }

      /* The artwork carries aria-hidden, so the link says nothing by itself. The same
         wording lives here as real text, hidden from sight only, and carries the
         accessible name. It reads as one sentence, where the artwork would hand a screen
         reader one line at a time. */
      .scf-fw-text {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
      }

      /* ─────────────────────────────────────────────────────────────────
         Phones: the map becomes a panorama, swiped sideways. At phone width
         the whole scene would be 342px wide and its chips 24px, too small to
         use. So below 600px the map is laid out 800px wide, where the chips
         reach their 44px cap, in a strip (.scf-pan-strip) that scrolls
         sideways. The top 44px of sky are cut off. The script in basecamp
         (scf-frontpage-magnet-hover.astro) adds three stops to snap to,
         starts at the middle one, draws the dots below and sets more-left and
         more-right on the frame for the soft edges. Without the script the
         strip still scrolls, from its left end.
         The hero wrapper turns into display: contents, as it did for the
         camera before: intro, scene and cards then stand in one column. That
         drops the wrapper's margins and its z-index for the open Get Started
         menu, so both are restated on the content box. The cards show their
         text instead of their picture, the scene above already shows the
         mountain. */
      @media (max-width: 600px) {
        .scf-hero-wrapper { display: contents; }
        .scf-hero-content-box { margin-top: -1.5rem; }
        /* inset: auto matters. The desktop rule places this box with left: max(2rem, 8%)
           and top: 2%, which a static box ignores but a relative one applies: opening
           the menu pushed the whole intro 32px to the right. */
        .scf-hero-content-box:has(.scf-cta[open]) { position: relative; inset: auto; z-index: 50; }

        .scf-pan {
          width: 100vw;
          margin-inline: calc(50% - 50vw);
          margin-bottom: 1.5rem;
        }
        .scf-pan-frame { position: relative; }
        /* The soft edge on the side where more of the map lies. */
        .scf-pan-frame::before,
        .scf-pan-frame::after {
          content: '';
          position: absolute;
          top: 0;
          bottom: 0;
          z-index: 2;
          width: 36px;
          pointer-events: none;
          opacity: 0;
          transition: opacity 0.25s;
        }
        .scf-pan-frame::before {
          left: 0;
          background: linear-gradient(90deg, var(--nds-mode-color-background-neutral-surface-default-rest, #18232C), transparent);
        }
        .scf-pan-frame::after {
          right: 0;
          background: linear-gradient(270deg, var(--nds-mode-color-background-neutral-surface-default-rest, #18232C), transparent);
        }
        .scf-pan-frame.more-left::before,
        .scf-pan-frame.more-right::after { opacity: 0.9; }
        .scf-pan-strip {
          position: relative;
          overflow-x: auto;
          overflow-y: hidden;
          scroll-snap-type: x mandatory;
          overscroll-behavior-x: contain;
          scrollbar-width: none;
        }
        .scf-pan-strip::-webkit-scrollbar { display: none; }
        .scf-pan-strip .scf-interactive-map {
          display: block;
          width: 800px;
          margin-top: -44px;
        }
        /* The script places one of these at each stop. */
        .scf-pan-stop {
          position: absolute;
          top: 0;
          width: 1px;
          height: 1px;
          scroll-snap-align: start;
        }

        .scf-fw-row { gap: 12px; }
        .scf-fw-card .scf-fw-art { display: none; }
        .scf-fw-card .scf-fw-text {
          position: static;
          display: block;
          width: auto;
          height: auto;
          margin: 0;
          padding: 16px 18px;
          overflow: visible;
          clip: auto;
          clip-path: none;
          white-space: normal;
          border: 1px solid #2C3D4A;
          border-radius: 16px;
          background: #162938;
          color: #E7EAED;
          font-size: 0.875rem;
          line-height: 1.45;
        }
        .scf-fw-card .scf-fw-title {
          display: block;
          margin-bottom: 4px;
          color: #FFFFFF;
          font-size: 1.0625rem;
          font-weight: 700;
        }
        /* The ". " between title and text is for screen readers only. */
        .scf-fw-card .scf-fw-sep {
          position: absolute;
          width: 1px;
          height: 1px;
          overflow: hidden;
          clip-path: inset(50%);
          white-space: nowrap;
        }
        :root[data-theme='light'] .scf-fw-card .scf-fw-text {
          border-color: var(--nds-mode-color-border-neutral-default-rest, #BEC8D1);
          background: #FFFFFF;
          color: #4C5D69;
        }
        :root[data-theme='light'] .scf-fw-card .scf-fw-title { color: #16232C; }

        @media (prefers-reduced-motion: reduce) {
          .scf-pan-frame::before,
          .scf-pan-frame::after { transition: none; }
        }
      }

      /* ─────────────────────────────────────────────────────────────────
         Data & AI is not released yet. On the map the mountain keeps its
         full colour but turns into a "site under construction" scene
         instead of a link: a piste groomer works switchbacks down the face
         and a small hazard sign stands at its foot. The sidebar entry, the
         Scenario card and the map chip stay greyed out and inert.
         To release it, delete: this block (in BOTH index.mdx files), the
         matching block in components/sidebar.astro, and the #scf_dai_wip
         group, the #scf_dai_block path and their hide-style in
         contributors/stackit/core/interactive_header.svg.
         ───────────────────────────────────────────────────────────────── */
      /* Not clickable, but not dimmed either - the construction scene
         carries the "not yet" message on its own. */
      .scf-interactive-map a.scf-interactive[href*="data-and-ai"],
      .scf-interactive-map a.scf-interactive[href*="data-and-ai"]:hover {
        pointer-events: none;
        cursor: default;
      }
      .scf-interactive-map a.scf-interactive[href*="data-and-ai"] > use.scf-hit {
        pointer-events: none;
      }
      .scf-interactive-map a.scf-interactive[href*="data-and-ai"]:hover > g {
        transform: none;
      }
      /* No skiing on a piste that is still being built. */
      #skier { display: none !important; }
      /* Reveal the construction scene (the group is display:none in the SVG). */
      #scf_dai_wip { display: block !important; }
      /* The board speaks the page's language. |= because Starlight stamps de-DE. */
      html[lang|='de'] #scf_dai_wip .scf-lang-en { display: none; }
      html[lang|='de'] #scf_dai_wip .scf-lang-de { display: inline; }
      /* The mountain still has to swallow the pointer, even though it no longer
         leads anywhere: the anchor is pointer-events:none above, so without this the
         cursor falls through to the advisory mountain painted behind it and hovers
         and opens that one instead. #scf_dai_block sits outside every anchor, so it
         catches the pointer and does nothing. */
      #scf_dai_block {
        display: block !important;
        pointer-events: all;
      }
      #scf_dai_groomer {
        /* No transform-box: SVG default origin (the sprite's own drawn centre)
           is what the tilt should pivot on, and it keeps translate() in plain
           user units. Slow - a groomer crawls; one pass down takes ~30s. */
        animation: scf-dai-groom 30s ease-in-out infinite;
      }
      /* Switchbacks down the front face of the Data & AI mesa. Offsets are in
         SVG user units from the groomer's parked spot near the plateau
         (translate 196 660 in the SVG). Each bend has a short dwell and a flip
         that happens in one frame (steps), so it reads as a vehicle turning, not as
         a card being turned over. The lists keep the same functions in the same
         order on every stop; a mismatch makes the browser tween the matrix and skew. */
      @keyframes scf-dai-groom {
        0%       { transform: translate(0, 0) scaleX(1) rotate(14deg); opacity: 0; }
        3%       { transform: translate(0, 0) scaleX(1) rotate(14deg); opacity: 1; }
        22%      { transform: translate(60px, 34px) scaleX(1) rotate(14deg); }
        26%      { transform: translate(60px, 36px) scaleX(1) rotate(14deg); animation-timing-function: steps(1, start); }
        26.5%    { transform: translate(60px, 36px) scaleX(-1) rotate(14deg); }
        29%      { transform: translate(56px, 44px) scaleX(-1) rotate(14deg); }
        48%      { transform: translate(-130px, 66px) scaleX(-1) rotate(14deg); }
        52%      { transform: translate(-130px, 68px) scaleX(-1) rotate(14deg); animation-timing-function: steps(1, start); }
        52.5%    { transform: translate(-130px, 68px) scaleX(1) rotate(14deg); }
        55%      { transform: translate(-124px, 76px) scaleX(1) rotate(14deg); }
        74%      { transform: translate(72px, 96px) scaleX(1) rotate(14deg); }
        78%      { transform: translate(72px, 98px) scaleX(1) rotate(14deg); animation-timing-function: steps(1, start); }
        78.5%    { transform: translate(72px, 98px) scaleX(-1) rotate(14deg); }
        81%      { transform: translate(66px, 106px) scaleX(-1) rotate(14deg); }
        96%      { transform: translate(-114px, 116px) scaleX(-1) rotate(14deg); opacity: 1; }
        99%, 100% { transform: translate(-116px, 120px) scaleX(-1) rotate(14deg); opacity: 0; }
      }
      /* The dotted line is the route still to cut. Behind the machine a fat
         pale stroke (#scf_dai_groomed) "draws in" over it, so the finished
         piste visibly grows. Its stops line up with the scf-dai-groom bends:
         bend 1 is ~11% along the path, bend 2 ~40%, bend 3 ~71%, foot 100%. */
      #scf_dai_route { animation: scf-dai-route 3s linear infinite; }
      @keyframes scf-dai-route { to { stroke-dashoffset: -17; } }
      #scf_dai_groomed { animation: scf-dai-groomed 30s ease-in-out infinite; }
      @keyframes scf-dai-groomed {
        0%       { stroke-dashoffset: 100; opacity: 0; }
        3%       { stroke-dashoffset: 100; opacity: 1; }
        22%      { stroke-dashoffset: 89; }
        48%      { stroke-dashoffset: 60; }
        74%      { stroke-dashoffset: 29; }
        94%      { stroke-dashoffset: 0; opacity: 1; }
        98%, 100% { stroke-dashoffset: 0; opacity: 0; }
      }
      /* Exhaust puffs from the stack (two, half a beat apart). */
      .scf-dai-puff {
        transform-box: fill-box;
        transform-origin: center;
        animation: scf-dai-puff 1.9s ease-out infinite;
      }
      .scf-dai-puff-b { animation-delay: -0.95s; }
      @keyframes scf-dai-puff {
        0%   { transform: translate(0, 0) scale(0.4); opacity: 0.55; }
        100% { transform: translate(-5px, -9px) scale(1.9); opacity: 0; }
      }
      /* Snow thrown up by the rear tiller. */
      .scf-dai-spray {
        transform-box: fill-box;
        transform-origin: center;
        animation: scf-dai-spray 0.9s ease-out infinite;
      }
      @keyframes scf-dai-spray {
        0%   { transform: translate(4px, 3px) scale(0.35); opacity: 0; }
        35%  { opacity: 0.9; }
        100% { transform: translate(-6px, -5px) scale(1.15); opacity: 0; }
      }
      /* Rolling track treads. */
      .scf-dai-tread { animation: scf-dai-tread 0.45s linear infinite; }
      @keyframes scf-dai-tread { to { stroke-dashoffset: -3.9; } }
      /* Rotating-beacon read: the bulb blinks, the halo pulses out in sync. */
      .scf-dai-beacon { animation: scf-dai-beacon 0.9s ease-in-out infinite; }
      @keyframes scf-dai-beacon {
        0%, 45%  { opacity: 1; }
        55%, 100% { opacity: 0.2; }
      }
      .scf-dai-beacon-halo {
        transform-box: fill-box;
        transform-origin: center;
        animation: scf-dai-halo 0.9s ease-out infinite;
      }
      @keyframes scf-dai-halo {
        0%   { transform: scale(0.5); opacity: 0.5; }
        70%  { opacity: 0; }
        100% { transform: scale(1.7); opacity: 0; }
      }
      .scf-dai-sign-board {
        transform-box: fill-box;
        transform-origin: center;
        animation: scf-dai-sign 3s ease-in-out infinite;
      }
      @keyframes scf-dai-sign {
        0%, 100% { opacity: 0.9; }
        50%      { opacity: 1; }
      }
      /* Survey drone over the plateau - scans the mountain while the piste is
         built ("gathering data"). Bobs, scan cone breathes, nav LED strobes,
         rotors shimmer. */
      #scf_dai_drone { animation: scf-dai-drone 4.6s ease-in-out infinite; }
      @keyframes scf-dai-drone {
        0%, 100% { transform: translate(0, 0) rotate(-1.5deg); }
        50%      { transform: translate(4px, -5px) rotate(1.5deg); }
      }
      .scf-dai-scan {
        transform-box: fill-box;
        transform-origin: top;
        animation: scf-dai-scan 3s ease-in-out infinite;
      }
      @keyframes scf-dai-scan {
        0%, 100% { opacity: 0.35; transform: scaleY(0.9); }
        50%      { opacity: 1;    transform: scaleY(1.06); }
      }
      .scf-dai-rotor {
        transform-box: fill-box;
        transform-origin: center;
        animation: scf-dai-rotor 0.16s linear infinite alternate;
      }
      @keyframes scf-dai-rotor { to { transform: scaleX(0.8); } }
      .scf-dai-drone-led { animation: scf-dai-led 1.7s steps(1, end) infinite; }
      @keyframes scf-dai-led { 0%, 12% { opacity: 1; } 13%, 100% { opacity: 0.15; } }
      /* Groomer headlight - soft cone, breathing faintly. */
      .scf-dai-headlight { animation: scf-dai-headlight 5s ease-in-out infinite; }
      @keyframes scf-dai-headlight { 0%, 100% { opacity: 0.75; } 50% { opacity: 1; } }
      /* Marker poles along the run - flags flutter, staggered. */
      .scf-dai-flag {
        transform-box: fill-box;
        transform-origin: left center;
        animation: scf-dai-flag 1.7s ease-in-out infinite;
      }
      .scf-dai-pole:nth-child(2) .scf-dai-flag { animation-delay: -0.5s; }
      .scf-dai-pole:nth-child(3) .scf-dai-flag { animation-delay: -1.1s; }
      .scf-dai-pole:nth-child(4) .scf-dai-flag { animation-delay: -0.8s; }
      .scf-dai-pole:nth-child(5) .scf-dai-flag { animation-delay: -1.4s; }
      @keyframes scf-dai-flag {
        0%, 100% { transform: rotate(-7deg) scaleX(0.9); }
        50%      { transform: rotate(6deg)  scaleX(1); }
      }
      @media (prefers-reduced-motion: reduce) {
        #scf_dai_groomer {
          animation: none;
          transform: translate(-130px, 66px) scaleX(-1) rotate(14deg);
          opacity: 1;
        }
        /* Freeze the piste about two-thirds groomed. */
        #scf_dai_groomed { animation: none; stroke-dashoffset: 40; opacity: 1; }
        #scf_dai_route,
        #scf_dai_drone,
        .scf-dai-tread,
        .scf-dai-beacon,
        .scf-dai-beacon-halo,
        .scf-dai-scan,
        .scf-dai-rotor,
        .scf-dai-drone-led,
        .scf-dai-headlight,
        .scf-dai-flag,
        .scf-dai-sign-board { animation: none; }
        .scf-dai-puff,
        .scf-dai-spray { animation: none; opacity: 0; }
      }
      /* Its overlay label / chip on the map */
      #btn-data {
        pointer-events: none;
        cursor: default;
        opacity: 0.4;
        filter: grayscale(1);
      }
      /* Keep the chip clear of the "COMING SOON" board that sits on the plateau
         top-left: above it on desktop, and as a small icon (<=1200px) centred
         directly above the board, so it still reads as the mountain's marker.
         Measured from 620 to 1199px: centred on the board, 4 to 7px clear of
         it, clear of the drone and of every other chip. */
      @media (min-width: 1201px) {
        #btn-data { top: 65% !important; left: 8% !important; }
      }
      @media (max-width: 1200px) {
        #btn-data { top: 72.5% !important; left: 8.6% !important; }
      }
      /* The Data & AI card in the "Scenario" cluster */
      .scf-fw-card[href="/de/data-and-ai/"] {
        pointer-events: none;
        cursor: default;
        opacity: 0.5;
        filter: grayscale(1);
      }
      .scf-fw-card[href="/de/data-and-ai/"]:hover,
      .scf-fw-card[href="/de/data-and-ai/"]:focus-visible {
        transform: none;
        box-shadow: none;
      }
source_url: "https://framework.stackit.cloud/de/"
source_file: "docs/de/index.mdx"
---

<div class="scf-hero-wrapper not-content">

  {/* Hero Content Overlay (Titel, Text, Button) */}
  <div class="scf-hero-content-box">
    <h2 class="scf-hero-title">Cloud Framework</h2>
    <p class="scf-hero-desc">
      Das STACKIT Cloud Framework zeigt dir, wie du zu STACKIT wechselst und deine Anwendungen dort betreibst. Es bündelt bewährte Anleitungen, Vorlagen und Beispiele von STACKIT-Teams, Partnern und weiteren Fachleuten. Wähle ein Framework für dein Thema oder folge einem Trail Schritt für Schritt.
    </p>
    <div class="scf-hero-actions">
      <details class="scf-cta">
        <summary class="scf-cta-face">
          Jetzt starten
          <svg class="scf-cta-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M6 9l6 6 6-6"></path></svg>
        </summary>
        <div class="scf-cta-menu">
          <a class="scf-cta-option" href="/de/trails/?trail=de%2Fadvisory%2Ftrails%2Fstackit%2Fgetting-started&present=ask">
            <svg class="scf-cta-option-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><path d="M3 18l6-3 6 3 6-3V6l-6 3-6-3-6 3z"></path><path d="M9 6v9M15 9v9"></path></svg>
            <span>
              <span class="scf-cta-option-label">Framework entdecken</span>
              <span class="scf-cta-option-desc">Eine kurze Tour durch Karte, Frameworks, Assets und Trails.</span>
            </span>
            <svg class="scf-cta-option-go" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M9 6l6 6-6 6"></path></svg>
          </a>
          <a class="scf-cta-option" href="/de/trails/?trail=de%2Fadvisory%2Ftrails%2Fstackit%2Fgetting-started-contributor&present=ask">
            <svg class="scf-cta-option-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><path d="M12 3l9 5v8l-9 5-9-5V8z"></path><path d="M12 12v8M12 12L3 8M12 12l9-4"></path></svg>
            <span>
              <span class="scf-cta-option-label">Inhalte beitragen</span>
              <span class="scf-cta-option-desc">Teile eigene Anleitungen und Beispiele. Eine geführte Tour zeigt dir, wie es geht.</span>
            </span>
            <svg class="scf-cta-option-go" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M9 6l6 6-6 6"></path></svg>
          </a>
        </div>
      </details>
  </div>
  </div>

  {/* SVG & Buttons combined in isolated coordinate system */}
  {/* On phones .scf-pan turns the map into a panorama to swipe, see the phone block in the head CSS. */}
  <div class="scf-pan"><div class="scf-pan-frame"><div class="scf-pan-strip">
  <div class="scf-interactive-map">
    <div
      class="scf-hero-graphic"
      set:html={scfMountainsSvg.replace(
        "<svg ",
        '<svg style="width:100%; height:auto; display:block;" '
      )}
    />

    <a id="btn-arch" href="/de/architecture/" class="scf-btn-overlay" style="top:40%; left:63.25%;" aria-label="Architecture">
      <svg class="scf-btn-icon" viewBox="0 0 32 32" aria-hidden="true"><path d="M2 15h13V6H2v9zm2-7h9v5H4V8zm13-2v9h13V6H17zm11 7h-9V8h9v5zM2 26h13v-9H2v9zm2-7h9v5H4v-5zm13 7h13v-9H17v9zm2-7h9v5h-9v-5z"/></svg>
      <span class="scf-btn-label">Architecture</span>
      <svg class="scf-btn-arrow" viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" stroke-width="2" fill="none"/></svg>
    </a>

    <a id="btn-adopt" href="/de/adoption/" class="scf-btn-overlay" style="top:48%; left:49.2%;" aria-label="Adoption">
      <svg class="scf-btn-icon" viewBox="0 0 32 32" aria-hidden="true"><path d="M28 3c-5.599 0-10.959 2.554-15.503 7.386a31.48 31.48 0 0 0-1.412 1.611l-4.012-.802a3.012 3.012 0 0 0-2.388.541l-3.256 3.488 6.057 3.634.006-.01 2.124 2.124-2.322 2.322 1.414 1.414 2.322-2.322 2.124 2.124-.01.006 3.634 6.057 3.367-3.122.121-.135a3 3 0 0 0 .54-2.388l-.802-4.012a32.421 32.421 0 0 0 1.611-1.412C26.446 14.959 29 9.598 29 4V3h-1zM5.945 13.294a.998.998 0 0 1 .735-.139l3.044.609a32.78 32.78 0 0 0-1.902 2.963l-3.251-1.951 1.374-1.482zM18.844 25.32a.998.998 0 0 1-.138.734l-1.482 1.374-1.951-3.251a32.78 32.78 0 0 0 2.963-1.902l.608 3.045zm-4.802-2.751-1.599-1.599 3.264-3.264-1.414-1.414-3.264 3.264-1.599-1.599c1.428-2.572 7.473-12.294 17.537-12.926-.631 10.066-10.353 16.111-12.925 17.538z"/><path d="M19 16c1.654 0 3-1.346 3-3s-1.346-3-3-3-3 1.346-3 3 1.346 3 3 3zm0-4a1.001 1.001 0 1 1-1 1c0-.551.448-1 1-1z"/></svg>
      <span class="scf-btn-label">Adoption</span>
      <svg class="scf-btn-arrow" viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" stroke-width="2" fill="none"/></svg>
    </a>

    <a id="btn-adv" href="/de/advisory/" class="scf-btn-overlay" style="top:51.5%; left:33.6%;" aria-label="Advisory">
      <svg class="scf-btn-icon" viewBox="0 0 32 32" aria-hidden="true"><path d="M16 2C8.28 2 2 8.28 2 16s6.28 14 14 14 14-6.28 14-14S23.72 2 16 2zm0 26C9.383 28 4 22.617 4 16S9.383 4 16 4s12 5.383 12 12-5.383 12-12 12z"/><path d="m9.419 22.581 9.872-3.29 3.29-9.872-9.872 3.291-3.29 9.871zm4.518-7.23 2.711 2.711-4.068 1.356 1.357-4.067zm4.126 1.298-2.711-2.711 4.068-1.356-1.357 4.067z"/></svg>
      <span class="scf-btn-label">Advisory</span>
      <svg class="scf-btn-arrow" viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" stroke-width="2" fill="none"/></svg>
    </a>

    <a id="btn-mig" href="/de/migration/" class="scf-btn-overlay" style="top:52.5%; left:76%;" aria-label="Migration">
      <svg class="scf-btn-icon" viewBox="0 0 32 32" aria-hidden="true"><path d="M22.934 8.283h-.045A8.4 8.4 0 0 0 15.566 4C11.434 4 7.962 6.975 7.3 10.918 4.307 11.351 2 13.91 2 16.993c0 3.386 2.781 6.141 6.2 6.141H15V28h2v-4.866h5.934c3.896 0 7.066-3.331 7.066-7.425 0-4.164-3.104-7.426-7.066-7.426zm0 12.851H17v-5.85l2.654 2.45 1.357-1.469L16 11.639l-5.012 4.626 1.357 1.469L15 15.284v5.85H8.2c-2.316 0-4.2-1.857-4.2-4.141 0-2.283 1.884-4.14 4.2-4.14h.943l.055-.941C9.394 8.597 12.19 6 15.566 6c2.498 0 4.776 1.456 5.804 3.709l.277.606.666-.022c.069-.002.549-.011.62-.011 2.841 0 5.066 2.383 5.066 5.425.001 2.993-2.271 5.427-5.065 5.427z"/></svg>
      <span class="scf-btn-label">Migration</span>
      <svg class="scf-btn-arrow" viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" stroke-width="2" fill="none"/></svg>
    </a>

    <a id="btn-isv" href="/de/isv/" class="scf-btn-overlay" style="top:73%; left:82%;" aria-label="ISV">
      <svg class="scf-btn-icon" viewBox="0 0 32 32" aria-hidden="true"><path d="M25.698 16H28v-4c0-1.654-1.346-3-3-3h-2v-.302c0-2.506-1.871-4.567-4.26-4.692a4.457 4.457 0 0 0-3.338 1.229A4.523 4.523 0 0 0 14 8.5V9h-2c-1.654 0-3 1.346-3 3v2h-.302c-2.505 0-4.566 1.871-4.692 4.26a4.471 4.471 0 0 0 1.23 3.338A4.52 4.52 0 0 0 8.5 23H9v2c0 1.654 1.346 3 3 3h13c1.654 0 3-1.346 3-3v-4h-2.5a2.474 2.474 0 0 1-1.813-.779 2.479 2.479 0 0 1-.683-1.856C23.072 17.061 24.281 16 25.698 16zm-3.462 5.598A4.52 4.52 0 0 0 25.5 23h.5v2a1 1 0 0 1-1 1H12a1 1 0 0 1-1-1v-4H8.5a2.474 2.474 0 0 1-1.813-.779 2.479 2.479 0 0 1-.683-1.856C6.072 17.061 7.281 16 8.698 16H11v-4c0-.551.448-1 1-1h4V8.5c0-.692.276-1.336.779-1.813a2.493 2.493 0 0 1 1.856-.683C19.939 6.072 21 7.281 21 8.698V11h4c.552 0 1 .449 1 1v2h-.302c-2.505 0-4.566 1.871-4.692 4.26a4.469 4.469 0 0 0 1.23 3.338z"/></svg>
      <span class="scf-btn-label">ISV</span>
      <svg class="scf-btn-arrow" viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" stroke-width="2" fill="none"/></svg>
    </a>

    <a id="btn-data" href="/de/data-and-ai/" class="scf-btn-overlay" style="top:72.5%; left:11.6%;" aria-label="Data & AI (noch nicht verfügbar)" aria-disabled="true" tabindex="-1">
      <svg class="scf-btn-icon" viewBox="0 0 32 32" aria-hidden="true"><path d="M26.969 6C26.647 3.257 21.141 2 16 2 10.702 2 5 3.33 5 6.25v19.5C5 28.67 10.702 30 16 30s11-1.33 11-4.25V6h-.031zM16 4c5.846 0 9 1.597 9 2.25S21.846 8.5 16 8.5 7 6.903 7 6.25 10.154 4 16 4zm0 24c-5.846 0-9-1.597-9-2.25v-3.921c2.128 1.134 5.643 1.671 9 1.671s6.872-.536 9-1.671v3.921c0 .653-3.154 2.25-9 2.25zm0-6.5c-5.846 0-9-1.597-9-2.25v-3.921C9.128 16.464 12.643 17 16 17s6.872-.536 9-1.671v3.921c0 .653-3.154 2.25-9 2.25zm0-6.5c-5.846 0-9-1.597-9-2.25V8.829c2.128 1.134 5.643 1.671 9 1.671s6.872-.536 9-1.671v3.921c0 .653-3.154 2.25-9 2.25z"/></svg>
      <span class="scf-btn-label">Data & AI</span>
      <svg class="scf-btn-arrow" viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" stroke-width="2" fill="none"/></svg>
    </a>

    <a id="btn-trail" href="/de/trails/" class="scf-btn-overlay" style="top:80.0%; left:49.5%;" aria-label="Trails">
      <svg class="scf-btn-icon" viewBox="0 0 32 32" aria-hidden="true"><path d="M29.081 13.783 18.218 2.918a3.142 3.142 0 0 0-4.436 0L2.919 13.782C2.326 14.375 2 15.162 2 16s.326 1.626.919 2.218l10.863 10.863c.593.593 1.38.919 2.218.919s1.625-.326 2.218-.919l10.863-10.863c.593-.592.919-1.38.919-2.218s-.326-1.625-.919-2.217zm-1.414 3.021L16.804 27.667a1.138 1.138 0 0 1-1.607 0L4.333 16.803C4.118 16.589 4 16.303 4 16s.118-.588.333-.803L15.196 4.333a1.138 1.138 0 0 1 1.607 0l10.863 10.865a1.13 1.13 0 0 1 .001 1.606z"/><path d="M17.293 11.707 19.586 14H10v6h2v-4h7.586l-2.293 2.293 1.414 1.414L23.414 15l-4.707-4.707z"/></svg>
      <span class="scf-btn-label">Trails</span>
      <svg class="scf-btn-arrow" viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" stroke-width="2" fill="none"/></svg>
    </a>

    <a id="btn-assets" href="/de/assets/" class="scf-btn-overlay" style="top:75.25%; left:59.75%;" aria-label="Assets">
      <svg class="scf-btn-icon" viewBox="0 0 32 32" aria-hidden="true"><path d="M25 4H7C5.35 4 4 5.35 4 7v18c0 1.65 1.35 3 3 3h18c1.65 0 3-1.35 3-3V7c0-1.65-1.35-3-3-3Zm1 21c0 .55-.45 1-1 1H7c-.55 0-1-.45-1-1V7c0-.55.45-1 1-1h18c.55 0 1 .45 1 1v18Z"/></svg>
      <span class="scf-btn-label">Assets</span>
      <svg class="scf-btn-arrow" viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" stroke-width="2" fill="none"/></svg>
    </a>

    <a id="btn-contributors" href="/de/contributors/" class="scf-btn-overlay" style="top:77%; left:28.5%;" aria-label="Contributors">
      <svg class="scf-btn-icon" viewBox="0 0 32 32" aria-hidden="true"><path d="M30 18.877A5.884 5.884 0 0 0 24.123 13H20c-2.269 0-4.255 1.419-5.081 3.447A6.382 6.382 0 0 0 12.581 16H8c-3.309 0-6 2.691-6 6v6h17v-4h11v-5.123zM17 26H4v-4c0-2.206 1.794-4 4-4h4.581A4.424 4.424 0 0 1 17 22.419V26zm11-4h-9.021a6.406 6.406 0 0 0-2.317-4.532A3.515 3.515 0 0 1 20 15h4.123A3.881 3.881 0 0 1 28 18.877V22z"/><path d="M10.5 15a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9zm0-7c1.378 0 2.5 1.121 2.5 2.5 0 1.378-1.122 2.5-2.5 2.5S8 11.878 8 10.5C8 9.121 9.122 8 10.5 8zm11.772 4a4 4 0 1 0 0-8 4 4 0 0 0 0 8zm0-6c1.103 0 2 .897 2 2s-.897 2-2 2-2-.897-2-2 .898-2 2-2z"/></svg>
      <span class="scf-btn-label">Contributors</span>
      <svg class="scf-btn-arrow" viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" stroke-width="2" fill="none"/></svg>
    </a>

    <a id="btn-portal" href="https://portal.stackit.cloud/" target="_blank" rel="noopener noreferrer" class="scf-btn-overlay" style="top:30.5%; left:83.1%;" aria-label="Portal">
      <svg class="scf-btn-icon" viewBox="0 0 41.536063 41.536063" aria-hidden="true"><path d="M13.9510149,10.4421038h20.8374634l-1.1608887,5.4412842h-14.5545654l-1.3522339,6.3352661h-6.2828369l2.5130615-11.7765503ZM22.5114397,25.652614H7.9081072l-1.1605225,5.4413452h20.8855591l2.5210571-11.8130493h-6.2828979l-1.3598633,6.3717041Z" fill="currentColor"/></svg>
      <span class="scf-btn-label">Portal</span>
      <svg class="scf-btn-arrow" viewBox="0 0 24 24"><path d="M7 17L17 7M17 7H9M17 7v8" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
    </a>

    <a id="btn-market" href="https://marketplace.stackit.cloud/" target="_blank" rel="noopener noreferrer" class="scf-btn-overlay" style="top:86.5%; left:88.2%;" aria-label="Marketplace">
      <svg class="scf-btn-icon" viewBox="0 0 32 32" aria-hidden="true"><path d="M27 8.669V7c0-1.654-1.346-3-3-3H8C6.346 4 5 5.346 5 7v1.669l-2.692 3.615v.332A3.538 3.538 0 0 0 5 16.041V28h22V16.04a3.537 3.537 0 0 0 2.692-3.425v-.332L27 8.669zM7 7c0-.551.448-1 1-1h16c.552 0 1 .449 1 1v1H7V7zm12 19v-6h2v6h-2zm4 0v-8h-6v8H7V15.944a3.528 3.528 0 0 0 1.385-.874c.644.665 1.542 1.083 2.538 1.083s1.895-.418 2.539-1.083c.644.665 1.542 1.083 2.538 1.083s1.895-.418 2.538-1.083c.644.665 1.542 1.083 2.539 1.083s1.895-.418 2.538-1.083c.381.394.856.69 1.385.874V26h-2zm3.154-11.846a1.54 1.54 0 0 1-1.539-1.539h-2a1.54 1.54 0 0 1-1.538 1.539 1.54 1.54 0 0 1-1.539-1.539h-2c0 .848-.69 1.539-1.538 1.539s-1.538-.69-1.538-1.539h-2a1.54 1.54 0 0 1-1.539 1.539 1.54 1.54 0 0 1-1.538-1.539h-2a1.54 1.54 0 0 1-1.539 1.539 1.542 1.542 0 0 1-1.51-1.245L6.502 10h18.996l2.166 2.909a1.542 1.542 0 0 1-1.51 1.245z"/><path d="M9 24h6v-6H9v6zm2-4h2v2h-2v-2z"/></svg>
      <span class="scf-btn-label">Marketplace</span>
      <svg class="scf-btn-arrow" viewBox="0 0 24 24"><path d="M7 17L17 7M17 7H9M17 7v8" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
    </a>
  </div>
  </div></div></div>

</div>

<div class="scf-fw-cards not-content">
  <h2 class="scf-fw-cluster" id="foundation">Basis</h2>
  <ul class="scf-fw-row">
    <li>
      <a class="scf-fw-card" href="/de/advisory/">
        <span class="scf-fw-art" set:html={cardAdvisory} />
        <span class="scf-fw-text"><span class="scf-fw-title">Advisory Framework</span><span class="scf-fw-sep">. </span><span class="scf-fw-desc">Für die Führungsebene: aus der Cloud-Vision wird ein freigegebener Plan mit klaren Prioritäten, Kosten und Regeln.</span></span>
      </a>
    </li>
    <li>
      <a class="scf-fw-card" href="/de/adoption/">
        <span class="scf-fw-art" set:html={cardAdoption} />
        <span class="scf-fw-text"><span class="scf-fw-title">Adoption Framework</span><span class="scf-fw-sep">. </span><span class="scf-fw-desc">Mach die Cloud zum Alltag in der ganzen Organisation: Betriebsmodell, Prozesse, Kompetenzen und sichere Standardumgebungen.</span></span>
      </a>
    </li>
    <li>
      <a class="scf-fw-card" href="/de/architecture/">
        <span class="scf-fw-art" set:html={cardArchitecture} />
        <span class="scf-fw-text"><span class="scf-fw-title">Architecture Framework</span><span class="scf-fw-sep">. </span><span class="scf-fw-desc">Prüfe dein System an sieben Säulen wie Zuverlässigkeit, Sicherheit und Souveränität. Sieh, was jede Entscheidung kostet.</span></span>
      </a>
    </li>
  </ul>
  <h2 class="scf-fw-cluster">Szenario</h2>
  <ul class="scf-fw-row">
    <li>
      <a class="scf-fw-card" href="/de/data-and-ai/" aria-disabled="true" tabindex="-1">
        <span class="scf-fw-art" set:html={cardDataAndAi} />
        <span class="scf-fw-text"><span class="scf-fw-title">Data & AI Framework</span><span class="scf-fw-sep">. </span><span class="scf-fw-desc">Von Rohdaten zu verlässlicher KI im Einsatz: eine souveräne Datenplattform, die richtigen Anwendungsfälle und ein stabiler Betrieb.</span></span>
      </a>
    </li>
    <li>
      <a class="scf-fw-card" href="/de/migration/">
        <span class="scf-fw-art" set:html={cardMigration} />
        <span class="scf-fw-text"><span class="scf-fw-title">Migration Framework</span><span class="scf-fw-sep">. </span><span class="scf-fw-desc">Zieh aus deinem Rechenzentrum zu STACKIT um, Schritt für Schritt von der ersten Bewertung bis zum stabilen Betrieb.</span></span>
      </a>
    </li>
    <li>
      <a class="scf-fw-card" href="/de/isv/">
        <span class="scf-fw-art" set:html={cardIsv} />
        <span class="scf-fw-text"><span class="scf-fw-title">ISV Framework</span><span class="scf-fw-sep">. </span><span class="scf-fw-desc">Für Softwareanbieter: vom ersten Kontakt bis zum Eintrag im STACKIT Marketplace, in zehn klaren Phasen.</span></span>
      </a>
    </li>
  </ul>
  <h2 class="scf-fw-cluster">Entdecken</h2>
  <ul class="scf-fw-row">
    <li>
      <a class="scf-fw-card" href="/de/contributors/">
        <span class="scf-fw-art" set:html={cardContributors} />
        <span class="scf-fw-text"><span class="scf-fw-title">Contributors</span><span class="scf-fw-sep">. </span><span class="scf-fw-desc">STACKIT-Teams, Partner und weitere Fachleute teilen hier ihr Wissen. Mitmachen kann jede Person mit STACKIT-Konto. Jeder Beitrag wird vor der Veröffentlichung geprüft.</span></span>
      </a>
    </li>
    <li>
      <a class="scf-fw-card" href="/de/assets/">
        <span class="scf-fw-art" set:html={cardAssets} />
        <span class="scf-fw-text"><span class="scf-fw-title">Assets</span><span class="scf-fw-sep">. </span><span class="scf-fw-desc">Alle Anleitungen, Vorlagen und Tools an einem Ort. Suche und filtere über alle Frameworks.</span></span>
      </a>
    </li>
    <li>
      <a class="scf-fw-card" href="/de/trails/">
        <span class="scf-fw-art" set:html={cardTrails} />
        <span class="scf-fw-text"><span class="scf-fw-title">Trails</span><span class="scf-fw-sep">. </span><span class="scf-fw-desc">Schritt-für-Schritt-Wege, die Assets und Inhalte der Frameworks in eine klare Reihenfolge bringen: vom ersten Plan bis zum Gipfel.</span></span>
      </a>
    </li>
  </ul>
</div>

<ScfFrontpageMagnetHover />
