:root{
  /* ---------- design tokens ---------- */
  /* spacing scale, 4px base */
  --s-1:4px;--s-2:8px;--s-3:12px;--s-4:16px;--s-5:24px;--s-6:32px;--s-7:48px;--s-8:64px;
  /* vertical rhythm */
  --section-y:clamp(56px,9vw,88px);   /* padding of every page section */
  --stack-title:var(--s-3);           /* eyebrow -> heading */
  --stack-lede:var(--s-4);            /* heading -> intro paragraph */
  --stack-block:clamp(32px,3.4vw,44px);   /* section head -> its own content */
  --stack-group:clamp(48px,6vw,72px);     /* one content group -> the next */
  /* the same four relationships INSIDE a card, tile, panel or form. Named after
     the relationship, not the size, so the same thing is spaced the same way
     wherever it appears — before these, a label sat 12px, 4px or 3px above what
     it labelled depending on which component it happened to be in. */
  --stack-tight:var(--s-1);           /* a heading and its own next line */
  --stack-label:var(--s-2);           /* a label and the thing it labels */
  --stack-item:var(--s-3);            /* item -> item inside a list */
  --stack-sub:var(--s-5);             /* block -> block inside a component */
  --gap-chip:var(--s-2);              /* chips in a wrapping row */
  /* grids & cards */
  --gutter:clamp(20px,3.6vw,32px);        /* page gutter, left and right */
  --grid-gap:clamp(16px,2.5vw,24px);
  --card-pad:clamp(20px,3vw,28px);
  /* type */
  --lh-tight:1.12;--lh-body:1.6;
  --fs-display:clamp(2rem,4vw,3.2rem);     /* page hero h1 */
  --fs-h2:clamp(1.8rem,3.2vw,2.5rem);        /* section heading */
  --fs-h3:1.3rem;
  --fs-lede:clamp(1.05rem,1.5vw,1.25rem);
  /* The same idea as the spacing tokens, one layer up: named after the role the
     text plays, not its size. The audit that produced them found 28 fixed sizes
     doing about six jobs — seven different sizes for "uppercase label", eight
     for "body text inside a card". */
  --fs-micro:.72rem;                  /* uppercase label inside a component */
  --fs-eyebrow:.85rem;                /* uppercase label above a section head */
  --fs-fine:.8rem;                    /* captions, notes, fine print, chips */
  --fs-small:.88rem;                  /* body text inside a card, tile, panel */
  --fs-ui:.95rem;                     /* controls: buttons, nav, inputs */
  --fs-body:1rem;                     /* running prose */
  --fs-h4:1.02rem;                    /* heading inside a component */
  --ink:#0d2233;--navy:#123a52;--slate:#51677a;--paper:#f4f8fb;--paper2:#eaf2f8;--white:#fff;
  --h2:#12bd86;--h2-deep:#0e9c6e;--h2-text:#0c8560;--sky:#2b8cc4;--sky-soft:#e7f1f8;--amber:#d9822b;
  --amber-deep:#8a6300;--amber-soft:#fdf0d0;--error:#b3261e;
  --line:#e3eaf1;--edge:#c3d0dc;--shadow:0 16px 44px -20px rgba(18,58,82,.28);--radius:18px;--maxw:1280px;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
html,body{overflow-x:clip}
body{font-family:'Inter',system-ui,sans-serif;color:var(--ink);background:var(--white);line-height:var(--lh-body);-webkit-font-smoothing:antialiased}
h1,h2,h3,h4{font-family:'Sora',sans-serif;color:var(--ink);line-height:var(--lh-tight);letter-spacing:-.02em;font-weight:700}
a{color:inherit;text-decoration:none}
img{max-width:100%;height:auto;display:block}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--gutter)}
.eyebrow{font-family:'Sora';font-size:var(--fs-eyebrow);font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--h2-text)}
.btn{display:inline-flex;align-items:center;gap:.5em;font-family:'Sora';font-weight:600;font-size:var(--fs-ui);padding:.85em 1.5em;border-radius:100px;border:1.5px solid transparent;cursor:pointer;transition:.25s;white-space:nowrap}
.btn-primary{background:var(--navy);color:#fff}@media (hover:hover){.btn-primary:hover{background:var(--ink);transform:translateY(-2px);color:#fff}}
.btn-ghost{background:rgba(255,255,255,.15);border-color:rgba(255,255,255,.65);color:#fff}.btn-ghost:hover{border-color:#fff;background:rgba(255,255,255,.25)}
.btn-dark{background:var(--navy);color:#fff}@media (hover:hover){.btn-dark:hover{background:var(--ink);transform:translateY(-2px)}}

/* --- what a button does, before it is clicked --------------------------------
   Three behaviours were wearing one appearance: open a dialog here, go to
   another page, leave for a new tab. The mark carries the kind and the colour
   is left alone, because colour on this site already means importance (navy =
   the one action of a section, white-on-green = the offer of the page) and one
   button cannot say both. Weight was tried for this once and reverted: a
   lighter button reads as a lesser offer, not as a different kind of place.
   Drawn as a mask so the mark inherits currentColor and no page needs a sprite
   for it. Arrow icons: Lucide (ISC), the diagonal pair is the site's own,
   already used on the tiles that open a panel.
   Order of the rules matters: the external mark wins over the internal one, so
   a link that opens a new tab is never labelled as going to another page. */
.btn-ico::after,a[target="_blank"]:not(.no-ico)::after{
  content:"";flex:none;width:1em;height:1em;background:currentColor;
  -webkit-mask:var(--ico) center/contain no-repeat;mask:var(--ico) center/contain no-repeat}
.btn--go{--ico:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M5%2012h14'/%3E%3Cpath%20d='m12%205%207%207-7%207'/%3E%3C/svg%3E")}                         /* another page on this site */
a[target="_blank"]:not(.no-ico){--ico:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M7%207h10v10'/%3E%3Cpath%20d='M7%2017%2017%207'/%3E%3C/svg%3E")}  /* leaves the site, new tab */
.btn--open{--ico:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%20fill='none'%20stroke='black'%20stroke-width='1.9'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M9.5%202.5h4v4'/%3E%3Cpath%20d='M6.5%2013.5h-4v-4'/%3E%3Cpath%20d='M13.5%202.5%202.5%2013.5'/%3E%3C/svg%3E")}                       /* opens here, nothing is left */
/* inline links carry the mark too, a little smaller and set off from the word */
a[target="_blank"]:not(.btn){display:inline-flex;align-items:center;gap:.25em}
a[target="_blank"]:not(.btn)::after{width:.85em;height:.85em}

/* announced instead of seen */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

header{position:sticky;top:0;z-index:50;background:rgba(255,255,255,.92);backdrop-filter:blur(14px);border-bottom:1px solid var(--line)}
nav{display:flex;align-items:center;justify-content:space-between;height:76px}
.logo img{height:64px;width:auto}
.navlinks{display:flex;gap:var(--s-6);align-items:center}
.navlinks a{font-size:var(--fs-ui);font-weight:500;color:var(--slate);transition:.2s}.navlinks a:hover{color:var(--h2-deep)}
.navlinks a.btn-dark{color:#fff;padding:.6em 1.2em}
.navlinks a.btn-dark:hover{color:#fff;background:var(--ink)}
/* Current page. aria-current carries it, so what a screen reader announces and
   what the eye sees are the same fact rather than two parallel mechanisms. */
.navlinks a[aria-current="page"]{color:var(--ink);font-weight:600;position:relative}
.navlinks a[aria-current="page"]:not(.btn-dark)::after{content:"";position:absolute;left:0;right:0;bottom:-9px;height:2px;border-radius:2px;background:var(--h2)}
/* the contact CTA is already a filled button: it darkens instead of gaining a rule */
.navlinks a.btn-dark[aria-current="page"]{background:var(--ink)}
.menu-btn{display:none;background:none;border:0;cursor:pointer;color:var(--navy)}

/* HERO */
/* Page heroes. The picture is a custom property, so a page swaps its hero by
   adding one modifier class instead of duplicating the whole block. */
.hero{--hero-img:url('images/hero-fields.webp?v=25');position:relative;min-height:38vh;display:flex;align-items:center;color:#fff;overflow:hidden}
.hero--apps{--hero-img:url('images/hero-apps.webp?v=8')}
/* Home hero on dense displays: the 1.5x file. Every other hero has no 2x
   variant, so image-set stays on this one rule. */
@media(min-resolution:1.5dppx){
  .hero:not([class*="hero--"]){--hero-img:url('images/hero-fields@2x.webp?v=25')}
}
@media(min-resolution:1.5dppx) and (max-width:600px){
  .hero:not([class*="hero--"]){--hero-img:url('images/hero-fields-800@2x.webp?v=26')}
}
.hero--tech{--hero-img:url('images/hero-tech.webp?v=3')}
.hero--projects{--hero-img:url('images/hero-projects.webp')}
.hero--company{--hero-img:url('images/hero-company-foam.webp?v=3')}
.hero .bg{position:absolute;inset:0;background:var(--hero-img) center/cover no-repeat}
/* Waagerechte Lage des Heros, 26. Aug. Das Bild ist 4:1, der Kasten nie: seine
   Hoehe steht bei rund 342 px, egal wie breit das Fenster ist. Unterhalb von
   etwa 1400 px schneidet cover deshalb seitlich, und zwar mittig — bei 610 px
   sind nur 44 % des Bildes im Kasten, bei 1000 px 73 %. Das Motiv liegt bei
   allen fuenf Heroes rechts der Mitte (63 bis 77 % der Bildbreite) und faellt
   damit als erstes heraus. Die Werte ruecken den Ausschnitt nach rechts.
   Ab der Breite, bei der das ganze Bild passt, gibt es keinen Ueberhang mehr,
   dort tun sie also nichts. Ausgewaehlt in _proto-herowide.html. */
.hero .bg{background-position:82% center}
.hero--apps .bg{background-position:89% center}
.hero--tech .bg{background-position:57% center}
.hero--projects .bg{background-position:77% center}
.hero--company .bg{background-position:80% center}
.hero .eyebrow{color:var(--h2);margin-bottom:var(--stack-title)}
/* 19 Aug: the tail now runs out to zero instead of stopping at .12, so the right
   edge of the picture is the picture. Everything left of about three quarters is
   unchanged, which is where the type sits. Measured behind the green accent line in
   the h1: 3.4:1 before, 3.2:1 now, against a 3:1 floor. Weakening the gradient as a
   whole was the obvious alternative and drops it to 2.9:1, under the floor. */
/* The house scrim. It used to be a light .55 gradient built for the homepage
   picture of the prototype, which had a dark left side; every page added since
   then needed a heavier one, so by the fifth hero there were four exceptions and
   one rule. The heavier gradient IS the rule now. Measured left-edge brightness
   before this: homepage 82 against 46-59 everywhere else, which is exactly the
   difference you see as "the gradient is not the same". */
.hero .scrim{position:absolute;inset:0;background:linear-gradient(100deg,rgba(10,32,48,.82) 0%,rgba(12,40,58,.55) 40%,rgba(12,40,58,.10) 76%,rgba(12,40,58,0) 100%)}
/* One real exception is left: the Company picture is an empty stainless bench,
   the brightest text ground of the five, and its lede runs to 62% of the width
   while the tray starts at 36%. It holds .66 out to the midpoint. */
.hero--company .scrim{background:linear-gradient(100deg,rgba(10,32,48,.86) 0%,rgba(12,40,58,.68) 46%,rgba(12,40,58,.16) 78%,rgba(12,40,58,.04) 100%)}
.hero-inner{position:relative;padding:var(--s-7) var(--gutter);max-width:var(--maxw);margin:0 auto;width:100%}
.hero h1{color:#fff;font-size:var(--fs-display);font-weight:800;max-width:30ch}
.hero h1 .accent{color:var(--h2)}
.hero .lede{margin-top:var(--stack-lede);font-size:var(--fs-lede);color:#e2eef5;max-width:50ch}

section.block{padding:var(--section-y) 0}
.section-head{max-width:62ch;margin:0 auto;text-align:center}
.section-head h1,.section-head h2{font-size:var(--fs-h2);margin-top:var(--stack-title)}
.section-head p{margin-top:var(--stack-lede);color:var(--slate);font-size:var(--fs-lede)}
.paper{background:var(--paper)}
/* one centred label above a stand-alone fact strip */
.mini-cap{display:block;text-align:center;margin-top:var(--stack-group)}
/* one emphasised sentence closing a section */
.emph{margin:var(--stack-group) auto 0;max-width:72ch;text-align:center;font-weight:600;color:var(--ink)}
/* the button row that closes a section — replaces one-off inline margins */
.sec-cta{margin-top:var(--stack-group);display:flex;justify-content:center;gap:var(--s-3);flex-wrap:wrap}

/* ==========================================================================
   HOMEPAGE LAYOUT SYSTEM
   Every homepage section is built from the same four primitives, so the reader
   only has to learn the page once:
     .section-head   eyebrow -> h2 -> lede          (identical in every section)
     .factrow        the numbers, always one shape  (headline + contrast + note)
     .tiles/.bento   image or flat cards; the interactive ones open a .dpanel
     .cardrow/.card  quiet icon cards for a list of equals
   Section-specific detail lives inside the panels, never in a bespoke layout.
   ========================================================================== */

/* --- motion --------------------------------------------------------------
   Two moves, no more: cards and figures rise in once when they enter the
   viewport, and a tile unfolds into its detail panel so the panel is the same
   object, not a new one. Timing follows the house curve used on apple.com,
   cubic-bezier(.4,0,.6,1): no snap at the start, a long soft finish. Durations
   sit deliberately above Apple's own range (they declare .2s-.5s across that
   page): this page is denser and scrolled more slowly, and .85s/.95s is where
   it stopped feeling rushed. Opacity trails the movement by 50ms so the rise
   leads. Tuned by eye against the real page, not to a spec.
   Everything is gated on .js-anim, which an inline script in <head> sets, so
   with JS off the page renders complete and static. Reduced motion opts out. */
.js-anim .tiles>.bento,
.js-anim .cardrow>.card,
.js-anim .factrow>.fact,
.js-anim .timeline>.tl,
.js-anim .econ-chart{
  opacity:0;transform:translateY(28px);
  transition-property:opacity,transform;
  transition-duration:.85s,.95s;
  transition-timing-function:cubic-bezier(.4,0,.6,1),cubic-bezier(.4,0,.6,1);
  transition-delay:calc(var(--d,0ms) + 50ms),var(--d,0ms);
}
.js-anim .tiles>.bento.is-in,
.js-anim .cardrow>.card.is-in,
.js-anim .factrow>.fact.is-in,
.js-anim .timeline>.tl.is-in,
.js-anim .econ-chart.is-in{opacity:1;transform:none}
/* once revealed, the tile gets its own transition back so hover stays snappy */
.js-anim .tiles>.bento.anim-done{transition:transform .25s,box-shadow .25s;transition-delay:0s}
@media (prefers-reduced-motion:reduce){
  .js-anim .tiles>.bento,
  .js-anim .cardrow>.card,
  .js-anim .factrow>.fact,
  .js-anim .timeline>.tl,
  .js-anim .econ-chart{opacity:1;transform:none;transition:none}
}

/* --- fact strip: the number carries the claim, the contrast line the point --- */
.factband{background:var(--paper);border-bottom:1px solid var(--line);padding:var(--s-7) 0}
.factband .eyebrow{display:block;text-align:center}
.factrow{list-style:none;display:grid;grid-template-columns:repeat(5,1fr);gap:var(--grid-gap);margin-top:var(--s-4)}
.factrow.f3{grid-template-columns:repeat(3,1fr)}
.fact{border-left:3px solid var(--h2);padding-left:var(--s-4)}
/* market context, not a PCC claim — grey bar keeps the two apart */
.fact--ctx{border-left-color:var(--edge)}
/* The upper bound is the column, not the viewport: the factrow column stops growing
   at 205px once the wrap hits its max-width, while 2.1vw keeps going. Above ~1280px
   the headline outgrew its own column and short phrases broke into two lines
   ("No NOx or PM"). Capped at the size that still fits 205px. */
.fact-n{font-family:'Sora',sans-serif;font-weight:800;font-size:clamp(1.45rem,2.1vw,1.65rem);line-height:1.05;letter-spacing:-.02em;color:var(--ink)}
.fact-vs{display:block;font-family:'Sora',sans-serif;font-size:var(--fs-fine);line-height:1.35;font-weight:600;letter-spacing:.01em;color:var(--h2-text);margin-top:var(--stack-label)}
/* reserve two lines so the notes below line up across all five columns
   (five-column strips only; the three-column variant needs no reserve) */
.factrow:not(.f3) .fact-vs{min-height:2.7em}
.fact--ctx .fact-vs{color:var(--slate)}
.fact-l{font-size:var(--fs-small);line-height:1.5;color:var(--slate);margin-top:var(--s-2);max-width:30ch}

/* --- tiles (bento): one card language for every section --- */
.tiles{display:grid;gap:var(--grid-gap);margin-top:var(--stack-block)}
.tiles-2{grid-template-columns:repeat(2,1fr)}
.tiles-3{grid-template-columns:repeat(3,1fr)}
.tiles-4{grid-template-columns:repeat(4,1fr)}
.bento{position:relative;display:block;width:100%;border:0;padding:0;border-radius:var(--radius);overflow:hidden;background:var(--ink);color:#fff;text-align:left;font-family:inherit;box-shadow:var(--shadow);transition:transform .25s,box-shadow .25s}
.tiles-2 .bento{aspect-ratio:16/10}
.tiles-3 .bento{aspect-ratio:4/3}
.tiles-4 .bento{aspect-ratio:4/5}
button.bento{cursor:pointer}
.bento img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:transform .5s}
.bento.power img{object-position:30% 50%}
.bento.mobility img{object-position:50% 50%}
/* Two layers, and they have different jobs. The veil over the whole tile is for mood;
   the dark ground under the text is what carries the type. It used to be one gradient
   measured from the bottom of the TILE, so the dark zone sat where the tile ended rather
   than where the text began. All three numbers below are measured behind the green fact
   line on app-power, the tile with the palest sky and the most copy: the old single
   gradient put it at 3.0:1, right on the 3:1 floor for large text, and simply weakening
   that gradient dropped it to 2.3:1, under the floor. Tying the ground to .bento-body
   makes it grow with the text instead, which measures 4.8:1 while the veil over the
   picture falls from .90/.66/.22/.14 to .42/.26/.08. Better in both directions. */
.bento-scrim{position:absolute;inset:0;background:linear-gradient(to top,rgba(9,26,40,.42) 0%,rgba(9,26,40,.26) 40%,rgba(9,26,40,.08) 100%)}
.bento-body{position:absolute;left:0;right:0;bottom:0;padding:var(--s-7) var(--s-5) var(--s-5);background:linear-gradient(to top,rgba(9,26,40,.70) 0%,rgba(9,26,40,.55) 55%,rgba(9,26,40,0) 100%)}
.bento-kicker{display:block;font-family:'Sora',sans-serif;font-weight:600;font-size:var(--fs-micro);letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.78)}
.bento-title{display:block;font-family:'Sora',sans-serif;font-weight:800;font-size:clamp(1.15rem,1.65vw,1.5rem);line-height:1.1;letter-spacing:-.02em;color:#fff;margin-top:var(--s-2)}
.bento-fact{display:block;font-family:'Sora',sans-serif;font-weight:800;font-size:clamp(1.3rem,1.9vw,1.7rem);line-height:1.05;letter-spacing:-.02em;color:#3ddf9f;margin-top:var(--s-3)}
.bento-sub{display:block;font-size:var(--fs-small);line-height:1.45;color:#cfdfea;margin-top:var(--s-2);max-width:58ch}
/* four-up tiles reserve three lines, so kicker, title and figure line up
   across the row even when the sentences differ in length */
.tiles-4 .bento-sub{min-height:calc(3 * 1.45em)}
.bento-icon{position:absolute;top:var(--s-5);right:var(--s-5);width:34px;height:34px;border-radius:50%;border:1px solid rgba(255,255,255,.55);display:grid;place-items:center;color:#fff;transition:background .25s,border-color .25s;z-index:2}
/* light tile: flows top-to-bottom (map or diagram on top, body below) */
.tiles .bento--light{aspect-ratio:auto;display:flex;flex-direction:column;background:#fff;color:var(--ink);border:1px solid var(--line);padding:var(--card-pad);box-shadow:0 8px 24px -14px rgba(18,58,82,.32)}
/* a light tile shows its picture in flow, not as the tile's ground, so neither the
   absolute image position nor the dark body gradient applies here */
.bento--light .bento-body{position:static;margin-top:auto;padding:0;background:none}
.bento--light .bento-title{color:var(--ink)}
.bento--light .bento-sub{color:var(--slate)}
.bento--light .bento-kicker{color:var(--slate)}
.bento--light .bento-fact{color:var(--h2-text)}
.bento--light .bento-icon{border-color:var(--edge);color:var(--navy)}
.bento--light .geo-map{width:100%;max-width:186px;margin:var(--s-2) auto var(--s-6)}
/* unit tile: Tim's engineering drawing of the process unit. It keeps its white sheet
   of graph paper (his own decision: a drawing may look like a drawing), but it is built
   as a tile, not as a card: the text sits ON the drawing under a dark layer, the way the
   photo tiles do it. That layer has to be stronger here than over a photo, because the
   ground underneath is white paper rather than a dark sky, so the gradient below is the
   tile's own and is measured against the paper, not against the picture.
   The drawing is contained rather than cropped, inset from the edge, and it runs on
   down INTO the gradient rather than stopping above it, the way a photo does in the
   tiles beside it. Scrim and body gradient are the shared ones, deliberately not a
   stronger set: the contrast on white paper is measured below. tech-skid.webp is a
   cut-out and therefore needs a light ground; the untouched original is in
   image-prompts/. */
.tiles-2 .bento--unit{aspect-ratio:auto}
.bento--unit{background:var(--white)}
.bento--unit::before{content:"";position:absolute;inset:0;z-index:0;
  background-image:linear-gradient(var(--line) 1px,transparent 1px),
                   linear-gradient(90deg,var(--line) 1px,transparent 1px);
  background-size:28px 28px}
.bento--unit img{object-fit:contain;object-position:50% 50%;padding:var(--s-5)}
/* list tile: a light tile whose body IS the content (no map or photo above it).
   Centred rather than pushed to the bottom, so a short list (four pills) does not
   leave the card top-heavy next to a full-height photo tile. */
.tiles .bento--light.bento--list{justify-content:center}
.bento--light.bento--list .bento-body{margin-top:0}
@media (hover:hover){
  button.bento:hover{transform:translateY(-4px);box-shadow:0 26px 56px -22px rgba(18,58,82,.46)}
  button.bento:hover img{transform:scale(1.045)}
  button.bento:hover .bento-icon{background:rgba(255,255,255,.18);border-color:#fff}
  button.bento--light:hover .bento-icon{background:var(--paper);border-color:var(--h2-deep);color:var(--h2-deep)}
}
.bento:focus-visible{outline:3px solid var(--sky);outline-offset:3px}

/* --- quiet cards: a list of equals, no interaction --- */
.cardrow{list-style:none;display:grid;grid-template-columns:repeat(4,1fr);gap:var(--grid-gap);margin-top:var(--stack-block)}
/* Column variants. Four is the default (four output streams, four credibility
   cards). Three is for a row of three equals; two is for a row whose entries
   differ a lot in length — the Technology process steps run from 100 to 270
   characters, and at four columns the long one made every card in the row three
   times as tall as its own text needed. */
.cardrow--3{grid-template-columns:repeat(3,1fr)}
.cardrow--2{grid-template-columns:repeat(2,1fr)}
.card{padding:var(--card-pad);border-radius:14px;border:1px solid var(--line);background:#fff;box-shadow:0 6px 20px -16px rgba(18,58,82,.4)}
.card-ic{color:var(--h2-deep);margin-bottom:var(--stack-label)}
/* place label above a card heading (Projects: the six markets in development).
   Same role as .bento-kicker on a tile, so it carries the same type and case. */
.card-k{display:block;font-family:'Sora',sans-serif;font-weight:600;font-size:var(--fs-micro);letter-spacing:.14em;text-transform:uppercase;color:var(--h2-text);margin-bottom:var(--stack-label)}
.card-h{font-size:var(--fs-h4);margin-bottom:var(--stack-tight)}
.card-p{font-size:var(--fs-small);line-height:1.5;color:var(--slate)}
.card--io{display:flex;gap:var(--s-4);align-items:flex-start}
.card-orb{flex:none;width:48px;height:48px;border-radius:50%;display:grid;place-items:center;color:#fff;background:var(--navy)}
.card-orb svg{width:52%;height:52%}
/* the same orb carrying a step number instead of an icon (Technology process) */
.card-orb--n{font-family:'Sora',sans-serif;font-weight:800;font-size:var(--fs-h4);letter-spacing:0}
.doi-link{text-decoration:underline;color:var(--h2-text)}

/* --- person card (Company leadership) ------------------------------------
   A .card that opens a panel, so it is a <button> and has to undo what a
   button brings with it, the way .bento does.

   The portrait is deliberately small. Two of the three photographs are full
   camera files, the third arrived as a 191px web avatar, and a set is only as
   sharp as its weakest picture: shown larger, one face would be visibly soft
   next to two crisp ones and the whole row would read as careless. At 88px it
   is the same picture quality across all three. When a full-size photograph of
   the third arrives, this number is the only thing that has to change. */
.card--person{display:block;width:100%;text-align:left;font-family:inherit;cursor:pointer;
  transition:transform .25s,box-shadow .25s}
.card--person:hover{transform:translateY(-2px);box-shadow:0 14px 28px -20px rgba(18,58,82,.55)}
@media (prefers-reduced-motion:reduce){.card--person,.card--person:hover{transition:none;transform:none}}
.person-av{flex:none;width:88px;height:88px;border-radius:50%;object-fit:cover;
  background:var(--paper);margin-bottom:var(--s-4);display:block}
/* sits at the foot of the card and says the card opens rather than navigates,
   so it carries .btn--open (the diagonal double arrow), not .btn--go */
.person-more{display:inline-flex;align-items:center;margin-top:var(--stack-tight);
  font-family:'Sora',sans-serif;font-weight:600;font-size:var(--fs-micro);
  letter-spacing:.14em;text-transform:uppercase;color:var(--h2-text)}

/* --- biography panel ------------------------------------------------------
   PCC supplied one of the three bios as a CV extract rather than prose: a role
   line and four bullets. It is their content and stays as written, so the
   panel has to be able to set it. */

/* --- process flow (Technology) -------------------------------------------
   A rebuild of the process graphic PCC supplied as a slide image. Same content,
   same three bands (inputs, process, outputs), but the labels are HTML text
   instead of pixels: PCC can edit them, they stay sharp at every width, and the
   diagram carries no baked-in lettering — the rule that keeps labelled diagrams
   out of image generation. It sits in the light tile next to the reactor photo,
   so it is sized for roughly half the page width. */
.flow{margin:0;margin-top:var(--s-4)}
.flow-band{display:grid;gap:var(--stack-label)}
.flow-k{font-family:'Sora',sans-serif;font-weight:600;font-size:var(--fs-micro);letter-spacing:.14em;text-transform:uppercase;color:var(--slate)}
.flow-row{list-style:none;display:grid;grid-template-columns:repeat(3,1fr);gap:var(--gap-chip)}
/* Four inputs do not fit the three-column row: at this tile width a fourth
   column squeezes every chip below its own label, and 3+1 leaves an orphan.
   Two by two instead, which is the only even split four has. */
.flow-row--4{grid-template-columns:repeat(2,1fr)}
/* Chips read icon-left rather than icon-on-top: the tile stands next to a
   16/10 photo tile, and the stacked version made the diagram some 200px taller
   than the picture beside it. */
.flow-chip{display:flex;align-items:center;gap:var(--s-2);padding:var(--s-2) var(--s-3);border:1px solid var(--line);border-radius:12px;background:var(--paper);font-size:var(--fs-fine);line-height:1.3;color:var(--navy)}
.flow-chip svg{flex:none;width:18px;height:18px;color:var(--h2-deep)}
/* the patented middle of the process is the one accent surface in the diagram */
.flow-core{border-radius:12px;background:var(--navy);color:#fff;padding:var(--s-3) var(--s-4);display:grid;gap:var(--s-2)}
.flow-core p{font-size:var(--fs-fine);line-height:1.4;color:#bcd2e2}
.flow-core b{display:block;font-family:'Sora',sans-serif;font-weight:700;font-size:var(--fs-small);color:#fff}
.flow-arrow{display:block;width:18px;margin:var(--s-2) auto;color:var(--edge)}
@media(max-width:600px){
  .flow-row{grid-template-columns:1fr}
}

/* --- legal text (Privacy) -------------------------------------------------
   One readable column, nothing else. Lived in the page's own stylesheet until
   the rebuild; here now so that no page ships a private one. */
.legal{max-width:760px;margin:0 auto;padding:var(--section-y) var(--s-5)}
.legal h1{font-size:var(--fs-h2);margin-bottom:var(--s-2)}
.legal .updated{color:var(--slate);font-size:var(--fs-small);margin-bottom:var(--s-7)}
.legal h2{font-size:var(--fs-h3);margin:var(--s-7) 0 var(--s-3)}
.legal p,.legal li{color:var(--slate);font-size:var(--fs-body);margin-bottom:var(--s-3)}
.legal ul{padding-left:var(--stack-sub);margin-bottom:var(--s-3)}
.legal a{text-decoration:underline;color:var(--h2-text)}

/* --- contact form ---------------------------------------------------------
   The only form on the site. Its styles sat in the page's private stylesheet
   until Contact was rebuilt; they live here now, on tokens, so a field, its
   label and its focus ring are the same objects as everything else.
   Contact is also the one page with no hero band: the form is the job of the
   page, and a picture would only push it down. It opens on a section head. */
.formcard{max-width:720px;margin:var(--stack-block) auto 0;background:var(--white);border:1px solid var(--line);border-radius:var(--radius);padding:var(--card-pad);box-shadow:var(--shadow)}
.form-field{margin-bottom:var(--stack-item)}
.form-field label{display:block;font-family:'Sora',sans-serif;font-size:var(--fs-small);font-weight:600;color:var(--navy);margin-bottom:var(--stack-label)}
/* An explicit line height on all three, because "normal" is not the same number
   in every engine and the fields then stop lining up. The textarea keeps a
   roomier one: it holds several lines, the others hold one. */
.form-field input,.form-field select,.form-field textarea{width:100%;padding:.8em 1em;border:1.5px solid var(--line);border-radius:11px;font-family:inherit;font-size:var(--fs-ui);line-height:1.35;color:var(--navy);background:var(--white)}
.form-field textarea{line-height:1.6}
/* iOS zooms the page in when a field smaller than 16px takes focus, and the
   page then scrolls sideways until the reader pinches back out. --fs-ui is
   15.2px, just under the line. On a touch device the fields go to exactly 16. */
@media (pointer:coarse){
  .form-field input,.form-field select,.form-field textarea{font-size:16px}
}
/* the browsers' own placeholder grey is not our grey, and next to the dropdown
   (which we colour ourselves) the difference shows */
.form-field ::placeholder{color:var(--slate);opacity:1}
.form-field input:focus,.form-field select:focus,.form-field textarea:focus{outline:none;border-color:var(--h2)}
/* The one control the browser insists on drawing itself. Left native it lands
   at a different height in every engine — 2px taller than the inputs in Chrome,
   visibly shorter in Safari — so it is the only field that breaks the row. Take
   the appearance away, give it the same box as an input, and draw the chevron
   as a background so it cannot drift either. */
.form-field select{appearance:none;-webkit-appearance:none;padding-right:2.8em;
  background-image:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%2351677a'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='m6%209%206%206%206-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 1em center;background-size:1.1em}
/* Nothing chosen yet reads as a placeholder, the way an empty text field does */
.form-field select.is-empty{color:var(--slate)}
/* the honeypot: a real field for a bot, off-screen for everyone else */
.form-field--trap{position:absolute;left:-9999px}
.form-submit{width:100%;justify-content:center;margin-top:var(--s-7)}
.form-note{font-size:var(--fs-fine);color:var(--slate);margin-top:var(--stack-sub)}
.form-note a{text-decoration:underline}
.form-error{display:none;color:var(--error);font-size:var(--fs-small);margin-top:var(--s-3)}
.form-done{display:none;text-align:center;padding:var(--s-7) var(--s-3)}
.form-done .tick{display:block;font-size:2.4rem;line-height:1;color:var(--h2-deep)}
.form-done h2{font-size:var(--fs-h3);margin:var(--s-3) 0}
.form-done p{color:var(--slate)}
.contact-hq{margin-top:var(--stack-group);text-align:center}
/* Contact standing in for the dialog (see panels.js): the page keeps its own
   chrome for anyone who arrived here directly, and drops it for anyone who got
   here by closing the distance from another page — there the close button is
   the way back, and a footer underneath a dialog reads as a mistake. */
.as-dialog header,.as-dialog footer,.as-dialog .contact-hq{display:none}
/* the section stops behaving like a section: less air on top, and room reserved
   for the close button so it never sits on the heading */
.as-dialog #contact{padding-top:var(--s-5)}
.as-dialog #contact .wrap{position:relative;padding-top:calc(38px + var(--s-4))}
.contact-x{top:0;right:var(--gutter)}
.contact-hq .eyebrow{display:block;margin-bottom:var(--stack-label)}
.contact-hq p{color:var(--slate);font-size:var(--fs-small);line-height:1.7}

/* --- timeline (Company) ---------------------------------------------------
   The one component Company needs that no other page does: a dated list of
   sixteen milestones. It stays a timeline rather than becoming sixteen cards,
   because the order and the dates are the content, not decoration. Moved out of
   the page's own stylesheet into here, on tokens, when Company was rebuilt.
   The dot carries no white ring: it is larger than the rule and centred on it,
   so the component does not have to know which section background it sits on. */
.timeline{list-style:none;position:relative;max-width:760px;margin:var(--stack-block) auto 0;padding-left:var(--s-6);border-left:2px solid var(--line)}
.tl{position:relative;padding-bottom:var(--s-6)}
.tl:last-child{padding-bottom:0}
.tl:before{content:"";position:absolute;left:calc(-1 * var(--s-6) - 7px);top:6px;width:12px;height:12px;border-radius:50%;background:var(--h2)}
.tl-date{display:block;font-family:'Sora',sans-serif;font-weight:700;font-size:var(--fs-fine);color:var(--h2-text)}
.tl-h{font-size:var(--fs-h4);margin:var(--stack-tight) 0}
.tl-p{font-size:var(--fs-small);line-height:1.5;color:var(--slate)}

/* --- grouping ------------------------------------------------------------
   The rhythm carries the reading: a heading and the row it introduces are one
   group and sit close together; two groups are pushed apart. Two tokens do it,
   --stack-block inside a group and --stack-group between them. Before this,
   both were 32px and the page read as one undifferentiated column.
   A .mini-cap label belongs to the row *underneath* it, never to what came
   before, so it takes the group gap above and a tight gap below. */
.mini-cap + .cardrow,.mini-cap + .factrow,.mini-cap + .tiles,
.mini-cap + .timeline,.mini-cap + .docfig{margin-top:var(--s-4)}
/* two content groups following each other, with no label between them */
.tiles + .tiles,.tiles + .cardrow,.tiles + .factrow,
.cardrow + .tiles,.cardrow + .cardrow,.cardrow + .factrow,
.factrow + .tiles,.factrow + .cardrow,.docfig + .cardrow,
.timeline + .cardrow{margin-top:var(--stack-group)}

/* --- detail panel: the one place section-specific content is allowed to differ --- */
/* Native <dialog>, opened with showModal(). The browser owns the top layer,
   the focus trap, Escape and the inert background; the ::backdrop is its to
   size, which is the whole reason this stopped being arithmetic against iOS.
   The dialog element itself is only the box's container, so it is sized to the
   visual viewport — that is what keeps the box clear of the on-screen keyboard
   and of Safari's address pill. Without the API both variables fall back and it
   behaves as a plain dvh overlay. */
.dpanel{position:fixed;left:0;right:0;top:0;width:auto;max-width:none;height:100vh;height:100dvh;height:var(--vv-h,100dvh);max-height:none;margin:0;border:0;padding:var(--s-5) var(--s-5) calc(var(--s-5) + var(--vv-gap,0px));background:transparent;color:inherit;overflow-y:auto;overscroll-behavior:contain}
.dpanel:not([open]){display:none}
.dpanel[open]{display:grid;place-items:center}
.dpanel::backdrop{background:rgba(13,34,51,.62);backdrop-filter:blur(6px);opacity:1;transition:opacity .36s cubic-bezier(.4,0,.6,1)}
@starting-style{.dpanel[open]::backdrop{opacity:0}}
.dpanel.is-closing::backdrop{opacity:0;transition-duration:.24s}
.dpanel-box{position:relative;width:100%;max-width:660px;background:#fff;border-radius:var(--radius);overflow:hidden;box-shadow:0 40px 90px -30px rgba(13,34,51,.6);margin:auto}
.dpanel--wide .dpanel-box{max-width:940px}
.dpanel-pic{aspect-ratio:2/1;background:var(--paper)}
.dpanel-pic img{width:100%;height:100%;object-fit:cover;display:block}
.dpanel-body{padding:var(--s-6)}
.dpanel-kicker{font-family:'Sora',sans-serif;font-weight:800;font-size:clamp(1.5rem,2.2vw,2.05rem);letter-spacing:-.02em;line-height:1.03;color:var(--ink)}
.dpanel-body h3{font-size:var(--fs-h3);color:var(--ink);margin:var(--stack-tight) 0 var(--stack-sub)}
.dpanel-body>p{color:var(--slate);margin-bottom:var(--stack-sub)}
.dpanel-x{position:absolute;top:var(--s-4);right:var(--s-4);width:38px;height:38px;border-radius:50%;border:0;background:rgba(13,34,51,.55);color:#fff;font-size:1.4rem;line-height:1;cursor:pointer;display:grid;place-items:center;transition:background .2s;z-index:3}
.dpanel-x:hover{background:var(--ink)}
.dpanel--form form{margin-top:var(--s-6)}
.dpanel-link{display:inline-block;margin-top:var(--stack-block);font-weight:600;color:var(--h2-deep)}
.dpanel-meta{margin-top:var(--stack-sub);padding-top:var(--stack-sub);border-top:1px dashed var(--edge);font-size:var(--fs-small);color:var(--slate)}
.dpanel-meta b{font-family:'Sora';font-size:var(--fs-micro);letter-spacing:.08em;text-transform:uppercase;color:var(--ink);display:block;margin-bottom:var(--stack-label)}
.dpanel-fig{padding:var(--s-6) var(--s-6) 0;margin:0}
/* the Cloverdale site plan is framed as a document on white inside the panel */
.dpanel .proof-shot figcaption{color:var(--slate)}

.pill{background:var(--paper);border:1px solid var(--line);border-radius:100px;padding:.45em .95em;font-size:var(--fs-fine);font-weight:500;color:var(--navy)}
.pill-row{display:flex;flex-wrap:wrap;gap:var(--gap-chip)}
/* a labelled group of pills. Used on Applications, where the use-case lists are
   short enough to stay on the page instead of moving into a detail panel. */
.pill-set{margin-top:var(--stack-sub)}
.pill-set .k{display:block;font-family:'Sora',sans-serif;font-weight:600;font-size:var(--fs-micro);letter-spacing:.1em;text-transform:uppercase;color:var(--h2-deep);margin-bottom:var(--stack-label)}

/* three products — lives inside the Deploy panel */
.out-row{list-style:none;display:grid;grid-template-columns:1fr;gap:var(--stack-sub);margin-top:var(--stack-label)}
.out-item{display:flex;gap:var(--s-4);align-items:flex-start}
.out-ic{flex:none;width:48px;height:48px;border-radius:50%;display:grid;place-items:center;color:#fff;background:var(--navy)}
.out-ic svg{width:52%;height:52%}
.out-txt h4{font-family:'Sora',sans-serif;font-size:var(--fs-h4);font-weight:600;color:var(--ink)}
.out-txt p{font-size:var(--fs-small);color:var(--slate);margin-top:var(--stack-tight)}
.out-txt .pill-row{margin-top:var(--stack-label)}
.out-apps{margin-top:var(--stack-sub);padding-top:var(--stack-sub);border-top:1px solid var(--line)}
.out-apps .k{display:block;font-family:'Sora';font-weight:600;font-size:var(--fs-micro);letter-spacing:.1em;text-transform:uppercase;color:var(--h2-deep);margin-bottom:var(--stack-label)}
.out-apps .pill-row{margin-top:var(--stack-label)}

/* Standortnachweis (index panel + projects): PCC's site plan is shown complete
   and framed as a document — never cropped to fill a box, since the crop cuts
   off the plant label and the legend that make it readable. Source line stays
   visible: it credits PCC and carries the base-imagery attribution. */
/* One .proof-shot exists on the site, the Cloverdale map, and it lives inside a
   detail panel. The base rule used to carry a saturate(.85) filter, a drop shadow
   and a translucent white border for a dark surface, and the .dpanel override then
   switched all three off again, so none of them ever reached the screen. Folded into
   one honest rule (19 Aug). The map is a Google base image with drawn labels: it
   needs no filter, and desaturating a map that people read distances off would be
   the wrong kind of polish anyway. */
.proof-shot{width:100%;margin:0}
.proof-shot img{display:block;width:100%;height:auto;border-radius:10px;border:1px solid var(--line)}
.proof-shot figcaption{margin-top:var(--stack-item);font-size:var(--fs-fine);line-height:1.5;color:var(--slate)}

/* --- supplied document (Projects) ----------------------------------------
   PCC supplied two artefacts that are documents, not photographs: the
   Cloverdale site plan and the project-locations map. Neither survives being
   cropped into a half-width picture tile — the crop cuts off the plant label
   and the legend that make them readable, and at tile size the lettering is
   gone. Both therefore run full width on a white card, framed identically, so
   the reader recognises them as the same kind of object: something PCC drew,
   not something we shot. */
.docfig{margin:var(--stack-block) auto 0;max-width:920px;background:var(--white);border:1px solid var(--line);border-radius:var(--radius);padding:var(--card-pad);box-shadow:0 8px 24px -14px rgba(18,58,82,.32)}
.docfig img{width:100%;height:auto;border-radius:10px}
.docfig figcaption{margin-top:var(--stack-item);font-size:var(--fs-fine);line-height:1.5;color:var(--slate);text-align:center}


/* regional maps — silhouettes generated from Natural Earth 10m.
   The shapes live as <symbol>s in the page sprite and are drawn with
   presentation attributes (var() tokens), so a <use> clone needs no CSS. */
.geo-svg{display:block;width:100%;height:auto}
.geo-map{display:block;max-width:250px;margin-top:var(--s-4)}
.geo-list{list-style:none;margin-top:var(--stack-item);display:grid;gap:var(--stack-item)}
.geo-list li{display:flex;gap:var(--stack-item);align-items:center;font-size:var(--fs-small);color:var(--slate)}
.geo-list i{flex:none;width:9px;height:9px;border-radius:50%;background:var(--navy)}
.geo-list li.is-live{color:var(--ink);font-weight:600}
.geo-list li.is-live i{background:var(--h2-deep)}

/* PROJECT ECONOMICS — illustrative LCOH-vs-scale chart */
/* Kept deliberately small: it is an illustration next to the text, not a
   headline visual — oversized bars and ticks made it read as the main event. */
.econ-chart{background:var(--white);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);padding:var(--card-pad);max-width:600px;margin:var(--stack-block) auto 0}
.econ-chart figcaption{display:block}
.econ-chart .econ-eyebrow{font-family:'Sora',sans-serif;font-size:var(--fs-micro);font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--h2-text)}
.econ-chart .econ-title{display:block;font-family:'Sora',sans-serif;font-size:var(--fs-h4);font-weight:700;line-height:var(--lh-tight);letter-spacing:-.01em;color:var(--ink);margin-top:var(--s-2)}
.econ-svg{display:block;width:100%;height:auto;margin-top:var(--s-5);overflow:visible}
.econ-svg .axis{stroke:var(--edge);stroke-width:1}
.econ-svg .bar{fill:var(--h2-deep)}
.econ-svg .lab{font-family:'Inter',system-ui,sans-serif;font-size:11px;fill:var(--slate)}
.econ-note{margin-top:var(--stack-sub);font-size:var(--fs-fine);color:var(--slate)}

/* The closing band was a full-bleed saturated green, the only saturated surface on
   the site, and Cyril asked for something matching the rebuilt look. It is navy now,
   the same ground every hero sits on, so each page opens and closes on one surface.
   That frees green to do the one job it already does everywhere else: accent. The
   surface rule in DESIGN.md changed with it. Body copy uses the hero lede grey rather
   than the old green-tinted white, and the button hover is the accent, which is also
   the only place green appears in the band now. */
.cta{background:linear-gradient(135deg,var(--navy),var(--ink));color:#fff}
.cta .wrap{text-align:center;padding:var(--section-y) var(--gutter)}
.cta h2{color:#fff;font-size:clamp(1.9rem,3.4vw,2.6rem);max-width:20ch;margin:0 auto}
.cta p{margin:var(--stack-lede) auto 0;max-width:48ch;color:#e2eef5}
.cta .btn-primary{background:#fff;color:var(--navy)}
@media (hover:hover){.cta .btn-primary:hover{background:var(--h2);color:#06251a}}
.cta-trust{margin-top:var(--s-5);font-family:'Sora',sans-serif;font-size:var(--fs-small);color:#e2eef5}

footer{background:var(--paper);color:var(--slate);padding:var(--s-8) 0 var(--s-6);border-top:1px solid var(--line)}
.foot-grid{display:grid;grid-template-columns:1.5fr 1fr 1fr 1fr;gap:var(--s-6)}
footer .foot-h{color:var(--ink);font-family:'Sora';font-size:var(--fs-eyebrow);text-transform:uppercase;letter-spacing:.1em;margin-bottom:var(--stack-label)}
/* A footer column is a heading and a list: the heading is the group label, the
   entries under it belong together and read as one block. The links used to be
   spaced by padding (5px, then 3px) while the address was spaced by its line
   height, so the two columns ran at different rhythms — 30px against 25.8px.
   Both are on the same line height now and the padding is gone. */
footer a{display:block;color:var(--slate);font-size:var(--fs-small);line-height:1.75;transition:.2s}footer a:hover{color:var(--h2-deep)}
.foot-logo img{height:36px;width:auto;margin-bottom:var(--stack-item)}
.foot-about{font-size:var(--fs-small);max-width:34ch;color:var(--slate)}
/* The postal address is not a link. It used to be three <a href="#">, which
   look and hover like links and jump to the top of the page when clicked. */
.foot-addr{font-style:normal;font-size:var(--fs-small);line-height:1.75;color:var(--slate);margin-bottom:var(--s-4)}
.foot-bottom{border-top:1px solid var(--line);margin-top:var(--s-7);padding-top:var(--stack-sub);display:flex;justify-content:space-between;flex-wrap:wrap;gap:var(--stack-item);font-size:var(--fs-fine);color:var(--slate)}
.foot-inline{display:inline;padding:0}
/* AI-Hinweis, von PCC im Wortlaut vorgegeben (12. Aug). Eigene Zeile unter der
   Rechtezeile, weil .foot-bottom zweispaltig umbricht und der Satz zusammenbleiben
   soll. Dieselbe Aussage steht als Absatz in privacy.html. */
.foot-note{margin-top:var(--stack-item);font-size:var(--fs-fine);color:var(--slate);max-width:78ch}

@media(max-width:1100px){
  .factrow{grid-template-columns:repeat(3,1fr);row-gap:var(--s-6)}
  .tiles-4{grid-template-columns:repeat(2,1fr)}
  .tiles-4 .bento{aspect-ratio:4/3}
  .cardrow,.cardrow--3{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:900px){
  .navlinks{display:none}.menu-btn{display:block}
  .tiles-2,.tiles-3{grid-template-columns:1fr}
  .tiles-2 .bento,.tiles-3 .bento{aspect-ratio:16/9}
  /* One column: no sibling left to take the height from. A fixed ratio was the
     first answer and it was wrong (Daniel, 26. Aug): the drawing is almost square
     at 1.09:1, so a 4/5 box leaves a third of its width as empty paper, split above
     and below the drawing. Without a neighbour the tile takes its height from its
     own content instead, and then there is no slack to distribute. The drawing runs
     in flow rather than as the tile's ground, and keeps clear of the text band by
     the band's own height. */
  .tiles-2 .bento.bento--unit{aspect-ratio:auto}  /* eine Klasse mehr, weil eine spaetere Media-Regel sonst 16/10 zurueckholt */
  .bento--unit img{position:relative;height:auto;object-fit:contain;
    padding:var(--s-5) var(--s-5) 124px}
  .tiles .bento--light{aspect-ratio:auto}
  .bento--light .geo-map{margin-bottom:var(--s-5)}
  .factrow.f3{grid-template-columns:1fr;gap:var(--s-5)}
  .foot-grid{grid-template-columns:1fr}
  .geo-map{margin-left:auto;margin-right:auto}
}
@media(max-width:600px){
  /* the tighter desktop rhythm would put footer links below a comfortable touch
     target, so they get padding back where a finger is doing the work */
  footer a{padding:10px 0}
  .btn{white-space:normal;text-align:center}
  .factrow,.factrow.f3{grid-template-columns:1fr;gap:var(--s-5)}
  /* the two reserved lines align .fact-l across a row of columns. In one
     column there is nothing left to align, and the reserve only opens a hole
     between the contrast line and the sentence it belongs to. */
  .factrow:not(.f3) .fact-vs{min-height:0}
  .fact-l{max-width:none}
  .tiles-4{grid-template-columns:1fr}
  .tiles-2 .bento,.tiles-3 .bento,.tiles-4 .bento{aspect-ratio:16/10}
  .tiles .bento--light{aspect-ratio:auto}
  .cardrow,.cardrow--3,.cardrow--2{grid-template-columns:1fr}
  /* Full-bleed on a phone. The bottom inset that keeps the last line clear of
     Safari's address pill goes INSIDE the scrolling content, not on the scroll
     container: a container's bottom padding is not reliably part of the
     scrollable area, so scrolling to the end still left the last line under the
     pill. Measured: last line at 640 against a visible edge of 604. */
  .dpanel{padding:0}
  .dpanel-box{border-radius:0;max-width:none;min-height:100%}
  .dpanel-body{padding:var(--s-5) var(--s-5) calc(var(--s-5) + var(--vv-gap,0px))}
  .dpanel-fig{padding:var(--s-5) var(--s-5) 0}
}
@media(max-width:400px){
  .hero h1{font-size:1.9rem}
}
#m a{min-height:44px;display:flex;align-items:center}


/* keyboard focus + skip link */
/* No border-radius here: the outline already follows whatever rounding the
   element has, and forcing 4px flattened everything that carries its own —
   tiles (18px) and pill buttons (100px) both lost their shape on focus. */
:focus-visible{outline:3px solid var(--sky);outline-offset:3px}
/* Panels move the focus by script: into the dialog on open, back onto the tile
   on close. A pointer user never asked for that and only sees a ring appear out
   of nowhere, so the script tags those elements and the ring stays hidden. It is
   not tagged when the panel was driven from the keyboard — there the ring is the
   only thing telling you where you now are. */
.no-ring:focus-visible{outline:none}
.skip-link{position:absolute;left:-9999px;top:0;background:var(--navy);color:#fff;padding:.8em 1.2em;z-index:200;border-radius:0 0 10px 0;font-family:'Sora',sans-serif}
.skip-link:focus{left:0}
/* mobile hero variants — each is its own crop, not a scaled-down desktop file */
@media(max-width:600px){
  .hero{--hero-img:url('images/hero-fields-800.webp?v=26')}
  .hero--apps{--hero-img:url('images/hero-apps-800.webp?v=9')}
  .hero--tech{--hero-img:url('images/hero-tech-800.webp?v=4')}
  .hero--projects{--hero-img:url('images/hero-projects-800.webp?v=2')}
  .hero--company{--hero-img:url('images/hero-company-foam-800.webp?v=4')}
  /* Die Mobilfassungen sind selbst schon aufs Motiv geschnitten (siehe
     tools/crop-hero-800.mjs), deshalb faellt die Verschiebung von oben hier
     wieder weg — sonst wanderte der Ausschnitt ein zweites Mal. */
  .hero .bg{background-position:center}
  /* on a phone the text covers the whole picture, so the sideways gradient has
     no quiet side left to work with: darken evenly instead */
  .hero .scrim{background:linear-gradient(180deg,rgba(10,32,48,.74),rgba(10,32,48,.66))}
  .hero--company .scrim{background:linear-gradient(180deg,rgba(10,32,48,.76),rgba(10,32,48,.68))}
}

/* Applications is the second hero that ships a 2x pair. Its rules have to sit AFTER
   the mobile block above: same selector, same specificity, so the later one wins.
   The homepage rules get away with living further up because their selector
   (.hero:not([class*="hero--"])) is more specific than the plain .hero above. */
@media(min-resolution:1.5dppx) and (min-width:601px){
  .hero--apps{--hero-img:url('images/hero-apps@2x.webp?v=8')}
}
@media(min-resolution:1.5dppx) and (max-width:600px){
  .hero--apps{--hero-img:url('images/hero-apps-800@2x.webp?v=9')}
}

/* mobile menu: animated overlay panel */
#m{display:block;position:fixed;top:0;right:0;bottom:0;width:min(320px,85vw);background:#fff;box-shadow:-18px 0 50px -20px rgba(10,25,45,.4);padding:96px var(--s-6) var(--s-6) !important;z-index:60;transform:translateX(105%);transition:transform .32s cubic-bezier(.4,0,.2,1);visibility:hidden}
#m.open{transform:translateX(0);visibility:visible}
#m a{font-family:'Sora',sans-serif;font-weight:600;font-size:var(--fs-h4);color:var(--ink);border-bottom:1px solid var(--line)}
#m a[aria-current="page"]{color:var(--h2-text);box-shadow:inset 3px 0 0 var(--h2);padding-left:var(--stack-item)}
.menu-btn{z-index:70;position:relative;width:44px;height:44px;display:none;flex-direction:column;align-items:center;justify-content:center;gap:5px}
@media(max-width:900px){.menu-btn{display:flex}}
.menu-btn span{display:block;width:22px;height:2px;background:var(--navy);border-radius:2px;transition:transform .28s,opacity .2s}
.menu-btn[aria-expanded="true"] span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.menu-btn[aria-expanded="true"] span:nth-child(2){opacity:0}
.menu-btn[aria-expanded="true"] span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
.menu-backdrop{position:fixed;inset:0;background:rgba(10,25,45,.35);opacity:0;pointer-events:none;transition:opacity .3s;z-index:55}
.menu-backdrop.open{opacity:1;pointer-events:auto}
