/* Landing page link-to-business-batiment.fr — temporary standalone page. */

/* Breakpoints are expressed in em, not px: they then follow the visitor's
   default font size, so someone browsing at 200% text size gets the roomier
   layout of the tier below instead of a cramped desktop grid.
   30em = 480px, 48em = 768px, 64em = 1024px at the 16px default. */

/* ---------- Fonts ---------- */

/* Inter ships as a single variable file covering the whole weight axis:
   one request instead of two, and no synthetic bold. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/inter-latin.woff2') format('woff2');
}

/* ---------- Design tokens ---------- */

:root {
  /* Palette sampled from design/maquette.png. */
  --color-accent: #ee5b04;
  --color-accent-dark: #d94f02;
  /* Small orange text on light backgrounds: the brand orange only reaches
     3.1:1, below the 4.5:1 AA needs for body copy. This darker shade holds
     the hue and clears 4.5:1 on every light surface, and on white. Fills,
     and text at 24px or more, keep --color-accent. */
  --color-accent-deep: #be4903;
  --color-ink: #152c42;
  --color-body: #3a4654;
  --color-taupe: #8a7b6d;
  /* White button labels on taupe need 4.5:1; the brand taupe gives 4.09:1. */
  --color-taupe-deep: #7c6f62;
  --color-surface: #f5f6f5;
  --color-surface-warm: #f5f3ef;
  /* Light zone of the contact band, sampled at #e3e2e0 on the mockup. */
  --color-surface-shade: #e3e2e0;
  --color-card: #ffffff;
  --color-footer: #424242;
  --color-rule: #dde1e3;

  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;

  /* Fluid type scale, calibrated on the 1366px mockup. */
  /* Calibrated on the retained headline, which runs 11 words where the mockup
     ran 7: at the mockup's 3.25rem it wrapped onto seven lines and pushed the
     hero visual off the fold. */
  --text-h1: clamp(1.75rem, 1.1rem + 2.6vw, 2.75rem);
  --text-h2: clamp(1.5rem, 1.07rem + 1.85vw, 2.125rem);
  --text-h3: clamp(1.0625rem, 1.02rem + 0.19vw, 1.125rem);
  --text-eyebrow: 0.875rem;
  --text-body: 1rem;
  --text-stat: clamp(1.75rem, 1.41rem + 1.48vw, 2.25rem);

  /* 4px rhythm. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 2.5rem;
  --space-8: 3rem;
  --space-9: 4rem;
  --space-10: 5rem;
  --space-11: 6rem;
  --space-12: 8rem;

  --radius-card: 1.5rem;
  --radius-pill: 999px;
  --container: 1280px;
  --gutter: clamp(1rem, 4vw, 2.5rem);
  /* Panel padding is capped against the viewport: a rem value doubles with
     the browser's text-zoom setting, which pushed panels wider than their
     container at 200%. */
  --pad-card: clamp(1rem, 3vw, 2rem);
}

/* ---------- Reset ---------- */

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

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--color-surface);
  color: var(--color-body);
  font-family: var(--font-sans);
  font-size: var(--text-body);
  line-height: 1.6;
}

h1,
h2,
h3 {
  margin: 0;
  color: var(--color-ink);
  line-height: 1.15;
  text-wrap: balance;
  /* Only kicks in when a single word genuinely cannot fit. */
  overflow-wrap: break-word;
}

h1 { font-size: var(--text-h1); }
h2 { font-size: var(--text-h2); }
h3 { font-size: var(--text-h3); }

p {
  margin: 0;
}

img,
svg {
  display: block;
  max-width: 100%;
  height: auto;
}

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

a {
  color: inherit;
}

/* ---------- Layout ---------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* ---------- Accessibility ---------- */

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: var(--space-4);
  z-index: 100;
  padding: var(--space-3) var(--space-4);
  background: var(--color-ink);
  color: #fff;
  border-radius: var(--space-2);
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: translateY(0);
}

/* Two-tone on purpose. No single colour clears 3:1 against every surface this
   page uses — white cards, the accent panel, the taupe band and the near-black
   footer. The white inner ring carries dark backgrounds, the ink outer ring
   carries light ones, so one of the two is always visible. */
:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 0;
  box-shadow: 0 0 0 4px var(--color-ink);
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- Components ---------- */

.section {
  padding-block: var(--space-9);
  background: var(--color-surface);
}

.section--warm {
  background: var(--color-surface-warm);
}

.card {
  background: var(--color-card);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.eyebrow {
  margin-bottom: var(--space-3);
  color: var(--color-accent-deep);
  font-size: var(--text-eyebrow);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Buttons. Minimum target 44px per the accessibility requirement. */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;
  /* max-width and a viewport-capped inline padding keep a button inside its
     container when the browser's text-zoom doubles every rem. */
  max-width: 100%;
  padding: var(--space-3) clamp(0.75rem, 3vw, 1.5rem);
  border: 0;
  border-radius: var(--space-2);
  font: inherit;
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.btn::after {
  content: '→';
  font-weight: 400;
}

/* Filled buttons carry white 16px labels, so they need 4.5:1, not the 3:1 of
   large text. The brand orange gives 3.42:1 and the brand taupe 4.09:1, both
   short; these darker shades of the same hues clear the bar. The undarkened
   colours stay in use for decorative fills, which carry no text. */
.btn--primary {
  background: var(--color-accent-deep);
  color: #fff;
}

.btn--primary:hover {
  background: #a74003;
}

.btn--secondary {
  background: var(--color-taupe-deep);
  color: #fff;
}

.btn--secondary:hover {
  background: #685c52;
}

.btn--ghost {
  padding-inline: 0;
  min-height: 0;
  background: none;
  color: var(--color-accent-deep);
}

.btn[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Visible marker for content that is not available yet.
   Never replace it with invented copy.
   It resets the display typography it may be nested in (a h1, an eyebrow):
   a marker must stay a small chip, never take on heading size or uppercasing,
   otherwise it wrecks the very layout it sits in. The full arbitration note
   lives in an HTML comment next to it. */
.todo {
  display: inline-block;
  max-width: 100%;
  padding: 0.15em 0.5em;
  background: #fff3a3;
  color: #6b5600;
  border: 1px dashed #b39700;
  border-radius: 0.25em;
  font-size: 0.8125rem;
  font-weight: 700;
  font-style: normal;
  line-height: 1.4;
  letter-spacing: normal;
  text-transform: none;
  vertical-align: middle;
}

/* Image placeholder. Holds the exact aspect ratio of the final asset so
   that dropping the real image in causes no layout shift. */
.ph {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  background-color: #e4e7e9;
  background-image: repeating-linear-gradient(
    45deg,
    rgba(21, 44, 66, 0.07) 0 8px,
    transparent 8px 16px
  );
  color: #56616d;
  font-size: 0.8125rem;
  font-weight: 700;
  text-align: center;
}

.ph::after {
  content: attr(data-ph);
  padding: var(--space-2);
}

/* ---------- Utilities ---------- */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- Site header ---------- */

.site-header {
  background: var(--color-card);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  min-height: 80px;
}

.site-header__logo {
  flex: 0 0 auto;
  text-decoration: none;
}

.ph--logo {
  width: 230px;
  aspect-ratio: 230 / 48;
}

/* Hidden until the script takes over: without JavaScript the navigation is
   already open, so a burger would be a visible control that does nothing while
   announcing aria-expanded="false" over an expanded menu. */
.site-header__burger {
  display: none;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.site-header__burger-bar,
.site-header__burger-bar::before,
.site-header__burger-bar::after {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--color-ink);
}

.site-header__burger-bar::before,
.site-header__burger-bar::after {
  content: '';
  position: relative;
}

.site-header__burger-bar::before { top: -8px; }
.site-header__burger-bar::after  { top: 6px; }

.site-nav__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
}

.site-nav__list a {
  text-decoration: none;
}

.site-nav__list a:hover {
  color: var(--color-accent);
}

/* Below 1024px the navigation is a panel toggled by the burger.
   Without JavaScript the panel stays open and stacked: the page remains
   fully usable. */
@media (max-width: 63.9375em) {
  .site-header__inner {
    flex-wrap: wrap;
  }

  .site-nav {
    flex: 1 0 100%;
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding-bottom: var(--space-5);
  }

  .site-nav__list {
    flex-direction: column;
    gap: 0;
  }

  .site-nav__list a {
    display: block;
    padding-block: var(--space-3);
    min-height: 44px;
  }

  /* Collapsed only once JavaScript has taken control. */
  .js .site-nav[hidden] {
    display: none;
  }

  .js .site-header__burger {
    display: grid;
  }
}

@media (min-width: 64em) {
  .js .site-header__burger {
    display: none;
  }

  .site-nav {
    display: flex;
    align-items: center;
    gap: var(--space-7);
  }
}


/* ---------- Media slots ---------- */

/* The shape and the ratio live on the __media container, never on the .ph
   placeholder: the placeholder is deleted the day the real image lands, and a
   radius or an aspect-ratio declared on it would vanish with it — taking the
   hero arch and the culture circle along, and shifting
   the layout. Whatever fills the slot inherits the rounding and covers the box. */
.hero__media,
.culture__media,
.cas__media {
  position: relative;
  overflow: hidden;
}

/* Taken out of flow on purpose. Left in flow, a slot whose height is set by its
   row would have the image's own ratio push that row taller the day the photo
   replaces the placeholder — a 5px shift, measured. Out of flow, whatever
   fills the slot can never resize it. */
.hero__media > *,
.culture__media > *,
.cas__media > * {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  object-fit: cover;
}

/* ---------- Hero ---------- */

.hero {
  padding-block: var(--space-8) var(--space-9);
  background: var(--color-surface);
}

.hero__inner {
  display: grid;
  gap: var(--space-7);
}

.hero__lead {
  max-width: 44rem;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  align-items: center;
}

.hero__media {
  position: relative;
  aspect-ratio: 756 / 390;
  border-radius: var(--radius-card) 0 0 var(--radius-card);
}

.ph--hero {
  /* Shape and ratio come from .hero__media. */
  aspect-ratio: auto;
}

/* Decorative orange arc echoing the mockup. Purely presentational.
   It stays inside its parent: hanging it outside widened the document by
   20px, which showed up as a 4px horizontal overflow at 320px. */
.hero__media::after {
  content: '';
  position: absolute;
  inset-block: 0;
  right: 0;
  width: 4rem;
  border-radius: 0 50% 50% 0 / 0 50% 50% 0;
  background: var(--color-accent);
  pointer-events: none;
}

.hero__targets {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  font-weight: 700;
  letter-spacing: 0.04em;
}

.hero__targets-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
}

/* Single long words — CONSTRUCTIF, PRESCRIPTEURS — outgrow a 320px column once
   the visitor doubles their text size, and uppercase plus letter-spacing makes
   them wider still. */
.eyebrow,
.hero__targets-list li {
  overflow-wrap: break-word;
}

.hero__targets-all {
  font-weight: 400;
}

/* Large text (>=32px bold here), so the brand orange's 3.16:1 clears the 3:1
   that WCAG asks of large text. Small orange text uses --color-accent-deep. */
.hero__accent {
  color: var(--color-accent);
}

@media (min-width: 64em) {
  .hero__targets-list {
    flex-direction: column;
    gap: var(--space-2);
  }
}

@media (min-width: 64em) {
  /* The retained headline runs six lines, so centring the visual against the
     whole block left it stranded low. It now tops out level with the headline,
     and the lead and the buttons run full width underneath — which also gives
     the long paragraph a comfortable measure instead of a narrow column.
     Source order stays reading order: headline, lead, buttons, visual, targets. */
  .hero__inner {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr) auto;
    grid-template-areas:
      'head    media   targets'
      'lead    lead    lead'
      'actions actions actions';
    align-items: start;
    gap: var(--space-6) var(--space-8);
  }

  /* Spans the full grid width but keeps a readable measure. The paragraph wraps
     in whole lines, so the measure is quantised: at 62rem and beyond it sits on
     two lines of ~125 characters, well past the ~90 where the eye starts losing
     its place on the return sweep; 58rem is the widest value that breaks to
     three lines of ~83. Centred, so the band still reads as full width. */
  .hero__lead {
    max-width: 58rem;
    margin-inline: auto;
  }

  .hero__actions {
    justify-content: center;
  }

  .hero__head    { grid-area: head; }

  /* Stretched rather than left at its own ratio: the visual then squares off
     against the headline top and bottom instead of leaving a gap below it.
     The delivered image is centre-cropped by object-fit: cover. */
  .hero__media {
    align-self: stretch;
    aspect-ratio: auto;
  }
  .hero__lead    { grid-area: lead; }
  .hero__actions { grid-area: actions; }
  .hero__media   { grid-area: media; }

  /* Centred against the visual, not against the whole hero: the targets sit in
     the first row only, and the visual is stretched to that row's height. */
  .hero__targets {
    grid-area: targets;
    align-self: center;
  }
}

/* ---------- Mission ---------- */

/* Not in the mockup. Built from what the copy already does: four of the five
   accroches in contenu.md open on « Être constructif, c'est… ». Setting that
   opening in the accent colour turns the repetition into a thread the eye can
   follow from one section to the next, using the existing tokens only.
   The section is centred and narrow, so it reads as a statement rather than as
   a second content card competing with « Notre culture bâtiment » below it. */
.mission__inner {
  max-width: 54rem;
  text-align: center;
}

.mission__inner .eyebrow::before {
  content: '';
  display: block;
  width: 3rem;
  height: 3px;
  margin: 0 auto var(--space-5);
  border-radius: var(--radius-pill);
  background: var(--color-accent);
}

.mission__text {
  margin-top: var(--space-5);
  /* Centred running text stops being comfortable past about three lines, and on
     a phone this paragraph runs to eight. The statement stays centred, the body
     reads ragged-right. */
  text-align: left;
}

@media (min-width: 48em) {
  .mission__text {
    text-align: center;
  }
}

.mission__inner .btn {
  margin-top: var(--space-6);
}

/* The recurring opening of the accroches. At h2 size it is large text, so the
   brand orange's 3.1:1 clears the 3:1 WCAG asks there. */
.accroche__lead {
  color: var(--color-accent);
}

/* ---------- Culture ---------- */

.culture__card {
  display: grid;
  gap: var(--space-6);
  padding: var(--pad-card);
}

.culture__card > * {
  min-width: 0;
}

.ph--round {
  /* Shape and ratio come from .culture__media. A delivered image that is not
     square is centre-cropped by object-fit: cover. */
  aspect-ratio: auto;
}

.culture__media {
  position: relative;
  /* Single column below 1024px: left unbounded, a 1:1 circle would take the
     full container width and stand several hundred pixels tall. */
  width: min(100%, 20rem);
  aspect-ratio: 1;
  border-radius: 50%;
}

.culture__media::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 6px solid var(--color-accent);
  clip-path: inset(0 0 0 55%);
  pointer-events: none;
}

.culture__text,
.culture__chain {
  margin-top: var(--space-4);
  max-width: 46rem;
}

.culture__chain {
  font-style: italic;
}

/* ---------- Key figures ---------- */

.stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-5);
  margin: var(--space-6) 0 0;
}

.stats__item {
  padding-left: var(--space-5);
  border-left: 1px solid var(--color-rule);
}

.stats__item:first-child {
  padding-left: 0;
  border-left: 0;
}

.stats__value {
  color: var(--color-accent);
  font-size: var(--text-stat);
  font-weight: 700;
  line-height: 1.1;
}

.stats__label {
  margin: var(--space-2) 0 0;
  font-size: 0.9375rem;
}

@media (min-width: 48em) {
  .stats {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (min-width: 64em) {
  .culture__card {
    grid-template-columns: minmax(0, 0.42fr) minmax(0, 1fr);
    align-items: center;
    padding: var(--space-7);
  }

  .culture__media {
    width: 100%;
  }
}

/* ---------- Expertises ---------- */

.expertises__head {
  display: grid;
  gap: var(--space-5);
  margin-bottom: var(--space-8);
}

.expertises__list {
  display: grid;
  gap: var(--space-7);
}

.expertise__icon {
  position: relative;
  width: 112px;
  margin-bottom: var(--space-5);
}

.ph--icon {
  aspect-ratio: 1;
  border-radius: 50%;
  background-color: var(--color-card);
}

.expertise__title {
  margin-bottom: var(--space-3);
}

.expertises__more {
  margin-top: var(--space-7);
}

@media (min-width: 48em) {
  .expertises__list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 64em) {
  .expertises__head {
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
    gap: var(--space-8);
  }

  .expertises__intro {
    padding-left: var(--space-6);
    border-left: 1px solid var(--color-rule);
  }

  .expertises__list {
    position: relative;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-8);
  }

  /* Decorative timeline joining the three icons. */
  .expertises__list::before {
    content: '';
    position: absolute;
    top: 56px;
    left: 112px;
    right: 0;
    height: 1px;
    background: var(--color-rule);
    z-index: 0;
  }

  .expertise__icon {
    z-index: 1;
  }
}

/* ---------- Défis ---------- */

.defis__intro {
  margin: var(--space-4) 0 var(--space-7);
  max-width: 44rem;
}

.defis__grid {
  display: grid;
  gap: var(--space-5);
}

/* The mockup drew four short cards with a photo each. contenu.md carries seven
   issues written as full paragraphs, and Franck settled the conflict in its
   favour, so the media slot is gone: these cards hold an icon and running text.
   Nothing here sets a height — a paragraph decides its own. */
.defi {
  display: grid;
  grid-template-areas:
    'icon'
    'body';
  gap: var(--space-4);
  align-content: start;
  padding: var(--space-5);
}

.defi__icon { grid-area: icon; }
.defi__body { grid-area: body; }

.ph--icon-sm {
  width: 64px;
  aspect-ratio: 1;
  border-radius: 50%;
  background-color: var(--color-accent);
  background-image: none;
  color: #fff;
}

.defi__body h3 {
  margin-bottom: var(--space-3);
}

.defi__body p + p {
  margin-top: var(--space-3);
}

/* Pull quote carried by the fifth issue in contenu.md. The accent rule sits on
   the inline start edge so it flips with the writing direction. */
.defi__quote {
  margin: var(--space-4) 0 0;
  padding-inline-start: var(--space-4);
  border-inline-start: 3px solid var(--color-accent);
  font-style: italic;
}

@media (min-width: 64em) {
  .defis__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-6);
  }

  /* Seven is odd: the last card would leave a hole beside it. It takes the full
     row instead, and turns its icon and text side by side so the extra width
     reads as a deliberate close rather than a stretched leftover. */
  .defi--wide {
    grid-column: 1 / -1;
    grid-template-areas: 'icon body';
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--space-5);
    align-items: start;
  }

  .defi--wide .defi__body {
    max-width: 58rem;
  }
}

/* ---------- References ---------- */

.references {
  padding-block: var(--space-8);
  background: var(--color-accent);
  color: #fff;
}

/* White on --color-accent measures 3.42:1: enough for WCAG AA large text
   (>=18.66px bold), not for body copy. The mockup sets this eyebrow at ~14px
   white, which fails; enlarging it to 20px bold is the smallest change that
   keeps the mockup's colours and satisfies AA. */
.eyebrow--on-accent {
  color: #fff;
  font-size: 1.25rem;
}

.references__title {
  color: #fff;
}

/* Body copy never sits directly on the accent: ink on white is 14.28:1. */
.references__warning {
  margin-top: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--space-2);
  background: rgba(255, 255, 255, 0.95);
  color: var(--color-ink);
}

.references__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-5);
  align-items: center;
  margin-top: var(--space-7);
}

.ph--logo-client {
  height: 40px;
  background-color: rgba(255, 255, 255, 0.85);
  background-image: none;
  color: var(--color-accent);
}

@media (min-width: 30em) {
  .references__list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 48em) {
  .references__list { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

@media (min-width: 64em) {
  .references__list {
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: var(--space-6);
  }
}

/* ---------- Cas concret ---------- */

.cas__head {
  display: grid;
  gap: var(--space-5);
  margin-bottom: var(--space-7);
}

.cas__intro {
  margin-top: var(--space-4);
  max-width: 44rem;
}

.cas__logo {
  width: 150px;
  height: 40px;
  justify-self: start;
  background-color: var(--color-card);
  color: var(--color-ink);
}

.cas__body {
  display: grid;
  gap: var(--space-6);
}

.cas__media {
  aspect-ratio: 1420 / 780;
  border-radius: var(--radius-card);
}

.cas__issue {
  align-content: start;
}

.cas__subtitle {
  margin-bottom: var(--space-3);
  color: var(--color-accent-deep);
  font-size: var(--text-eyebrow);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.cas__bullets {
  display: grid;
  gap: var(--space-4);
}

.cas__bullets li {
  position: relative;
  padding-left: var(--space-5);
}

.cas__bullets li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.6em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-accent);
}

.cas__results {
  padding: var(--pad-card);
}

/* Second line of the results card on the mockup: the two conversion costs,
   then the audience note, parted by the same hairlines as the figures above. */
.cas__costs {
  display: grid;
  gap: var(--space-5);
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: 1px solid var(--color-rule);
}

.cas__cost-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-5);
  margin: 0;
}

.cas__cost {
  padding-left: var(--space-5);
  border-left: 1px solid var(--color-rule);
}

.cas__cost:first-child {
  padding-left: 0;
  border-left: 0;
}

.cas__cost-value {
  color: var(--color-ink);
  font-size: var(--text-h3);
  font-weight: 700;
}

.cas__cost-label {
  margin: var(--space-1) 0 0;
  font-size: 0.9375rem;
}

.cas__audience {
  font-size: 0.9375rem;
}

@media (min-width: 48em) {
  .cas__costs {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
  }

  .cas__audience {
    padding-left: var(--space-5);
    border-left: 1px solid var(--color-rule);
  }
}

@media (min-width: 48em) {
  .cas__bullets {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-6);
  }
}

@media (min-width: 64em) {
  .cas__head {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
  }

  .cas__logo { justify-self: end; }

  .cas__body {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    gap: var(--space-7);
  }

  /* Both run the full width under the image-and-issue row. */
  .cas__approach,
  .cas__results {
    grid-column: 1 / -1;
  }

  .cas__bullets {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-6);
  }

  /* Centred and capped rather than edge to edge: the four figures would
     drift apart across the full 1280px container. */
  .cas__results {
    width: 100%;
    max-width: 64rem;
    margin-inline: auto;
  }
}

/* ---------- Décryptages (section commented out until content arrives) ---------- */

.decryptages__head {
  display: grid;
  gap: var(--space-5);
  margin-bottom: var(--space-6);
}

.decryptages__intro {
  margin-top: var(--space-4);
  max-width: 48rem;
}

.decryptages__grid {
  display: grid;
  gap: var(--space-5);
}

.ph--article {
  aspect-ratio: 790 / 200;
}

.article__body {
  padding: var(--space-5);
}

.article__meta {
  margin-bottom: var(--space-2);
  color: var(--color-accent-deep);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.article__body h3 {
  margin-bottom: var(--space-3);
}

.article__body .btn {
  margin-top: var(--space-4);
}

@media (min-width: 48em) {
  .decryptages__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 64em) {
  .decryptages__head {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
  }

  .decryptages__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ---------- Contact ---------- */

.ph--logo-mono {
  width: min(250px, 100%);
  aspect-ratio: 250 / 52;
}

.contact {
  background: var(--color-taupe);
  color: #fff;
}

.contact__inner {
  display: grid;
  gap: var(--space-6);
  padding-block: var(--space-7);
}

/* Without this a child's min-content width props the whole grid open, and the
   page gains a horizontal scrollbar — most visibly under browser text-zoom. */
.hero__inner > *,
.contact__inner > *,
.defi > *,
.cas__body > *,
.expertises__head > *,
.expertises__list > *,
.decryptages__head > *,
.decryptages__grid > * {
  min-width: 0;
}

/* White body copy sits on this panel, so it uses the deep accent: the brand
   orange would only give 3.42:1. */
.contact__pitch {
  padding: var(--pad-card);
  border-radius: var(--radius-card);
  background: var(--color-accent-deep);
}

.contact__pitch h2 {
  color: #fff;
  margin-bottom: var(--space-3);
}

.contact__pitch .btn {
  margin-top: var(--space-5);
}

.btn--light {
  background: #fff;
  color: var(--color-accent-deep);
}

.btn--light:hover {
  background: #f1f1f1;
}

.contact__list li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-3);
  align-items: start;
}

.contact__list li + li {
  margin-top: var(--space-4);
}

/* Circle-and-glyph of the mockup's contact rows. The glyph is a Lucide path
   drawn in currentColor, so the circle sets the colour and the icon follows. */
.contact__icon {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1px solid var(--color-rule);
  background: #fff;
  color: var(--color-body);
}

.contact__icon svg {
  width: 16px;
  height: 16px;
}

/* Newsletter: a filled disc with the accent glyph, as the mockup draws it.
   #ee5b04 on this surface clears the 3:1 that non-text contrast asks for. */
.contact__icon--lg {
  width: 64px;
  height: 64px;
  border: 0;
  background: var(--color-surface);
  color: var(--color-accent);
}

.contact__icon--lg svg {
  width: 28px;
  height: 28px;
}

.contact__details,
.contact__newsletter {
  padding: var(--pad-card);
  border-radius: var(--radius-card);
  background: rgba(255, 255, 255, 0.95);
  color: var(--color-body);
}

.contact__newsletter h3 {
  margin-block: var(--space-3);
}

.contact__newsletter .btn {
  margin-top: var(--space-4);
}

/* Secondary contact copy, a notch down like the mockup's, so the address
   line stops breaking into three. */
.contact__list {
  font-size: 0.9375rem;
}

/* Long unbreakable strings (email, domain) must not force a scrollbar. */
.contact__list a,
.contact__list p {
  overflow-wrap: anywhere;
}

/* ---------- Site footer ---------- */

.site-footer {
  background: var(--color-footer);
  color: #fff;
  padding-block: var(--space-5);
  font-size: 0.875rem;
}

.site-footer__inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-4);
}

.site-footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
}

.site-footer__links a {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}

@media (min-width: 64em) {
  .contact__inner {
    grid-template-columns: auto minmax(0, 1.2fr) minmax(0, 0.9fr) minmax(0, 0.7fr);
    align-items: center;
  }
}

/* The band below needs room: at 1024px its headline ran to four lines and the
   address to three. Between 64em and 75em the four cards above hold instead. */
@media (min-width: 75em) {
  /* The mockup draws this band as three fields, not four cards: a taupe panel
     carrying the logo, a wide orange field holding the pitch, and a light zone
     for the details and the newsletter. The two curved fields are painted by
     pseudo-elements, so the markup stays a plain four-cell grid.

     Their widths are measured from the container's content box rather than the
     viewport. Anchored to the viewport they drifted across the columns as the
     window grew past the container, and the logo ended up straddling the taupe
     edge. */
  .contact {
    --edge: calc(max(0px, (100% - var(--container)) / 2) + var(--gutter));
    --content-w: calc(min(100%, var(--container)) - 2 * var(--gutter));
    --overhang: 600px;
    position: relative;
    isolation: isolate;
    overflow: hidden;
    background: var(--color-surface-shade);
    color: var(--color-body);
  }

  /* Both edges are true circular arcs. Tracing the mockup row by row and
     fitting a circle gives r=159px on the taupe and r=233px on the orange, on a
     band 206px tall — circles far taller than the band, which crops them top
     and bottom and leaves a bulge of only 38px and 24px. An elliptical
     border-radius cannot express that: the arc has to come from a box taller
     than the band, cropped by its overflow.

     So each field is a box of height 2r with a radius of r on both right
     corners — a true semicircle, hence a perfect circle — centred on the band and
     left to spill past it.

     Heights are 2r, so the right edge is exactly a semicircle — unless the band
     outgrows that, which it does under the browser's text-zoom: at 32px default
     type it reaches 1794px. The max() lets the box follow, and the field
     degrades to a straight edge with circular corners rather than leaving
     strips of the band uncovered.

     Both boxes also overhang to the left, well past the viewport edge, so each
     stays wider than its own radius; under that the browser scales the radius
     down and flattens the arc back into the ellipse this replaces. */
  .contact::before,
  .contact::after {
    content: '';
    position: absolute;
    top: 50%;
    left: calc(-1 * var(--overhang));
    transform: translateY(-50%);
    z-index: -1;
  }

  /* Orange field, with the warm gradient sampled off the mockup. */
  .contact::before {
    width: calc(var(--overhang) + var(--edge) + 0.577 * var(--content-w));
    height: max(940px, 100%);
    background: linear-gradient(135deg, #df5c0c, #ee7617);
    border-radius: 0 470px 470px 0;
  }

  /* Taupe panel. The white sliver the mockup leaves between the two fields is
     drawn as its right border, so it follows the same arc for free. */
  .contact::after {
    width: calc(var(--overhang) + var(--edge) + 0.182 * var(--content-w));
    height: max(640px, 100%);
    background: var(--color-taupe);
    border-right: 8px solid #fff;
    border-radius: 0 320px 320px 0;
  }

  .contact__inner {
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 2.95fr) minmax(0, 1.75fr) minmax(0, 1.35fr);
    align-items: center;
    gap: var(--space-5);
    padding-block: var(--space-8);
  }

  /* The field behind it carries the colour now, so the pitch drops its own.
     It keeps white copy though: the band switched to dark body text for the
     light zone, and the pitch paragraph would otherwise inherit it and sit
     dark-on-orange. */
  .contact__pitch {
    padding: 0 var(--space-6) 0 var(--space-5);
    background: none;
    border-radius: 0;
    color: #fff;
  }

  /* White copy measures 3.02 to 3.23:1 on the mockup's bright orange, short of
     the 4.5:1 that 16px demands. At 24px the paragraph counts as large text,
     where 3:1 is the bar. The field keeps the mockup's colour, by decision. */
  .contact__pitch p {
    font-size: 1.5rem;
  }

  .contact__details {
    padding: var(--space-5);
    border-radius: 0;
    background: var(--color-surface);
  }

  /* No card here on the mockup: the newsletter sits straight on the light zone,
     set apart by a rule. --color-rule is tuned for white and vanishes on this
     shade, hence the ink-derived tint. */
  .contact__newsletter {
    align-self: stretch;
    padding: 0 0 0 var(--space-6);
    background: none;
    border-left: 1px solid rgba(21, 44, 66, 0.15);
    border-radius: 0;
  }
}

/* ---------- Editorial pages ---------- */

.prose {
  max-width: 48rem;
}

.prose h1 {
  margin-bottom: var(--space-5);
}

.prose p + p {
  margin-top: var(--space-4);
}

.prose__list li + li {
  margin-top: var(--space-3);
}

.prose__list a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* ---------- Print and forced colors ---------- */

@media print {
  .site-header__burger,
  .contact::before,
  .contact::after,
  .ph {
    display: none;
  }

  .references,
  .contact,
  .contact__pitch,
  .site-footer {
    background: #fff !important;
    color: #000 !important;
  }

  .references__title,
  .contact__pitch h2,
  .eyebrow--on-accent {
    color: #000 !important;
  }

  /* The focus ring's white inner outline is invisible on paper. */
  :focus-visible {
    outline-color: #000 !important;
    box-shadow: none !important;
  }

  .btn {
    border: 1px solid #000;
    background: none !important;
    color: #000 !important;
  }

  a[href^="http"]::after,
  a[href^="mailto"]::after {
    content: ' (' attr(href) ')';
    font-size: 0.85em;
  }
}

@media (forced-colors: active) {
  .btn {
    border: 1px solid ButtonText;
  }

  /* Decorative only: without them nothing is lost, and in forced colours they
     would otherwise paint over readable text. */
  .hero__media::after,
  .culture__media::after,
  .expertises__list::before {
    display: none;
  }
}

/* ---------- Pull quote ---------- */

.culture__quote {
  margin: var(--space-5) 0 0;
  padding-left: var(--space-5);
  border-left: 3px solid var(--color-accent);
  max-width: 46rem;
  font-style: italic;
}

.culture__quote footer {
  margin-top: var(--space-3);
  font-style: normal;
  font-weight: 700;
}
