/* Layout and components. Use the variables from tokens.css, never raw values.
   Section order follows _layouts/onepage.html: header · hero · how we work · solutions · cta · who we are · footer. */

/* ---- Base ---- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-padding-top: 6rem; scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; /* footer stays at the bottom on short pages (legal, 404) */
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-weight: var(--fw-regular);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  overflow-x: hidden;
}
h1, h2, h3, h4 { font-family: var(--font-display); font-weight: var(--fw-medium); margin: 0; }
.hero__title, .section-head h2, .platform-hub__title, .cta-band h2, .prose h1 { font-weight: var(--fw-regular); } /* titles at 400, as on UrbanDataLab */
p { margin: 0; }
a { color: var(--color-accent); }
a:hover { color: var(--color-text); }
:focus-visible { outline: 3px solid var(--color-focus); outline-offset: 3px; border-radius: 2px; }
img { max-width: 100%; height: auto; display: block; }
.wrap { max-width: var(--wrap-max); margin: 0 auto; padding: 0 var(--gutter); }
.wrap--narrow { max-width: 46rem; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.skip-link {
  position: absolute; left: var(--gutter-mobile); top: -100px; z-index: 100;
  padding: .75rem 1rem; background: var(--color-accent); color: var(--color-accent-contrast);
  border-radius: var(--radius); text-decoration: none;
}
.skip-link:focus { top: var(--gutter-mobile); color: var(--color-accent-contrast); }
[hidden] { display: none !important; }

/* ---- Shared ---- */
.eyebrow {
  font-weight: var(--fw-medium);
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--color-accent);
}
.lede { font-size: var(--fs-lede); line-height: var(--lh-lede); color: var(--color-text-lede); }
.prose p + p { margin-top: 1em; }
.prose p { text-wrap: pretty; }

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--btn-height); padding: 0 40px;
  border-radius: var(--radius);
  border: var(--btn-border) solid transparent;
  font-family: var(--font-body); font-weight: var(--fw-bold); font-size: var(--fs-body); line-height: 1.2;
  text-decoration: none; text-align: center;
  transition: background-color .15s, color .15s, border-color .15s;
}
.btn--small { min-height: var(--btn-height-small); padding: 0 22px; font-size: var(--fs-nav); }
.btn--primary { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-accent-contrast); }
.btn--primary:hover { background: var(--color-accent-hover); border-color: var(--color-accent-hover); color: var(--color-accent-contrast); }
.btn--secondary { background: transparent; border-color: var(--color-text); color: var(--color-text); }
.btn--secondary:hover { background: var(--color-text); color: var(--color-accent-contrast); }
.btn--inverse { min-height: var(--btn-height-band); padding: 0 40px; background: var(--color-bg); border-color: var(--color-bg); color: var(--color-text); }
.btn--inverse:hover { background: var(--color-text); border-color: var(--color-text); color: var(--color-band-text); }
.btn--inverse:focus-visible { outline-color: var(--color-focus-inverse); }
.actions { display: flex; gap: 16px; flex-wrap: wrap; margin: 0; }

.section { padding: var(--section-space) 0; }
.section--alt { background: var(--color-bg-alt); }
.section-head { display: flex; flex-direction: column; gap: 20px; }
.section-head h2 {
  font-size: var(--fs-h2); line-height: var(--lh-h2); letter-spacing: var(--ls-h2);
  max-width: var(--measure-h2); text-wrap: balance;
}
.section-head--center { text-align: center; align-items: center; }
.media { overflow: hidden; border-radius: var(--radius-media); }
/* title left, text right (How we work, Who we are) */
.split {
  display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: 64px; align-items: start;
}
.split__body { max-width: var(--measure-text); }

/* ---- Header ---- */
.site-header {
  position: sticky; top: 0; z-index: 10;
  background: var(--color-header-bg);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--color-line-soft);
}
.site-header__inner {
  display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap;
  padding-top: var(--header-pad); padding-bottom: var(--header-pad);
}
.brand {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--font-display); font-weight: var(--fw-bold); font-size: var(--fs-brand);
  color: var(--color-text); text-decoration: none;
}
.brand:hover { color: var(--color-text); }
.brand__mark {
  width: var(--brand-mark); height: var(--brand-mark); flex: none;
  background: var(--color-accent);
  clip-path: polygon(40% 0, 100% 0, 60% 100%, 0 100%);
}
.site-nav { display: flex; gap: 36px; flex-wrap: wrap; font-size: var(--fs-nav); }
.site-nav a { color: var(--color-text-soft); text-decoration: none; }
.site-nav a:hover { color: var(--color-accent); }
.site-header__end { display: flex; align-items: center; gap: 20px; }
.lang-switch { display: flex; gap: 10px; font-size: var(--fs-label); letter-spacing: .04em; }
.lang-switch a { color: var(--color-text-muted); text-decoration: none; }
.lang-switch a:hover { color: var(--color-accent); }
.lang-switch a[aria-current="page"] { color: var(--color-text); font-weight: var(--fw-medium); }

/* ---- UrbanDataLab banner (home page only: under the header and above the footer; scrolls with the page) ---- */
.udl-banner { background: var(--color-udl); color: var(--color-udl-text); font-size: var(--fs-udl); line-height: 1.3; }
.udl-banner__inner {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 4px 12px;
  min-height: var(--udl-banner-height); margin-top: 0; margin-bottom: 0; padding-top: 8px; padding-bottom: 8px; text-align: center;
}
.udl-banner a { display: inline-flex; align-items: center; gap: 6px; color: var(--color-udl-text); font-weight: var(--fw-medium); text-decoration: none; }
.udl-banner a:hover { color: var(--color-udl-text); text-decoration: underline; }
.udl-banner :focus-visible { outline-color: var(--color-focus-inverse); }
.udl-banner__tagline { margin-left: 12px; }   /* UDL's sentence after the link (MEMORY.md §7.4); desktop only */
.udl-banner__arrow { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }

/* ---- Hero: text left, tree image right ---- */
.hero { position: relative; overflow: hidden; }
.hero__inner {
  position: relative;
  padding-top: var(--hero-space-top); padding-bottom: var(--hero-space-bottom);
}
.hero__inner--image {
  display: grid; grid-template-columns: minmax(0, var(--hero-text-ratio)) minmax(0, 1fr); gap: 48px; align-items: center;   /* text a bit wider than the tree so the green title phrase fits on 2 lines (MEMORY.md §8.2, §8.3) */
}
.hero__text { display: flex; flex-direction: column; gap: 28px; }
.hero__image { width: 100%; max-width: var(--hero-image-max); justify-self: end; border-radius: var(--radius-media); } /* 18px image radius, as on UrbanDataLab */
/* Animated tree (MEMORY.md §8.2): starts as the photo only; the mesh then grows from the left edge to the right
   (left of the split = mesh, right = photo; no visible line, MEMORY.md §8.2) until the whole tree is mesh, then goes back. Loops.
   --split is a registered property so it can be animated; browsers without @property show a still 50/50 split.
   Desktop/tablet: 5% bigger than its column, growing into the right margin (left edge stays aligned). */
@property --split { syntax: "<percentage>"; inherits: true; initial-value: 50%; }
.hero-reveal {
  position: relative; overflow: hidden; --split: 50%;
  width: calc(100% * var(--hero-image-grow)); max-width: calc(var(--hero-image-max) * var(--hero-image-grow)); justify-self: start;
  animation: hero-reveal var(--hero-reveal-duration) ease-in-out infinite alternate;
}
.hero-reveal img { display: block; width: 100%; height: auto; }
.hero-reveal__mesh { position: absolute; inset: 0; clip-path: inset(0 calc(100% - var(--split)) 0 0); }
@keyframes hero-reveal { 0%, 12% { --split: 0%; } 88%, 100% { --split: 100%; } }
.hero__title {
  font-size: var(--fs-h1); line-height: var(--lh-h1); letter-spacing: var(--ls-h1);
  max-width: var(--measure-hero); text-wrap: balance;
}
.hero__title-accent { display: block; color: var(--color-accent); font-weight: var(--fw-medium); }   /* 2nd phrase: brand green, a bit bolder (500 vs 400), always on its own line (MEMORY.md §8.3) */
.hero__subtitle {
  font-size: var(--fs-hero-sub); line-height: var(--lh-lede); color: var(--color-text-lede);
  max-width: var(--measure-text); text-wrap: pretty;
}
.hero__offer {
  font-size: var(--fs-offer); line-height: var(--lh-h3); font-weight: var(--fw-medium);
  color: var(--color-accent);
}
.hero .actions { margin-top: 8px; }

/* ---- How we work: title · platform intro · hub · button (centred) · steps with detail paragraphs (MEMORY.md §7.6) ---- */
/* platform hub: modules left and right, video of the Core Data Viewer in the centre */
.platform-hub { margin-top: 56px; }
.platform-hub:first-child { margin-top: 0; }
.platform-hub__head { margin-bottom: 56px; }
.platform-hub__title {
  font-size: var(--fs-h3-block); line-height: var(--lh-h2-band);
  max-width: var(--measure-h2); text-wrap: balance;
}
.platform-hub__head .lede { max-width: var(--measure-text); }
.hub {
  display: grid; align-items: stretch;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.55fr) minmax(0, 1fr);
  grid-template-areas: "left frame right" ". core .";
  column-gap: var(--hub-gap); row-gap: 24px;
}
.hub__frame {
  grid-area: frame; position: relative; align-self: center;
  aspect-ratio: var(--video-ratio);
  background: var(--color-frame);
  box-shadow: var(--shadow-media);
}
.hub__frame:empty {   /* placeholder when no video/poster is set: faint dashboard grid */
  background-image:
    linear-gradient(var(--color-frame-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--color-frame-line) 1px, transparent 1px);
  background-size: 100% 25%, 20% 100%;
}
.hub__frame img, .hub__video { display: block; width: 100%; height: 100%; object-fit: contain; } /* whole video/poster, never cropped */
.hub__core { grid-area: core; text-align: center; max-width: var(--measure-text); justify-self: center; }
.hub__modules {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; justify-content: space-around; gap: 24px;
}
.hub__modules--left { grid-area: left; }
.hub__modules--right { grid-area: right; }
.hub__module { position: relative; display: flex; align-items: flex-start; gap: 14px; }
.hub__modules--left .hub__module { flex-direction: row-reverse; text-align: right; }
/* thin connector line from the icon towards the screenshot */
.hub__module::after {
  content: ""; position: absolute; top: calc(var(--icon-size) / 2);
  width: calc(var(--hub-gap) - 8px); border-top: 1px solid var(--color-connector);
}
.hub__modules--left .hub__module::after { left: calc(100% + 4px); }
.hub__modules--right .hub__module::after { right: calc(100% + 4px); }
.hub__icon {
  flex: none; width: var(--icon-size); height: var(--icon-size);
  fill: none; stroke: var(--color-accent); stroke-width: var(--icon-stroke); stroke-linejoin: round; stroke-linecap: round;
}
.hub__text { display: flex; flex-direction: column; gap: 4px; }
.hub__name { font-size: var(--fs-row-name); line-height: var(--lh-h3); }
.hub__module p, .hub__core p { font-size: var(--fs-item); line-height: var(--lh-body); color: var(--color-text-muted); }
.hub__core .hub__name { margin-bottom: 4px; }
.hub__core p { text-wrap: balance; }

/* e-mail button: centred, directly below the hub */
.how-we-work__cta { margin-top: 56px; justify-content: center; }
/* numbered steps 01–03 (big light accent numbers, as in the wireframe); 3 columns, aligned at the top;
   each column = number · title · short text · detail paragraph in lede type */
.steps {
  list-style: none; margin: 56px 0 0; padding: 0;   /* same 56px rhythm as title → hub → button */
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 48px; align-items: start;
}
.step { display: flex; flex-direction: column; gap: 10px; }
.step__num { font-weight: var(--fw-light); font-size: var(--fs-step-num); line-height: 1; color: var(--color-accent); }
.step__title { font-size: var(--fs-h3); line-height: var(--lh-h3); }
.step p { font-size: var(--fs-item); line-height: var(--lh-body); color: var(--color-text-muted); }
.step p.step__detail { margin-top: 14px; font-size: var(--fs-step-detail); line-height: var(--lh-lede); color: var(--color-text-lede); text-wrap: pretty; }

/* ---- Solutions: card grid, one card per combination (card B, MEMORY.md §7.7); 3 · 2 · 1 per row ---- */
.solutions__head { margin-bottom: 48px; }
.combo-cards {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px;
}
.combo-card {
  display: flex; flex-direction: column; gap: 8px;
  padding: 32px; border-radius: var(--radius); background: var(--color-bg-alt);
}
.combo-card__name { font-size: var(--fs-row-name); font-weight: var(--fw-medium); line-height: var(--lh-h3); }
.combo-card__text { font-size: var(--fs-item); line-height: var(--lh-body); color: var(--color-text-muted); }
.combo-card__modules {   /* pushed to the bottom so the module lines align across a row */
  margin-top: auto; padding-top: 16px; border-top: 1px solid var(--color-line-alt);
  font-size: var(--fs-item); line-height: var(--lh-body); color: var(--color-text-soft);
}
.combo-card__label { margin-right: 6px; font-weight: var(--fw-medium); color: var(--color-accent); }

/* ---- CTA band ---- */
.cta-band { background: var(--color-band); color: var(--color-band-text); }
.cta-band__inner {
  display: flex; align-items: center; justify-content: space-between; gap: 40px; flex-wrap: wrap;
  padding-top: var(--band-space); padding-bottom: var(--band-space);
}
.cta-band h2 {
  font-size: var(--fs-h2-band); line-height: var(--lh-h2-band); letter-spacing: var(--ls-h2-band);
  max-width: var(--measure-band); text-wrap: balance;
}

/* ---- Who we are ---- */
.values__title { margin-top: 64px; padding-top: 32px; border-top: 1px solid var(--color-line); font-size: var(--fs-h3); line-height: var(--lh-h3); }
.values {
  list-style: none; margin: 64px 0 0; padding: 32px 0 0;
  border-top: 1px solid var(--color-line);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); gap: 32px 48px;
}
.values__title + .values { margin-top: 24px; padding-top: 0; border-top: 0; }
.value { display: flex; align-items: baseline; gap: 14px; font-size: var(--fs-value); line-height: var(--lh-h3); }
.value__mark {   /* brand parallelogram */
  flex: none; width: var(--value-mark); height: var(--value-mark);
  background: var(--color-accent);
  clip-path: polygon(40% 0, 100% 0, 60% 100%, 0 100%);
}
.people {
  list-style: none; margin: 72px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 48px;
}
.person { display: grid; grid-template-columns: var(--photo-size) minmax(0, 1fr); gap: 28px; align-items: start; }
.person__photo { aspect-ratio: 1; background: var(--color-placeholder); }
.person__photo img { width: 100%; height: 100%; object-fit: cover; }
.person__photo--round { border-radius: 50%; background: none; }   /* real photo: round, no placeholder grey behind the transparent corners */
.person__text { display: flex; flex-direction: column; gap: 8px; }
.person__name { font-size: var(--fs-h3); line-height: var(--lh-h3); }
.person__role { font-size: var(--fs-item); font-weight: var(--fw-medium); color: var(--color-accent); }
.person__bio { font-size: var(--fs-item); line-height: var(--lh-body); color: var(--color-text-muted); }
.person__link { margin-top: 4px; font-size: var(--fs-item); font-weight: var(--fw-medium); }

/* ---- Footer: 4 columns (as on urbandatalab.ch); the UrbanDataLab banner sits just above it on the home page ---- */
.site-footer { background: var(--color-footer); color: var(--color-footer-text); font-size: var(--fs-small); }
.site-footer a { color: var(--color-footer-text); text-decoration: none; }
.site-footer a:hover { color: var(--color-accent-contrast); text-decoration: underline; }
.site-footer :focus-visible { outline-color: var(--color-focus-inverse); }
.site-footer__grid {
  display: grid; grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr)); gap: 40px;
  padding-top: var(--gutter); padding-bottom: var(--gutter);
}
.site-footer__col { display: flex; flex-direction: column; gap: 14px; align-items: flex-start; }
.site-footer__title {
  font-size: var(--fs-footer-title); font-weight: var(--fw-medium); line-height: 1.3;
  color: var(--color-footer-title);
}
.site-footer__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; font-size: var(--fs-footer-link); line-height: 1.3; }
.brand--inverse, .brand--inverse:hover { color: var(--color-footer-strong); font-size: var(--fs-brand-footer); }
.site-footer .brand--inverse, .site-footer .brand--inverse:hover { color: var(--color-footer-strong); text-decoration: none; }
.brand--inverse .brand__mark { width: var(--brand-mark-footer); height: var(--brand-mark-footer); background: var(--color-footer-strong); }

main { flex: 1 0 auto; }   /* fills the space between header and footer (see body) */

/* ---- Legal pages / 404 ---- */
.prose h1 { font-size: var(--fs-h2); line-height: var(--lh-h2); letter-spacing: var(--ls-h2); margin-bottom: 32px; }
.prose h2 { font-size: var(--fs-h3); margin: 2em 0 .5em; }
.wrap--narrow.prose h1 { text-align: center; } /* legal pages + 404: centred title, as on urbandatalab.ch/imprint */
.wrap--narrow.prose p { font-size: var(--fs-lede); line-height: var(--lh-body); } /* legal pages + 404: text 20px, as on urbandatalab.ch/imprint (t-text_md) */

/* ---- Medium screens ---- */
@media (max-width: 960px) {
  .split { grid-template-columns: 1fr; gap: 32px; }
  .udl-banner__tagline { display: none; }   /* banner stays one line on tablets and phones */
  /* hub: screenshot + caption on top, modules below in two columns, no connectors */
  .hub { grid-template-columns: 1fr 1fr; grid-template-areas: "frame frame" "core core" "left right"; row-gap: 32px; column-gap: 40px; }
  .hub__modules { justify-content: flex-start; }
  .hub__modules--left .hub__module { flex-direction: row; text-align: left; }
  .hub__module::after { display: none; }
  /* steps stacked (the detail paragraphs in lede type are too long for 3 narrow columns), readable line length */
  .steps { grid-template-columns: 1fr; gap: 48px; max-width: var(--measure-text); }
  .combo-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .people { grid-template-columns: 1fr; }
  .site-footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---- Phones ---- */
@media (max-width: 640px) {
  :root { --gutter: var(--gutter-mobile); --section-space: var(--section-space-mobile); --band-space: var(--section-space-mobile); --hero-space-top: 64px; --hero-space-bottom: 72px; --header-pad: 12px; }
  html { scroll-padding-top: 8rem; }
  /* rows: brand + button, then nav (full width), then languages when shown */
  .site-header__inner { display: grid; grid-template-columns: 1fr auto; grid-template-areas: "brand cta" "nav nav"; gap: 10px 16px; }
  .site-header__end { display: contents; }
  .site-header .brand { grid-area: brand; }
  .site-header .lang-switch { grid-column: 1 / -1; }
  .site-nav { grid-area: nav; gap: 20px; }
  .site-header .btn { grid-area: cta; justify-self: end; }
  .hero__inner--image { grid-template-columns: 1fr; gap: 40px; }   /* tree below the buttons, smaller */
  .hero__text { gap: 22px; }
  .hero__image { max-width: var(--hero-image-max-mobile); justify-self: start; }
  .hero-reveal { width: 100%; }   /* phones: no growth into the margin */
  .actions .btn { flex: 1 1 100%; }
  .cta-band .btn { width: 100%; }
  .how-we-work__head, .platform-hub__head { text-align: left; align-items: flex-start; } /* left, like the video caption and modules below */
  .platform-hub { margin-top: 40px; }
  .platform-hub__head { margin-bottom: 40px; }
  .hub { grid-template-columns: 1fr; grid-template-areas: "frame" "core" "left" "right"; row-gap: 24px; }
  .hub__core { text-align: left; justify-self: start; }
  .how-we-work__cta { margin-top: 40px; }
  .steps { gap: 40px; margin-top: 40px; }
  .solutions__head { margin-bottom: 32px; }
  .combo-cards { grid-template-columns: 1fr; gap: 16px; }
  .combo-card { padding: 24px; }
  .values, .values__title { margin-top: 48px; }
  .values__title + .values { margin-top: 20px; }
  .people { margin-top: 48px; gap: 40px; }
  .person { grid-template-columns: 1fr; gap: 20px; }
  .person__photo { width: var(--photo-size); }
  .site-footer__grid { grid-template-columns: 1fr; gap: 32px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; animation: none !important; }
}
