/*
 * RR42 — Systemische Intelligenz & KI-Transformation
 *
 * Design adapted from Fabrizio Calderan's CSS-only
 * scroll-animation demo (MIT, codepen.io/fcalderan/pen/PorLqrE):
 * https://www.linkedin.com/in/fabriziocalderan/
 *
 * Scroll effects are pure CSS (scroll-driven animations),
 * no JavaScript required.
 *
 *
 * TWO LAYOUT MODES
 * ----------------
 * base      — a plain, stacked document. What a browser without
 *             CSS scroll-driven animations gets. Lives inside
 *             `@supports not (animation-timeline: view())`, so it
 *             can never leak into the mode below.
 *
 * enhanced  — the sticky full-viewport scroll choreography
 *             (overlapping heroes, blob reveal, horizontal cards).
 *             Runs at EVERY width, phones included; only the
 *             headline column (--hero-col) and card padding change
 *             at the 48rem breakpoint.
 *
 * Two things keep the choreography portable rather than
 * Chrome-only, both easy to reintroduce by accident:
 *
 *   - animation-range uses plain scroll offsets. `entry`/`exit`
 *     are VIEW-timeline range names and are not valid on a named
 *     SCROLL timeline; Chrome reads them as the offsets anyway,
 *     other engines need not.
 *   - the blob is scaled on the <path>, not the <clipPath>, so
 *     transform-box: fill-box has a real box to resolve against.
 */


*,*::before,*::after { box-sizing: border-box; }

:root {
   --items: min(30rem, 80vw);
   /* width of the headline column the card track starts after.
    * One card per screen on a phone, the original two-up framing
    * from ~48rem. Shared by the grid and the scroll keyframe so the
    * track always comes to rest in the right place. */
   --hero-col: 80vw;
   --color-base: #181213;
   --gradient: linear-gradient(125deg,
      rgb(131 163 172), rgb(223 151 132));
   scroll-timeline: --page block;

   /* The card track travels sideways well past the viewport, so the
    * horizontal overflow has to be clipped - but it must be clipped
    * HERE, on the root, not on <body>.
    *
    * Overflow set on <body> propagates to the viewport and leaves
    * <body> itself a scroll container that never actually scrolls.
    * Every view() timeline then resolves to that dead scrollport and
    * goes inactive, silently killing the section reveals. Setting it
    * on the root clips the same way while the viewport stays the
    * live scroller that the timelines resolve against. */
   overflow-x: hidden;

   /* Keep the choreography stable under touch.
    *
    * `pan-y pinch-zoom` allows exactly two gestures: scrolling down
    * the page, and deliberate pinch-zoom. Sideways panning is gone,
    * so the card track can no longer be dragged off-centre, and so
    * is double-tap-to-zoom, the usual way a phone zooms by accident
    * mid-scroll and strands the sticky panes at the wrong size.
    *
    * Pinch-zoom is kept on purpose: iOS ignores user-scalable=no by
    * design, and removing zoom would fail WCAG 1.4.4.
    *
    * `overscroll-behavior-y: none` stops the rubber-band bounce from
    * exposing white above the pinned hero. */
   touch-action: pan-y pinch-zoom;
   overscroll-behavior-y: none;

   @media (prefers-reduced-motion: no-preference) {
      scroll-behavior: smooth;
   }

   /* the original two-up framing from ~48rem up */
   @media (width >= 48rem) {
      --hero-col: 55vw;
   }
}

body {
   margin: 0;
   background: #fff;
   font: 300 1rem/1.33 "Helvetica Neue", Helvetica, Arial, sans-serif;
   color: var(--color-base);
   display: grid;
}

img {
   max-inline-size: 100%;
   block-size: auto;
}

hr[id] {
   border: 0;
   margin: 0;
}


/* animations */

/* The original 1.75 is enough to cover the viewport once the blob
 * actually grows from its own centre - see `clipPath path` below.
 * Scaling happens in the clip path's normalised 0-1 space, so this
 * single value holds at every size and aspect ratio. */
@keyframes clip {
   to { transform: scale(var(--blob-scale, 1.75)); }
}
/* Where the card track comes to rest.
 *
 * The track starts after the page margin, the headline column and
 * the grid gap (10vw + --hero-col + 10vw) and runs for three cards.
 * To leave the last card inset by the same 10vw margin as the rest
 * of the page, it has to travel until its right edge sits at 90vw:
 *
 *    translate = 90vw - (20vw + --hero-col + 3 * --items)
 *              = 70vw - --hero-col - 3 * --items
 *
 * The original `-3 * --items + 15vw` is exactly this for the desktop
 * column (70vw - 55vw = 15vw), which is why it looked right there
 * and pushed the third card ~58px off-stage on a phone. */
@keyframes scroll {
   to {
      translate: calc(70vw - var(--hero-col) - (var(--items) * 3)) 0;
   }
}
@keyframes moveup {
    to { transform: translateY(var(--moveup)); }
}
/* transform-only entrance: content must never be opacity-0 at rest,
 * or fast/momentum scrolling outruns the scroll-driven animation and
 * whole sections render blank until it catches up */
@keyframes reveal {
    from { transform: translateY(4rem); }
    to   { transform: translateY(0); }
}


body > svg {
   block-size: 0;
   inline-size: 0;

   /* Scale the PATH, not the <clipPath>.
    *
    * A <clipPath> is not a rendered box, so transform-box: fill-box
    * has nothing to resolve against and `center` collapses onto the
    * 0x0 parent <svg> - the blob then grows away toward the
    * bottom-right and never covers the top-left of the screen.
    * (The original worked around the same problem by setting the
    * origin to `50vw * devicePixelRatio`, guessing density from a
    * list of dppx values.)
    *
    * The <path> does have a bounding box, so fill-box gives a true
    * centre and the reveal grows evenly in all directions. */
   clipPath path {
      transform-box: fill-box;
      transform-origin: center;

      transform: scale(0);
      animation: linear clip 1 forwards;
      animation-timeline: --page;
      /* plain scroll offsets. `entry`/`exit` are VIEW-timeline range
       * names and are not valid on a named SCROLL timeline; Chrome
       * quietly reads them as these very offsets, other engines need
       * not. Verified pixel-identical to the original in Chrome. */
      animation-range: 10dvb 100dvb;
   }
}



/* header */

header {
   position: fixed;
   z-index: 1;
   inset: 0 0 auto 0;
   background: #fff;

   > div {
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 1rem 2rem;
      margin: 0 10vw;
      border-bottom: 1px solid;
      padding-block: 1.5rem;
   }

   h1 { margin: 0; }

   img {
      display: block;
      inline-size: 9rem;
   }

   ul {
      display: flex;
      gap: 2.5rem;
      margin: 0;
      padding: 0;
      list-style: none;

      @media (width < 48rem) {
         display: none;
      }

      :any-link {
         font-weight: 300;
         font-size: 1.25rem;
         color: inherit;
         text-decoration: none;
      }
   }

   /* CSS-only burger menu for small screens */
   .menu {
      display: none;
      position: relative;

      @media (width < 48rem) {
         display: block;
      }

      summary {
         list-style: none;
         cursor: pointer;
         display: grid;
         gap: 5px;
         padding: .5rem;

         &::-webkit-details-marker { display: none; }

         span {
            display: block;
            inline-size: 1.6rem;
            block-size: 2px;
            background: currentColor;
         }
      }

      ul {
         display: grid;
         position: absolute;
         top: calc(100% + 1rem);
         right: 0;
         gap: 1.25rem;
         min-inline-size: 14rem;
         padding: 1.5rem;
         background: #fff;
         border: 1px solid;
      }
   }
}


/* general sections style */
section {
   padding-block: 7dvb;

   h2 {
      font-size: clamp(3rem, 6vw, 6rem);
      line-height: 1;
      letter-spacing: -.15rem;
      font-weight: 300;
      text-shadow: 0 0 1px currentColor;
   }

   h3 {
      margin-block: 2rem;
      font-size: clamp(1.6rem, 4.5vw, 4.5rem);
      font-weight: 400;

      small {
         display: block;
         font-size: clamp(.85rem, 1.2vw, 1.05rem);
         font-weight: 300;
         letter-spacing: .25em;
         text-transform: uppercase;
         opacity: .85;
         margin-block-end: .9rem;
      }
   }

   p {
      font-size: 1.1rem;
      line-height: 1.5;
   }
}


/* general hero style */

.hero {
   min-block-size: 100dvb;


   @supports (animation-timeline: view()) {
      block-size: 100dvb;
      inline-size: 100vw;
      position: sticky;
      top: 0;
      grid-area: 1 / 1;

      /* both heroes travel up and off, so the first hero's headline
       * is gone by the time the article content arrives */
      --moveup: -100dvb;
      will-change: transform;
      animation: linear moveup 1 forwards;
      animation-timeline: --page;
      animation-range: 200dvb 300dvb;

      /* give enough room to run scroll-animations
       * so the main element is not hidden
       */
      ~ main {
         margin-block-start: 200dvb;
         min-block-size: 100dvb;
      }
   }


   h2 {
      font-size: clamp(2.5rem, 8vw, 8rem);
      font-weight: 320;
      text-shadow: none;
      max-inline-size: 14ch;
   }


   > div  {
      block-size: 100%;
      display: grid;
      align-items: center;
      margin-inline: 10vw;
   }


   :any-link {
      --hover: 0;
      background-color: rgba(0, 72, 90, var(--hover));
      transition: all .33s;
      &:hover {
         color: #fff;
         border-color: transparent;
         --hover: 1;
      }
   }


   /* the bouncing scroll-down arrow only makes sense while the
    * sticky choreography is running */
   [href^="#"] {

      display: none;
      position: absolute;
      border-radius: 50%;
      border: 0;
      bottom: 3rem;
      left: calc(50% - 2rem);
      block-size: 4rem;
      padding: .75rem;
      aspect-ratio: 1;
      color: inherit;

      @media (prefers-reduced-motion: no-preference) {
         --moveup: -1rem;
         animation: moveup 1s
            cubic-bezier(.5,0,1,.5) infinite alternate;

         &:hover {
            animation-play-state: paused;
         }
      }

      @supports (animation-timeline: view()) {
         display: block;
      }

   }


   svg {
      transform: rotateZ(.25turn);
      inline-size: 100%;
      aspect-ratio: 1;
      fill: currentColor;
   }


   .hero__content {
      display: flex;
      align-items: start;
      flex-direction: column;
      gap: 2rem;
   }

   :where(:any-link) {
      --hover: 0;
      color: inherit;
      text-decoration: none;
      border-radius: 1.5rem;
      padding: .75rem 2rem;
      font-size: 92%;
      letter-spacing: 0;
      border: 1px solid currentColor;
   }
}



/* 2nd hero hidden */
#focus-areas {

   color: #fff;
   background: var(--gradient);

   @supports (animation-timeline: view()) {
      clip-path: url("#blob");
   }

   > div {
      gap: 10vw;

      @supports (animation-timeline: view()) {
         grid-template-columns: var(--hero-col) auto;

         translate: 0 0;
         will-change: translate;
         animation: ease-out scroll 1 forwards;
         animation-timeline: --page;
         animation-range: 100dvb 200dvb;
      }
   }

   ul {
      display: flex;
      margin: 0;
      padding: 0;

      @supports not (animation-timeline: view()) {
         block-size: auto;
         border-inline-end: 1px #fff solid;

         /* stack for the whole non-enhanced range, so cards are never
          * squeezed three-abreast on a tablet in portrait */
         @media (width < 48rem) {
            flex-direction: column;
            border-inline: 0;
         }
      }

      @supports (animation-timeline: view()) {
         block-size: calc(100dvb - 10rem);
      }
   }

   li {

      flex: 1;
      display: flex;
      align-items: center;
      inline-size: auto;

      /* long German/English titles must stay inside the card
       * (the original demo only had one-word titles) */
      h3 {
         font-size: clamp(1.5rem, 2.3vw, 2.5rem);
         overflow-wrap: anywhere;
      }

      span:has(img), img {
         max-block-size: 30dvmin;
      }

      @media (width < 48rem) {
         span:has(img), img { display: none; }
      }

      /* --- stacked fallback (no scroll-driven animations) ---------
       * Kept strictly inside `@supports not`: when the choreography
       * IS running these rules must not leak into it, or the
       * hairlines meant to separate stacked cards draw a stray box
       * around the gliding card. */
      @supports not (animation-timeline: view()) {
         padding-inline: 2.5rem;
         border-inline-start: 1px #fff solid;
         h3, p { text-align: center; }

         /* the nested <section> otherwise inherits the generic 7dvb
          * block padding, ~120px of dead space per card on a phone */
         @media (width < 40rem) {
            flex: 0 0 auto;
            padding-inline: 0;
            border-inline: 0;

            > section { padding-block: 0; }

            h3 { margin-block: 1rem .75rem; }

            &:not(:last-child) {
               padding-block-end: 2.5rem;
               border-block-end: 1px #fff solid;
            }

            &:not(:first-child) {
               padding-block-start: 2.5rem;
            }
         }
      }

      /* --- gliding card track (choreography running) -------------- */
      @supports (animation-timeline: view()) {
         inline-size: var(--items);
         padding-inline: 1.75rem;
         border-inline: 0;
         border-inline-start: 1px #fff solid;
         h3, p { text-align: left; }

         > section { padding-block: 0; }

         @media (width >= 48rem) {
            padding-inline: 2.5rem;
         }
      }
   }
}


main {

   section {
      padding-block: 5dvb;

      /* rise-on-entry, all widths. Safe on phones because the
       * keyframes are transform-only (see @keyframes reveal): even
       * if the timeline stalls, the text is still there. */
      @media (prefers-reduced-motion: no-preference) {
         will-change: transform;
         animation: ease-out reveal 1 both;
         animation-timeline: view();
         animation-range: cover 0% cover 25%;
      }

      > div {
         padding-inline: 10vw;
      }
   }

   #philosophy {

      p {
         max-inline-size: 62ch;
         margin-block: 1.75rem;
      }

      .lede {
         margin-block-start: 2.5rem;
         font-size: clamp(1.3rem, 1.9vw, 1.65rem);
         line-height: 1.45;
      }

      .claim {
         font-size: clamp(1.2rem, 1.7vw, 1.5rem);
         font-weight: 400;
         border-inline-start: 3px solid rgb(223 151 132);
         padding-inline-start: 1.5rem;
      }
   }

   .team {
      list-style: none;
      margin: 5dvb 0 0;
      padding: 0;
      display: grid;
      gap: 3rem 5rem;
      grid-template-columns: repeat(auto-fit, minmax(min(26rem, 100%), 1fr));

      h3 {
         margin-block: 0 .25rem;
         font-size: clamp(1.6rem, 2.6vw, 2.4rem);
      }

      .role {
         color: #7d868d;
         margin-block: 0 1.25rem;
      }

      p { max-inline-size: 55ch; }

      ul {
         margin: 1.25rem 0 0;
         padding-inline-start: 1.2rem;

         li {
            margin-block: .5rem;
            font-size: 1.05rem;
            line-height: 1.5;
         }
      }
   }

   .news {
      margin-block-start: 5dvb;
      margin-block-end: 0;
      padding: 0;
      list-style: none;

      li {
         padding-block: 2dvb;
         border-bottom: 1px solid;
         container: article / inline-size;
         --hover: 0;
         &:hover {
            --hover: 1;
         }
      }

      article {
         position: relative;
         display: grid;
         grid-template-columns: minmax(15vw, 22rem) auto;
         @container article (width <= 48rem) {
            grid-template-columns: 1fr;
         }

         align-items: center;
         gap: 2rem;
         opacity: calc(0.7 + (var(--hover) * 0.3));
         transition: opacity .33s;

      }

      div {
         aspect-ratio: 1.8 / 1;
         overflow: hidden;
         border-radius: 1rem;
         inline-size: 100%;

         @container article (width <= 48rem) {
            display: none;
         }

         img {
            object-fit: cover;
            block-size: 100%;
            inline-size: 100%;
         }
      }

      :any-link {
         display: grid;
         grid-template: auto auto / 1fr minmax(2.5rem, 6cqi);
         gap: 1rem min(5vw, 5rem);
         justify-content: space-between;
         align-items: center;
         color: inherit;
         text-decoration: none;

         .meta {
            grid-area: 1 / 1 / 2 / 3;
            font-size: 1rem;
            line-height: 1.33;
            color: #847c79;
            flex: 1 0 100%;

         }

         .title {
            grid-area: 2 / 1 / 3 / 2;
            flex-wrap: nowrap;
            font-size: clamp(1.35rem, 2.6vw, 2.1rem);
            line-height: 1.33;
         }

         &:hover .title {
            text-decoration: underline;
         }

         &::before {
            content: "";
            position: absolute;
            inset: 0;
         }
      }

      svg {
         grid-area: 1 / 2 / 3 / 3;
         aspect-ratio: 1;
         padding: .75rem;
         inline-size: 100%;
         border-radius: 50%;
         border: 2px solid;
         clip-path: polygon(18% 0, 100% 0, 100% 100%, 18% 100%);
         color: #645c59;
         fill: currentColor;
         transition: transform .33s;
         transform: rotateZ(calc(var(--hover) * .25turn));
      }
   }
}


/* footer */

footer {
   background: #fff;

   > div {
      margin-inline: 10vw;
      border-top: 1px solid;
      padding-block: 2.5rem;
      display: flex;
      flex-wrap: wrap;
      gap: 1rem 2rem;
      justify-content: space-between;
      align-items: center;
      font-size: .95rem;
   }

   p { margin: 0; }

   ul {
      display: flex;
      gap: 2rem;
      margin: 0;
      padding: 0;
      list-style: none;
   }

   :any-link {
      color: inherit;
      text-decoration: none;

      &:hover {
         text-decoration: underline;
      }
   }
}



/* show header on scrollup and hide on scrolldown
 * original demo: https://codepen.io/fcalderan/pen/LYKwyyd
 */

@property --scroll-direction {
	syntax: "<number>";
	inherits: true;
	initial-value: 0;
}

@property --scroll {
	syntax: "<number>";
	inherits: true;
	initial-value: 0;
}

@property --scroll-delayed {
	syntax: "<number>";
	inherits: true;
	initial-value: 0;
}


@keyframes adjust-pos {
	to {
		--scroll: 10000;
		--scroll-delayed: 10000;
	}
}

:root {
	animation: adjust-pos linear both;
	animation-timeline: scroll(root);

}

body {
   transition: --scroll-delayed .55s linear;
   --scroll-velocity: calc(var(--scroll) - var(--scroll-delayed));
   --scroll-speed: max(var(--scroll-velocity), -1 * var(--scroll-velocity));
   --scroll-direction: calc(var(--scroll-velocity) / var(--scroll-speed));
}

header {
   background: #fff9;
   backdrop-filter: blur(8px);

   /* Auto-hide is desktop-only. On phones the header stays put:
    * the scroll-direction value is derived from a scroll timeline,
    * and a stuck value would park the header off-screen for good. */
   @media (width >= 48rem) {
      transition: transform .5s 0s;
      transform: translateY(var(--translate));

      @container style(--scroll-direction: 0) {
         transition-delay: calc(infinity * 1s);
      }

      @container style(--scroll-direction: -1) {
         --translate: 0;
      }

      @container style(--scroll-direction: 1) {
         --translate: calc(-100% - 2px);
      }
   }
}



/* keyboard focus */
:where(a, summary):focus-visible {
   outline: 2px solid rgb(0 72 90);
   outline-offset: 3px;
}

#focus-areas :where(a, summary):focus-visible {
   outline-color: #fff;
}


/* product popups (CSS-only, opened via :target) */

.modal {
   display: none;
   position: fixed;
   inset: 0;
   z-index: 20;
   padding: 1.5rem;

   &:target {
      display: grid;
      place-items: center;
   }
}

.modal__backdrop {
   position: absolute;
   inset: 0;
   background: rgba(24, 18, 19, .6);
}

.modal__panel {
   position: relative;
   z-index: 1;
   background: #fff;
   color: var(--color-base);
   inline-size: min(30rem, 100%);
   max-block-size: min(32rem, 85dvb);
   border-radius: 1.25rem;
   padding: 2.5rem;
   box-shadow: 0 1.5rem 4rem rgba(0, 0, 0, .35);

   /* Only the description scrolls. If the whole panel scrolled, a
    * long entry (compliify) would push "Learn more" below the fold
    * on a phone and hide the call to action. */
   display: flex;
   flex-direction: column;
   overflow: hidden;

   h3 {
      margin: 0 0 1rem;
      font-size: clamp(1.6rem, 3vw, 2.1rem);
      font-weight: 400;
   }

   p {
      font-size: 1.02rem;
      line-height: 1.55;
      margin-block: 0 1.5rem;
      overflow-y: auto;
      min-block-size: 0;   /* let the flex child actually shrink */
      overscroll-behavior: contain;
   }

   @media (prefers-reduced-motion: no-preference) {
      transition: opacity .2s ease, transform .2s ease;
   }
}

@media (prefers-reduced-motion: no-preference) {
   @starting-style {
      .modal:target .modal__panel {
         opacity: 0;
         transform: translateY(.75rem) scale(.97);
      }
   }
}

.modal__meta {
   display: block;
   font-size: .85rem;
   letter-spacing: .08em;
   text-transform: uppercase;
   color: #847c79;
   margin-block-end: .5rem;
}

.modal__close {
   position: absolute;
   top: 1rem;
   right: 1rem;
   inline-size: 2.25rem;
   block-size: 2.25rem;
   display: grid;
   place-items: center;
   border-radius: 50%;
   color: inherit;
   text-decoration: none;
   font-size: 1.5rem;
   line-height: 1;

   &:hover { background: rgba(24, 18, 19, .08); }
}

/* Pinned action row: stays put while the description scrolls above it,
 * so the buttons are reachable however long the copy gets. */
.modal__actions {
   flex: none;
   display: flex;
   flex-wrap: wrap;
   align-items: center;
   gap: .75rem 1.5rem;
}

/* outbound link to the product's own site */
.modal__visit {
   color: inherit;
   text-decoration: none;
   border: 1px solid currentColor;
   border-radius: 1.5rem;
   padding: .5rem 1.15rem;
   font-size: .95rem;
   white-space: nowrap;
   transition: background-color .33s, color .33s, border-color .33s;

   &:hover {
      background: rgb(0 72 90);
      border-color: transparent;
      color: #fff;
   }
}

.modal__link {
   flex: none;
   align-self: center;
   display: inline-flex;
   color: inherit;
   text-decoration: none;
   border-bottom: 1px solid currentColor;
   padding-block-end: .15rem;

   &:hover { opacity: .7; }
}


/* fix images */
span:has(> img) {
   aspect-ratio: 86 / 100;
   display: block;
   overflow: hidden;

   img {
      inline-size: 115%;
      max-inline-size: 115%;
   }
}
