/* ------------------------------------------------------------------------
   main.css — everything below the fold, plus the tweaks panel and the chat
   widget. A concatenation of what used to be css/sections.css (§II–§VII) and
   css/tweaks-chat.css, in that order.

   Why one file: each `preload -> stylesheet` swap inserts a sheet into a fully
   parsed <head> and invalidates the whole style tree. Three swaps landed within
   2 ms of each other at ~352 ms and cost one 36 ms layout pass over 295 objects
   before the first paint. One sheet, one invalidation.

   utilities.css is deliberately NOT merged in here: legale/*.html loads it and
   must keep doing so without dragging in the ~100 KB of section styles it does
   not use (see CLAUDE.md §2).
   ------------------------------------------------------------------------ */

/* ------------ Section shells ------------ */
section {
  position: relative;
  padding: var(--section-pad) 0;
  z-index: 2;
}
.section-head {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
  margin-bottom: clamp(40px, 5vw, 72px);
}
@media (min-width: 800px) {
  .section-head {
    grid-template-columns: 1fr 1.4fr;
    gap: 12px 48px;
  }
  .section-head .meta {
    grid-column: 1 / -1;
    margin-bottom: 8px;
  }
  .section-head h2 {
    align-self: end;
  }
  .section-head .lead {
    align-self: start;
  }
}
.section-head h2 {
  font-weight: 400;
}
.section-head h2 em { font-weight: 400; color: var(--brass-deep); }
/* About / Practice section-head: bespoke layout — h2 + image on top row, lead below.
   Voci uses its own single-column head; the marquee sits directly below. */
.about .section-head,
.practice .section-head {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(20px, 3vw, 36px);
}
.about .section-head h2 em,
.practice .section-head h2 em { font-weight: 400; color: var(--brass-deep); }
.about .section-head .meta,
.practice .section-head .meta {
  grid-column: 1 / -1;
  margin-bottom: 0;
}
.about .section-head .head-figure,
.practice .section-head .head-figure {
  position: relative;
  margin: 0;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--rule);
  background-color: var(--bg);
  background-image: var(--bg-img, none);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  overflow: hidden;
}
/* Inner inset frame — matches .about-figure frame-in-frame */
.about .section-head .head-figure::before,
.practice .section-head .head-figure::before {
  content: "";
  position: absolute; inset: 14px;
  border: 1px solid color-mix(in oklab, var(--paper) 78%, transparent);
  pointer-events: none;
  z-index: 3;
}
/* Two tiny brass ticks on the inner frame's top edge */
.about .section-head .head-figure::after,
.practice .section-head .head-figure::after {
  content: "";
  position: absolute;
  left: 14px; right: 14px; top: 14px;
  height: 1px;
  background:
    linear-gradient(to right,
      transparent 0,
      transparent calc(20% - 4px),
      var(--brass) calc(20% - 4px),
      var(--brass) calc(20% + 4px),
      transparent calc(20% + 4px),
      transparent calc(80% - 4px),
      var(--brass) calc(80% - 4px),
      var(--brass) calc(80% + 4px),
      transparent calc(80% + 4px),
      transparent 100%);
  pointer-events: none;
  z-index: 4;
}
.about .section-head .head-figure .caption,
.practice .section-head .head-figure .caption {
  position: absolute;
  left: 26px; right: 26px; bottom: 26px;
  z-index: 5;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  background: color-mix(in oklab, var(--paper) 88%, transparent);
  padding: 10px 12px;
  border: 1px solid var(--rule);
}
.about .section-head .head-figure .caption .ref,
.practice .section-head .head-figure .caption .ref { color: var(--brass-deep); }
.about .section-head .head-lead,
.practice .section-head .head-lead,
.voci .section-head .head-lead {
  margin: 0;
}
.about .section-head .head-lead .lead,
.practice .section-head .head-lead .lead,
.voci .section-head .head-lead .lead {
  font-size: clamp(0.9375rem, 1.2vw, 17px);
  color: var(--ink-soft);
  max-width: 60ch;
  line-height: 1.65;
  margin: 0;
}
.about .section-head .head-lead .lead-rule,
.practice .section-head .head-lead .lead-rule,
.voci .section-head .head-lead .lead-rule {
  width: 48px; height: 1px;
  background: var(--brass);
  margin: 0 0 16px 0;
}

@media (min-width: 800px) {
  .about .section-head,
  .practice .section-head {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto 1fr auto;
    column-gap: clamp(28px, 4vw, 56px);
    row-gap: clamp(24px, 3vw, 40px);
  }
  .about .section-head .meta,
  .practice .section-head .meta { grid-column: 1 / -1; grid-row: 1; }
  .about .section-head h2,
  .practice .section-head h2 {
    grid-column: 1;
    grid-row: 2;
    align-self: stretch;
    margin: 0;
  }
  .about .section-head .head-lead,
  .practice .section-head .head-lead {
    grid-column: 1;
    grid-row: 3;
    max-width: none;
  }
  .about .section-head .head-figure,
  .practice .section-head .head-figure {
    grid-column: 2;
    grid-row: 2 / span 2;
    aspect-ratio: auto;
    height: 100%;
    min-height: 100%;
    align-self: stretch;
    margin-left: calc(clamp(28px, 4vw, 56px) / -2);
    width: calc(100% + clamp(28px, 4vw, 56px) / 2);
  }
}
.section-head .lead {
  font-size: clamp(0.9375rem, 1.2vw, 17px);
  color: var(--ink-soft);
  max-width: 54ch;
  line-height: 1.65;
}
.section-head .meta {
  display: flex;
  align-items: center;
  gap: 16px;
}

/* Stats grid — full width */
.about-stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 800px) {
  .about-stats { grid-template-columns: repeat(4, 1fr); }
}
.about {
  background: var(--bg);
}
/* Two-row about grid: each row = image + text, alternating sides on desktop */
.about-rows {
  display: grid;
  gap: clamp(40px, 6vw, 88px);
}
.about-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(24px, 4vw, 56px);
  align-items: center;
}
@media (min-width: 900px) {
  .about-row { grid-template-columns: 1fr 1fr; }
  /* DOM order is text→figure; on desktop Row 1 shows figure left, text right */
  .about-row .about-figure { order: 1; }
  .about-row .about-text   { order: 2; }
  /* Row 2 (.flip): text left, figure right */
  .about-row.flip .about-figure { order: 2; }
  .about-row.flip .about-text   { order: 1; }
}

/* Figure placeholder — same frame language as hero portrait */
.about-figure {
  position: relative;
  aspect-ratio: 4/5;
  width: 100%;
  max-width: 520px;
  margin: 0 auto;
  background: var(--paper);
  border: 1px solid var(--rule);
  overflow: hidden;
}
@media (min-width: 900px) {
  .about-figure {
    max-width: none;
    width: calc(100% + clamp(24px, 4vw, 56px) / 2);
    aspect-ratio: unset;
    align-self: stretch;
    height: 100%;
  }
  /* Pull figure into the column-gap so it spans the full 50% of the row,
     matching the head-figure treatment above. */
  .about-row:not(.flip) .about-figure { margin: 0 calc(clamp(24px, 4vw, 56px) / -2) 0 0; }
  .about-row.flip        .about-figure { margin: 0 0 0 calc(clamp(24px, 4vw, 56px) / -2); }
}
.about-figure::before {
  content: "";
  position: absolute; inset: 14px;
  border: 1px solid var(--rule);
  pointer-events: none;
  z-index: 3;
}
.about-figure::after {
  /* Two brass ticks on the inner frame's top edge (CLAUDE.md §4.4).
     This used percentage offsets in box-shadow — box-shadow takes <length>,
     percentages are invalid, so the parser dropped the whole declaration and
     the ticks have never rendered. Same technique as .head-figure::after,
     which does it correctly with a gradient and calc(). */
  content: "";
  position: absolute;
  left: 14px; right: 14px; top: 14px;
  height: 1px;
  background:
    linear-gradient(to right,
      transparent 0,
      transparent calc(20% - 4px),
      var(--brass) calc(20% - 4px),
      var(--brass) calc(20% + 4px),
      transparent calc(20% + 4px),
      transparent calc(80% - 4px),
      var(--brass) calc(80% - 4px),
      var(--brass) calc(80% + 4px),
      transparent calc(80% + 4px),
      transparent 100%);
  pointer-events: none;
  z-index: 4;
}
.about-figure .fig-body {
  position: absolute; inset: 0;
  background:
    repeating-linear-gradient(
      135deg,
      color-mix(in oklab, var(--brass) 10%, var(--paper)) 0 2px,
      var(--paper) 2px 18px
    );
  display: grid;
  place-items: center;
}
.about-figure .fig-body .fig-mono {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  background: color-mix(in oklab, var(--paper) 92%, transparent);
  padding: 8px 14px;
  border: 1px dashed var(--rule);
}.about-figure .fig-caption {
  position: absolute;
  left: 26px; right: 26px; bottom: 26px;
  z-index: 5;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  display: flex;
  justify-content: space-between;
  gap: 12px;
  background: color-mix(in oklab, var(--paper) 88%, transparent);
  padding: 10px 12px;
  border: 1px solid var(--rule);
}
.about-figure .fig-caption .tick { color: var(--brass-deep); }

/* Portrait variant — Ritratto · 01 */
.about-figure[data-portrait="01"] .fig-body {
  background-image: var(--bg-img, none);
  background-size: cover;
  background-position: center top;
  background-repeat: no-repeat;
}
.about-figure[data-portrait="01"] .fig-mono { display: none; }
.about-figure--map::before,
.about-figure--map::after { display: none; }

.about-text { min-width: 0; }
.about-text .eyebrow { margin-bottom: 18px; }
.about-text h3 {
  font-size: clamp(26px, 3vw, 40px);
  margin-bottom: 18px;
  max-width: 22ch;
}
.about-text h3 em { color: var(--brass-deep); font-weight: 400; }
.about-text p {
  color: var(--ink-soft);
  font-size: clamp(0.875rem, 1.1vw, 16px);
  line-height: 1.75;
  margin-bottom: 16px;
  max-width: 58ch;
}
.about-text .drop::first-letter {
  font-family: var(--font-display);
  font-size: 3.2em;
  float: left;
  line-height: 0.9;
  padding: 4px 10px 0 0;
  color: var(--brass-deep);
  font-style: italic;
  font-weight: 500;
}
@media (max-width: 600px) {
  .about-text .drop::first-letter { font-size: 2.6em; }
}
.about-text ul.bio {
  list-style: none;
  padding: 0;
  margin: 24px 0 0;
  display: grid;
  grid-template-columns: 28px max-content 1fr;
  column-gap: 20px;
  border-top: 1px solid var(--rule);
  padding-top: 20px;
}
.about-text ul.bio li {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  font-size: 13.5px;
  color: var(--ink-soft);
  padding: 12px 0;
  border-bottom: 1px dashed var(--rule);
  align-items: baseline;
  word-break: break-word;
}
.about-text ul.bio li:first-child { padding-top: 0; }
.about-text ul.bio li:last-child { border-bottom: 0; padding-bottom: 0; }
.about-text ul.bio .k {
  font-family: var(--font-mono);
  font-size: 10px;
  /* --brass on --bg is 3.41:1 in travertino — fine for a hairline, not for
     10px text. --brass-deep is 5.15:1. */
  color: var(--brass-deep);
  letter-spacing: 0.14em;
}
.about-text ul.bio .bio-label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  font-weight: 500;
}
.about-text ul.bio .bio-value {
  color: var(--ink-soft);
  min-width: 0;
}
.about-text ul.bio .bio-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ink-soft);
  text-decoration: underline;
  text-decoration-color: var(--brass);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: color .2s, text-decoration-color .2s;
  cursor: pointer;
}
/* Reset button defaults so .bio-copy looks identical to the previous <a> */
.about-text ul.bio button.bio-link {
  background: transparent;
  border: 0;
  /* Vertical padding only — it was 22px tall, under the 24px AA floor. */
  padding: 4px 0;
  margin: 0;
  font: inherit;
  text-align: left;
  appearance: none;
}
.about-text ul.bio .bio-link:hover {
  color: var(--brass);
  text-decoration-color: var(--brass);
}
.about-text ul.bio .bio-link-icon {
  display: inline-block;
  vertical-align: -1.5px;
  opacity: .55;
  transition: opacity .2s, transform .35s cubic-bezier(.16, 1, .3, 1), color .2s;
}
.about-text ul.bio .bio-link:hover .bio-link-icon {
  opacity: 1;
}
/* Stack the two icons (copy + check) — only one visible at a time */
.about-text ul.bio .bio-copy-icons {
  position: relative;
  display: inline-block;
  width: 13px;
  height: 13px;
  margin-left: 4px;
  line-height: 0;
}
.about-text ul.bio .bio-copy-icons .bio-link-icon {
  position: absolute;
  inset: 0;
  margin-left: 0;
  transition: opacity .35s ease, transform .5s cubic-bezier(.16, 1, .3, 1), color .2s;
}
.about-text ul.bio .bio-copy-icons .ic-check {
  opacity: 0;
  transform: scale(.4) rotate(-12deg);
  color: var(--brass-deep);
}
.about-text ul.bio .bio-copy.is-copied .ic-copy {
  opacity: 0;
  transform: scale(.4) rotate(8deg);
}
.about-text ul.bio .bio-copy.is-copied .ic-check {
  opacity: 1;
  transform: scale(1.15) rotate(0);
  animation: bioCheckPop .55s cubic-bezier(.16, 1, .3, 1);
}
@keyframes bioCheckPop {
  0%   { transform: scale(.4) rotate(-12deg); opacity: 0; }
  55%  { transform: scale(1.35) rotate(0); opacity: 1; }
  100% { transform: scale(1.15) rotate(0); opacity: 1; }
}
/* Tiny "Copiato" toast */
.about-text ul.bio .bio-copy-toast {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 6px);
  transform: translate(-50%, 4px);
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brass-deep);
  background: var(--paper);
  border: 1px solid color-mix(in oklab, var(--brass) 40%, var(--rule));
  padding: 3px 8px;
  pointer-events: none;
  opacity: 0;
  white-space: nowrap;
  transition: opacity .25s ease, transform .35s cubic-bezier(.16, 1, .3, 1);
}
.about-text ul.bio .bio-copy.is-copied .bio-copy-toast {
  opacity: 1;
  transform: translate(-50%, 0);
}
@media (prefers-reduced-motion: reduce) {
  .about-text ul.bio .bio-link-icon,
  .about-text ul.bio .bio-copy-toast { transition: opacity .2s; }
}
@media (max-width: 540px) {
  .about-text ul.bio {
    grid-template-columns: 24px 1fr;
    column-gap: 12px;
  }
  .about-text ul.bio li {
    row-gap: 4px;
  }
  .about-text ul.bio .bio-label { grid-column: 2; }
  .about-text ul.bio .bio-value { grid-column: 2; }
}
.about-text .signoff {
  margin-top: 22px;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 18px;
  color: var(--ink);
}
.about-text .signoff::before {
  content: "";
  width: 28px; height: 1px; background: var(--brass);
}


.values {
  margin-top: clamp(32px, 4vw, 56px);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
}
@media (min-width: 800px) { .values { grid-template-columns: repeat(4, 1fr); } }
.value {
  background: var(--bg);
  padding: 24px 20px;
  transition: background 0.4s ease;
  position: relative;
}
.value:hover { background: var(--hover-bg); }
.value .num {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--brass-deep);
  letter-spacing: 0.18em;
}
.value h4 {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 500;
  margin: 10px 0 6px;
}
.value p {
  font-size: 13px;
  color: var(--muted);
  line-height: 1.55;
}
.value::after {
  content: "";
  position: absolute;
  left: 20px; right: 20px; bottom: 16px;
  height: 1px;
  background: var(--brass);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.5s cubic-bezier(.2,.8,.2,1);
}
.value:hover::after { transform: scaleX(1); }

.practice {
  background: var(--bg-alt);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}
.areas {
  display: grid;
  grid-template-areas: "stack";
  position: relative;
  overflow: hidden;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}
.areas::before,
.areas::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  width: clamp(32px, 6vw, 80px);
  z-index: 10;
  pointer-events: none;
}
.areas::before {
  left: 0;
  background: linear-gradient(to right, var(--bg-alt), transparent);
}
.areas::after {
  right: 0;
  background: linear-gradient(to left, var(--bg-alt), transparent);
}
.areas .area {
  grid-area: stack;
  width: 100%;
}
/* Resting state for the window before layout() has written its inline styles.
   All five cards share one grid cell, so until then they overlap at full
   opacity. That window used to be one animation frame; now that
   initAreasSlider is queued to its own task after the first paint it is a few
   frames, and if the initialiser ever throws it is permanent — this keeps that
   failure mode down to "one card" instead of "five cards on top of each other".
   Scoped to :not(.is-ready) so it can never fight layout()'s inline opacity,
   and the scripting:none branch in utilities.css overrides it with !important. */
.areas:not(.is-ready) .area:not(:first-child) { opacity: 0; }
/* will-change is applied by JS only while a slide is in flight and cleared
   afterwards. Declaring it in CSS kept five compositing layers alive for the
   life of the page and never released them — the textbook misuse. `filter` is
   deliberately absent: promoting a blurred layer does not make the blur cheap,
   it just pins the rasterisation. */
.areas .area.is-moving { will-change: transform, opacity; }
.areas.is-ready .area {
  transition: transform 0.55s cubic-bezier(.22,.9,.36,1),
              filter 0.55s cubic-bezier(.22,.9,.36,1),
              opacity 0.55s cubic-bezier(.22,.9,.36,1);
}
@media (orientation: landscape) and (min-width: 700px) {
  .areas .area { width: 50%; }
}

/* Slider controls (arrows + dots) */
.areas-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(16px, 2vw, 28px);
  padding: clamp(20px, 2.5vw, 32px) clamp(20px, 4vw, 48px) 0;
}
.areas-arrow {
  width: 44px; height: 44px;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  transition: background 0.3s ease, color 0.3s ease, border-color 0.3s ease, opacity 0.3s ease;
}
.areas-arrow:hover { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.areas-arrow[disabled] { opacity: 0.3; cursor: default; }
.areas-arrow[disabled]:hover { background: transparent; color: var(--ink); border-color: var(--rule); }
.areas-dots {
  display: flex;
  gap: 10px;
  align-items: center;
}
/* 44×44 hit area around an 8px dot — the visual stays small, the target meets
   2.5.5. Previously 28×28. */
.areas-dot {
  width: 44px; height: 44px;
  border: 0;
  background: transparent;
  padding: 0;
  margin: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.areas-dot::before {
  content: "";
  width: 8px; height: 8px;
  border-radius: 50%;
  /* Was 35% of --ink → 2.12:1 against --bg-alt. UI state indicators need 3:1
     (WCAG 1.4.11). */
  border: 1px solid color-mix(in oklab, var(--ink) 62%, transparent);
  background: transparent;
  transition: background 0.3s ease, border-color 0.3s ease, transform 0.3s ease;
}
.areas-dot[aria-current="true"]::before {
  background: var(--brass-deep);
  border-color: var(--brass-deep);
  transform: scale(1.25);
}
.area {
  position: relative;
  padding: clamp(28px, 3.5vw, 48px);
  border-bottom: 0;
  background: transparent;
  transition: background 0.5s ease;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.area + .area { border-left: 1px solid var(--rule); }
.area:hover { background-color: var(--paper); }

.area::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--brass);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.6s cubic-bezier(.2,.8,.2,1);
}
.area:hover::before { transform: scaleX(1); }

.area-head {
  margin-bottom: 24px;
}
.area-num {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  /* --brass on --bg-alt is 3.12:1 in travertino; --brass-deep is 4.70:1. */
  color: var(--brass-deep);
}
.area-roman {
  position: absolute;
  top: clamp(28px, 3.5vw, 48px);
  right: clamp(28px, 3.5vw, 48px);
  font-family: var(--font-display);
  font-size: clamp(72px, 8vw, 120px);
  font-weight: 400;
  line-height: 0.85;
  color: var(--ink);
  transition: color 0.5s ease, transform 0.6s cubic-bezier(.2,.8,.2,1);
  letter-spacing: -0.02em;
}
.area:hover .area-roman {
  color: var(--brass-deep);
  transform: translateX(6px);
}

.area h3 {
  font-size: clamp(26px, 2.6vw, 36px);
  font-weight: 500;
  margin-bottom: 16px;
  letter-spacing: -0.005em;
}
.area h3 em {
  font-weight: 400;
  color: var(--brass-deep);
}
.area-bullets {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.area-bullets li {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  /* 12px, not 10: the tick grows to 1.6× on hover, i.e. 20px → 32px, and the
     extra 12px now runs into this gap instead of into the reserved box. */
  gap: 12px;
  transition: color 0.3s ease;
}
.area-bullets li::before {
  content: '';
  display: block;
  width: 20px;
  height: 1px;
  background: var(--brass);
  flex-shrink: 0;
  /* This used to animate the box's own inline size, which relayouts the flex
     row every frame AND shoved the label 12px right as the rule grew. Scaling
     leaves the reserved box at 20px, so the rule extends toward a label that
     never moves. */
  transform-origin: left center;
  transition: transform 0.3s ease;
}
.area:hover .area-bullets li { color: var(--ink); }
.area:hover .area-bullets li::before { transform: scaleX(1.6); }

/* ------------ Approach / Metodo — accordion grid (no image) ------------ */
.approach { background: var(--bg); position: relative; }
.approach .container { position: relative; }

.approach .steps-wrap {
  margin-top: clamp(36px, 6vw, 72px);
}

/* ----- Accordion list — 1 col (portrait) / 2×2 grid (landscape) ----- */
.steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  /* Shared column width for the Roman numeral so every title (and its
     description) aligns to the same left edge across all rows. */
  --num-col: clamp(56px, 6vw, 88px);
}
.step {
  position: relative;
  margin: 0;
  border-top: 1px solid var(--rule);
}
.step:last-child { border-bottom: 1px solid var(--rule); }
/* Brass tick that grows when the row activates */
.step::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  width: 64px;
  height: 2px;
  background: var(--brass);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 500ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.step.is-active::before { transform: scaleX(1); }

/* Heading wrapper around the trigger — same pattern as .faq-q. Purely
   semantic: it must add no box of its own. */
.step-q { margin: 0; font: inherit; }

.step-trigger {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: clamp(18px, 2.4vw, 32px);
  width: 100%;
  padding: clamp(22px, 2.8vw, 32px) 0;
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
  color: inherit;
  font: inherit;
}
.step-trigger:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 4px;
}
.step-trigger .n {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(40px, 5vw, 64px);
  line-height: 0.85;
  /* Ghost numeral for the collapsed steps. 55% put it at 2.22:1 — under the 3:1
     floor for large text even as decoration. 76% is the first step that clears
     3:1 in travertino/light, the tightest of the eight themes (72% gave 2.99). */
  color: color-mix(in oklab, var(--brass-deep) 76%, transparent);
  width: var(--num-col);
  flex-shrink: 0;
  transition: color 380ms ease;
}
.step.is-active .step-trigger .n,
.step-trigger:hover .n { color: var(--brass-deep); }

.step-trigger .t {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(24px, 2.6vw, 36px);
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-wrap: balance;
}
.step-trigger .t em {
  font-style: italic;
  color: var(--brass-deep);
  font-weight: 400;
}

/* +/− glyph indicator */
.step-trigger .chev {
  position: relative;
  width: 28px;
  height: 28px;
  border: 1px solid var(--rule);
  border-radius: 50%;
  flex-shrink: 0;
  transition: border-color 380ms ease, background 380ms ease;
}
.step-trigger .chev::before,
.step-trigger .chev::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  background: var(--ink);
  transition:
    transform 420ms cubic-bezier(0.2, 0.7, 0.2, 1),
    background 380ms ease;
}
.step-trigger .chev::before {
  width: 11px; height: 1px;
  transform: translate(-50%, -50%);
}
.step-trigger .chev::after {
  width: 1px; height: 11px;
  transform: translate(-50%, -50%);
}
.step.is-active .step-trigger .chev {
  border-color: var(--brass);
  background: color-mix(in oklab, var(--brass) 14%, transparent);
}
.step.is-active .step-trigger .chev::before { background: var(--brass-deep); }
.step.is-active .step-trigger .chev::after  { transform: translate(-50%, -50%) scaleY(0); }

/* Animated description panel (grid-rows trick → no max-height guesswork) */
.step-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 520ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.step-panel > .panel-inner {
  overflow: hidden;
  min-height: 0;
  /* grid-template-rows:0fr collapses the box but leaves the text in the
     accessibility tree and in find-in-page, so a screen reader read all four
     descriptions while every trigger reported "collapsed". Delayed so the
     close animation still plays. */
  visibility: hidden;
  transition: visibility 0s linear 520ms;
}
.step.is-active .step-panel { grid-template-rows: 1fr; }
.step.is-active .step-panel > .panel-inner { visibility: visible; transition-delay: 0s; }

.step-panel .d {
  font-family: var(--font-body);
  font-size: clamp(0.9375rem, 1.05vw, 17px);
  line-height: 1.65;
  color: var(--ink-soft);
  max-width: 56ch;
  margin: 0;
  padding: 0 0 clamp(22px, 2.8vw, 32px) calc(var(--num-col) + clamp(18px, 2.4vw, 32px));
  text-wrap: pretty;
  opacity: 0;
  transform: translateY(6px);
  transition:
    opacity 380ms ease,
    transform 460ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.step.is-active .step-panel .d {
  opacity: 1;
  transform: translateY(0);
  transition-delay: 140ms;
}

/* ----- Landscape: 2 columns × 2 rows -----
   The width floor matters: a bare `orientation: landscape` also matches a
   520×400 desktop window, where each column is 220px of which 120px is chrome,
   and the 24px display title overflows. The sibling rule at ~:679 already
   guards the identical pattern this way. */
@media (orientation: landscape) and (min-width: 700px) {
  .steps {
    grid-template-columns: 1fr 1fr;
    column-gap: clamp(40px, 5vw, 80px);
  }
  /* Top border on every cell; bottom border on the last row to close the grid */
  .step:nth-last-child(-n+2) { border-bottom: 1px solid var(--rule); }
}

/* Reduced-motion: snap, don't animate */
@media (prefers-reduced-motion: reduce) {
  .step-panel,
  .step-panel .d,
  .step::before,
  .step-trigger .chev::before,
  .step-trigger .chev::after { transition: none; }
}

/* Closing principle (kept) */
.approach-coda {
  margin-top: clamp(36px, 5vw, 64px);
  border-top: 1px solid var(--rule);
  padding-top: clamp(28px, 4vw, 44px);
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(16px, 2vw, 24px);
  align-items: baseline;
}
.approach-coda .glyph {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(40px, 5vw, 64px);
  line-height: 1;
  color: var(--brass);
}
.approach-coda blockquote {
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 2.4vw, 28px);
  line-height: 1.4;
  font-weight: 400;
  color: var(--ink);
  margin: 0 0 clamp(12px, 1.5vw, 18px) 0;
  letter-spacing: -0.005em;
}
.approach-coda blockquote em {
  color: var(--brass-deep);
  font-style: italic;
}
.approach-coda cite {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-style: normal;
}
@media (min-width: 700px) {
  .approach-coda { grid-template-columns: 60px 1fr; gap: clamp(18px, 2.5vw, 28px); }
}

@media (min-width: 900px) {
  .approach .container { max-width: 1360px; }
  .approach .section-head { max-width: none; }
}

/* Approach section-head: full-width single column (override default 2-col grid),
   so h2 and lead paragraph each span the whole row. */
.approach .section-head {
  grid-template-columns: 1fr;
  row-gap: clamp(24px, 3vw, 40px);
}
.approach .section-head .meta { grid-column: 1 / -1; }
.approach .section-head h2 { grid-column: 1 / -1; align-self: start; max-width: none; }
.approach .section-head .head-lead {
  grid-column: 1 / -1;
  align-self: start;
  margin: 0;
}
.approach .section-head .head-lead .lead-rule {
  width: 48px; height: 1px;
  background: var(--brass);
  margin: 0 0 16px 0;
}
.approach .section-head .head-lead .lead {
  font-size: clamp(0.9375rem, 1.2vw, 17px);
  color: var(--ink-soft);
  line-height: 1.65;
  margin: 0;
  max-width: none;
}

/* ------------ Voci / Testimonials (horizontal marquee) ------------ */
.voci {
  background: var(--bg-alt);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  position: relative;
  overflow: hidden;
}
.voci::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: linear-gradient(var(--grid-color) 1px, transparent 1px);
  background-size: 100% clamp(80px, 8vw, 120px);
  opacity: 0.5;
  pointer-events: none;
  z-index: 0;
}
.voci .container { position: relative; z-index: 1; }


/* ─────────────────────────────────────────────────────────────────────
   § V — Voci · protocol block (figure 4:3 left, 4 cards 2×2 right).
   Mobile: figure stacks on top, cards become a horizontal-scroll strip.
   The voci .section-head is overridden to a single-column meta/h2/lead
   stack at all breakpoints so title + lead read full container width.
   ───────────────────────────────────────────────────────────────────── */

/* Override the generic .section-head 2-col rule for voci so the title + lead
   span the full container width (no 1.4fr second column eating the right side). */
.voci .section-head {
  grid-template-columns: 1fr;
  gap: clamp(20px, 3vw, 36px);
  margin-bottom: clamp(28px, 3vw, 44px);
}
@media (min-width: 800px) {
  .voci .section-head { grid-template-columns: 1fr; gap: clamp(20px, 3vw, 36px); }
  .voci .section-head .meta { grid-column: 1 / -1; margin-bottom: 0; }
  .voci .section-head h2 { align-self: start; margin: 0; }
  .voci .section-head .head-lead { max-width: none; }
}
/* Voci title — keep the base h2 size, left-aligned. text-wrap: balance still
   distributes words evenly between the two natural lines. */
.voci .section-head h2 {
  width: 100%;
  text-align: left;
  text-wrap: balance;
}
.voci .section-head h2 em { font-weight: 400; color: var(--brass-deep); }
/* Voci lead — drop the max-width cap so the paragraph wraps at the full
   container width (yields roughly two lines on desktop). */
.voci .section-head .head-lead { margin: 0; width: 100%; max-width: none; }
.voci .section-head .head-lead .lead {
  max-width: none;
  width: 100%;
}
/* Voci intro — social-proof lead-in under the H2 (sober brass italic, editorial idiom). */
.voci .section-head .voci-intro {
  margin: 0;
  width: 100%;
  max-width: 54ch;
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(1.15rem, 1.6vw, 1.5rem);
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--brass-deep);
}

/* Marquee rail — sits directly inside .voci .container, full container width */
.voci-rail {
  position: relative;
  margin: clamp(28px, 3.4vw, 44px) 0 0;
  width: 100%;
  overflow: hidden;
  /* fade edges so cards enter/exit gracefully */
  -webkit-mask-image: linear-gradient(90deg,
    transparent 0,
    #000 clamp(24px, 6vw, 96px),
    #000 calc(100% - clamp(24px, 6vw, 96px)),
    transparent 100%);
          mask-image: linear-gradient(90deg,
    transparent 0,
    #000 clamp(24px, 6vw, 96px),
    #000 calc(100% - clamp(24px, 6vw, 96px)),
    transparent 100%);
  padding: clamp(8px, 1vw, 14px) 0;
}
/* Mobile: full-bleed cinematic feel across the viewport */
@media (max-width: 899px) {
  .voci-rail {
    margin-left: calc(50% - (100vw - var(--sbw, 0px)) / 2);
    margin-right: calc(50% - (100vw - var(--sbw, 0px)) / 2);
    width: calc(100vw - var(--sbw, 0px));
  }
}

.voci-track {
  display: flex;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: clamp(16px, 1.6vw, 24px);
  width: max-content;
  /* JS drives transform via translate3d on --voci-x */
  transform: translate3d(var(--voci-x, 0px), 0, 0);
  will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
  .voci-track { transform: none; animation: none; }
  .voci-rail {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
  }
  .voce { scroll-snap-align: start; }
}
/* Mobile / touch devices: drive the marquee via pure CSS instead of the JS
   rAF loop. Track contains two identical halves, so translating from 0 to
   -50% produces a seamless wrap. JS init bails out on coarse-pointer
   devices to avoid double-driving the transform. */
@keyframes voci-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
@media (hover: none) and (pointer: coarse) and (prefers-reduced-motion: no-preference) {
  .voci-track {
    animation: voci-scroll 70s linear infinite;
  }
}

.voce {
  position: relative;
  flex: 0 0 auto;
  width: clamp(280px, 78vw, 360px);
  /* Floor raised from 180px. Below 818px viewport width the clamp resolved to
     its minimum, but the tallest testimonial measures ~200px at 320px — and
     because margin-top:auto collapses in an overflowing flex column, the
     overflow landed on .voce-foot, silently clipping the attribution and the
     hairline. 210px clears the measured worst case. */
  max-height: clamp(210px, 22vw, 240px);
  overflow: hidden;
  /* `align-items: stretch` on .voci-track equalizes card heights to the
     tallest; max-height bounds that tallest to a compact editorial strip.
     Required because some unknown source (suspected: Chrome's
     content-visibility: auto + flex-children rendering quirk on .voci at
     lines 3149-3156) was stretching cards to ~958px in testing — DevTools
     confirmed both .voci-track and .voce rendered at 958.9px while no CSS
     rule in the source explained it. overflow:hidden clips any future
     testimonial that exceeds the cap. .voce-foot uses `margin-top: auto`
     to anchor the bottom hairline. Do NOT set explicit `height` here —
     it breaks the equalization. See CLAUDE.md §3 "Voci marquee specifics". */
  background: var(--paper);
  border: 1px solid var(--rule);
  padding: clamp(14px, 1.2vw, 18px) clamp(18px, 1.6vw, 22px);
  display: flex;
  flex-direction: column;
  gap: clamp(10px, 0.9vw, 14px);
  transition: background 0.35s ease, border-color 0.35s ease;
}
@media (min-width: 700px)  { .voce { width: clamp(320px, 38vw, 380px); } }
@media (min-width: 1100px) { .voce { width: clamp(340px, 28vw, 400px); } }

.voce::before {
  /* brass top-left hairline tick */
  content: "";
  position: absolute;
  top: 0;
  left: clamp(22px, 2.2vw, 32px);
  width: 48px;
  height: 2px;
  background: var(--brass);
}
.voce:hover {
  background: color-mix(in oklab, var(--paper) 92%, var(--brass) 8%);
  border-color: color-mix(in oklab, var(--rule) 55%, var(--brass) 45%);
}

.voce-quote {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.0625rem, 1.4vw, 20px);
  line-height: 1.3;
  letter-spacing: -0.003em;
  color: var(--ink);
  text-wrap: pretty;
  margin: 0;
  quotes: "\201C" "\201D";
}
.voce-quote em { color: var(--brass-deep); font-style: italic; }
.voce-quote::before {
  content: open-quote;
  color: var(--brass);
  font-size: 1.4em;
  line-height: 0;
  margin-right: 0.05em;
  vertical-align: -0.18em;
}
.voce-quote::after { content: close-quote; color: var(--brass); }

.voce-foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  margin-top: auto;
  border-top: 1px solid var(--rule);
  padding: clamp(8px, 0.8vw, 12px) 0 0;
  background: transparent;
}
.voce-foot .name {
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.3vw, 18px);
  font-weight: 500;
  color: var(--ink);
  line-height: 1.2;
  flex-shrink: 0;
}
.voce-foot .role {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: right;
  line-height: 1.6;
}
/* ------------ FAQ (§ VI) — accordion (mirrors the Metodo .steps pattern) ------------ */
.faq { background: var(--bg-alt); position: relative; }
.faq .container { position: relative; }
/* Full-width head — override the generic 2-col .section-head grid so the h2
   spans the whole container (mirrors the .approach section-head). */
.faq .section-head { grid-template-columns: 1fr; gap: clamp(16px, 2vw, 24px); }
.faq .section-head h2 { grid-column: 1 / -1; width: 100%; max-width: none; align-self: stretch; }
.faq .section-head h2 em { font-weight: 400; color: var(--brass-deep); }

.faq-list {
  list-style: none;
  margin: clamp(28px, 4vw, 56px) 0 0;
  padding: 0;
  max-width: none;
}
.faq-item {
  position: relative;
  margin: 0;
  border-top: 1px solid var(--rule);
}
.faq-item:last-child { border-bottom: 1px solid var(--rule); }
/* Brass tick top-left, in the established card idiom */
.faq-item::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  width: 48px;
  height: 2px;
  background: var(--brass);
}
/* h3 is just a semantic wrapper around the full-width trigger button */
.faq-q { margin: 0; }
.faq-trigger {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: clamp(18px, 2.4vw, 32px);
  width: 100%;
  padding: clamp(22px, 2.8vw, 32px) 0;
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
  color: inherit;
  font: inherit;
}
.faq-trigger:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 4px;
}
.faq-q-text {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.3rem, 2vw, 1.7rem);
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-wrap: balance;
  transition: color 380ms ease;
}
.faq-item.is-active .faq-q-text,
.faq-trigger:hover .faq-q-text { color: var(--brass-deep); }

/* +/− glyph indicator (same idiom as the Metodo chevron) */
.faq-trigger .chev {
  position: relative;
  width: 28px;
  height: 28px;
  border: 1px solid var(--rule);
  border-radius: 50%;
  flex-shrink: 0;
  transition: border-color 380ms ease, background 380ms ease;
}
.faq-trigger .chev::before,
.faq-trigger .chev::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  background: var(--ink);
  transition:
    transform 420ms cubic-bezier(0.2, 0.7, 0.2, 1),
    background 380ms ease;
}
.faq-trigger .chev::before {
  width: 11px; height: 1px;
  transform: translate(-50%, -50%);
}
.faq-trigger .chev::after {
  width: 1px; height: 11px;
  transform: translate(-50%, -50%);
}
.faq-item.is-active .faq-trigger .chev {
  border-color: var(--brass);
  background: color-mix(in oklab, var(--brass) 14%, transparent);
}
.faq-item.is-active .faq-trigger .chev::before { background: var(--brass-deep); }
.faq-item.is-active .faq-trigger .chev::after  { transform: translate(-50%, -50%) scaleY(0); }

/* Animated answer panel (grid-rows trick → no max-height guesswork) */
.faq-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 520ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.faq-panel > .panel-inner {
  overflow: hidden;
  min-height: 0;
  /* Same as .step-panel: the collapsed answer must leave the accessibility
     tree, not just the visual box. */
  visibility: hidden;
  transition: visibility 0s linear 520ms;
}
.faq-item.is-active .faq-panel { grid-template-rows: 1fr; }
.faq-item.is-active .faq-panel > .panel-inner { visibility: visible; transition-delay: 0s; }
.faq-a {
  margin: 0;
  max-width: 68ch;
  padding: 0 0 clamp(22px, 2.8vw, 32px);
  color: var(--ink-soft);
  line-height: 1.7;
  text-wrap: pretty;
  opacity: 0;
  transform: translateY(6px);
  transition:
    opacity 380ms ease,
    transform 460ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.faq-item.is-active .faq-a {
  opacity: 1;
  transform: translateY(0);
  transition-delay: 120ms;
}
@media (prefers-reduced-motion: reduce) {
  .faq-panel,
  .faq-a,
  .faq-trigger .chev::before,
  .faq-trigger .chev::after { transition: none; }
}

/* ------------ Contact ------------ */
.contact {
  background: var(--ink);
  color: var(--bg);
  position: relative;
  overflow: hidden;
}
.contact::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, color-mix(in oklab, var(--bg) 3.5%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in oklab, var(--bg) 3.5%, transparent) 1px, transparent 1px);
  background-size: clamp(60px, 8vw, 120px) clamp(60px, 8vw, 120px);
  mask-image: radial-gradient(ellipse at 20% 30%, black 10%, transparent 60%);
  -webkit-mask-image: radial-gradient(ellipse at 20% 30%, black 10%, transparent 60%);
}
/* §VII paints on --ink, so every accent inside it faces the OPPOSITE surface
   from the rest of the page. Raw --brass is tuned against --bg and collapsed
   here: 1.86:1 in foresta/dark, 2.86:1 in notturno/light. Mixing toward --bg
   always pushes the accent away from this section's background, because --bg
   is by definition the opposite of --ink — it self-corrects in both modes.
   Percentages solved against all four palettes × light/dark, worst case:
     72% -> 3.42:1  (large display text, needs 3)
     56% -> 4.97:1  (small text, needs 4.5) */
.contact {
  --brass-inv: color-mix(in oklab, var(--brass) 72%, var(--bg));
  --brass-inv-text: color-mix(in oklab, var(--brass) 56%, var(--bg));
}
.contact .container { position: relative; z-index: 2; }
.contact .eyebrow { color: color-mix(in oklab, var(--bg) 70%, transparent); }
.contact .eyebrow::before { background: var(--brass-inv); }
.contact .section-num { color: var(--brass-inv-text); }
.contact h2 { color: var(--bg); }
.contact h2 em { color: var(--brass-inv); font-style: italic; font-weight: 400; }

/* Contact section-head: single-column flow, headline owns the full width */
.contact .section-head {
  grid-template-columns: 1fr;
  gap: clamp(16px, 2vw, 24px);
  max-width: none;
}
@media (min-width: 800px) {
  .contact .section-head {
    grid-template-columns: 1fr;
  }
  .contact .section-head h2 { align-self: stretch; }
}
.contact .section-head h2 {
  width: 100%;
  font-size: clamp(30px, 4.4vw, 58px);
  line-height: 1.05;
  letter-spacing: -0.01em;
}

/* Vertical stack: card rail on top, full-width form below — same on every
   viewport (no 2-column desktop layout). */
.contact-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(32px, 4vw, 56px);
  margin-top: clamp(40px, 5vw, 72px);
}

.contact-info-wrap {
  min-width: 0;
}

/* Rail — same flex/scroll-snap behaviour on every viewport. Pattern lifted
   from .voci-rail; mobile gets a full-bleed override further down. */
.contact-rail {
  position: relative;
  width: 100%;
  /* On tablet/desktop the rail is already bounded to the container content
     area, so overflow:hidden alone keeps cards strictly within the section's
     margins. No mask needed here — the mobile-only override below adds a
     fade aligned to the container padding for the full-bleed phone layout. */
  overflow: hidden;
  padding: clamp(8px,1vw,14px) 0;
}
@media (max-width: 899px) {
  .contact-rail {
    margin-left: calc(50% - (100vw - var(--sbw, 0px)) / 2);
    margin-right: calc(50% - (100vw - var(--sbw, 0px)) / 2);
    width: calc(100vw - var(--sbw, 0px));
    /* Mask fade aligned to .container's horizontal padding so cards are
       fully visible only inside the content area; anything in the viewport
       padding gutters fades out symmetrically at both margins. */
    -webkit-mask-image: linear-gradient(90deg,
      transparent 0,
      #000 clamp(20px, 4vw, 56px),
      #000 calc(100% - clamp(20px, 4vw, 56px)),
      transparent 100%);
            mask-image: linear-gradient(90deg,
      transparent 0,
      #000 clamp(20px, 4vw, 56px),
      #000 calc(100% - clamp(20px, 4vw, 56px)),
      transparent 100%);
  }
}
/* 900–1099px: the rail still scrolls (the 5-column grid only starts at 1100px)
   but the scrollbar is hidden, there is no mask and there are no arrows — at
   1000px that is ~194px of card off-screen with nothing to suggest it. A
   right-edge fade restores the affordance without full-bleeding the rail. */
@media (min-width: 900px) and (max-width: 1099px) {
  .contact-rail {
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 56px), transparent 100%);
            mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 56px), transparent 100%);
  }
}

.contact-track {
  display: flex;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: clamp(14px, 1.6vw, 22px);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  /* No horizontal padding by default — when the rail is inside .container
     (≥900px), this keeps the first card flush with the container's content
     left edge (= where the eyebrow / h2 sit). Mobile full-bleed adds the
     padding back via a media query below. */
  padding: 2px 0;
  scroll-padding-inline: 0;
  scrollbar-width: none;
}
.contact-track::-webkit-scrollbar { display: none; }
@media (max-width: 899px) {
  /* Full-bleed rail spans viewport edge-to-edge; inset cards by the same
     amount as .container's horizontal padding so the first card aligns
     with the section-head text on phones too. */
  .contact-track {
    padding-left: clamp(20px, 4vw, 56px);
    padding-right: clamp(20px, 4vw, 56px);
    scroll-padding-inline: clamp(20px, 4vw, 56px);
  }
}

/* Single card — dark-inverted, brass hairline tick like .voce / .form-card.
   Width clamp sizes the mobile rail card; height hugs natural content and
   equalises to the tallest card via the parent's align-items: stretch. */
.contact-card {
  position: relative;
  flex: 0 0 auto;
  width: clamp(170px, 46vw, 210px);
  scroll-snap-align: start;
  background: color-mix(in oklab, var(--bg) 6%, var(--ink));
  border: 1px solid color-mix(in oklab, var(--bg) 10%, transparent);
  padding: clamp(18px, 1.8vw, 22px) clamp(20px, 2vw, 24px);
  display: grid;
  grid-template-areas:
    "icon  label"
    "value value";
  grid-template-columns: auto 1fr;
  grid-template-rows: auto 1fr;
  column-gap: 12px;
  row-gap: clamp(8px, 0.8vw, 12px);
  align-items: center;
  overflow: hidden;
  transition: background 0.35s ease, border-color 0.35s ease;
}
.contact-card::before {
  content: "";
  position: absolute;
  top: -1px; left: clamp(20px, 2vw, 24px);
  width: 36px; height: 2px;
  background: var(--brass);
}
.contact-card:hover {
  background: color-mix(in oklab, var(--ink) 92%, var(--brass) 8%);
  border-color: color-mix(in oklab, color-mix(in oklab, var(--bg) 10%, transparent) 50%, var(--brass) 50%);
}

.card-icon {
  grid-area: icon;
  width: 22px; height: 22px;
  color: var(--brass);
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
}
.card-icon svg { width: 100%; height: 100%; display: block; }

.card-k {
  grid-area: label;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 22px;          /* match .card-icon height so the title's
                                 line-box vertically centers with the icon */
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--bg) 70%, transparent);
}

.card-v {
  grid-area: value;
  align-self: start;
  color: var(--bg);
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.3vw, 19px);
  line-height: 1.3;
  font-weight: 400;
}
.card-v a {
  position: relative;
  display: inline-block;
  color: inherit;
  text-decoration: none;
}
.card-v a::after {
  content: "";
  position: absolute;
  left: 0; bottom: -2px;
  /* Held at full width and scaled from 0 — see the nav underline note. */
  width: 100%; height: 1px;
  background: var(--brass);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.4s ease;
}
.card-v a:hover::after { transform: scaleX(1); }
/* Live (Orario) card — body sans + brass diagonal glow. The element keeps
   id="studioPresence" + class "presence" so the existing clock JS continues
   to fire. The older `.presence` rule (line ~2877) sets margin / padding /
   border / gap with the same specificity but a later source position; this
   selector `.contact-card.presence` has higher specificity (0,2,0) so it
   wins for the properties it re-declares — required to keep the live card
   visually identical to the other cards. */
.contact-card.presence {
  margin-top: 0;
  padding: clamp(18px, 1.8vw, 22px) clamp(20px, 2vw, 24px);
  border: 1px solid color-mix(in oklab, var(--bg) 10%, transparent);
  column-gap: 12px;
  row-gap: clamp(8px, 0.8vw, 12px);
  background:
    linear-gradient(135deg,
      color-mix(in oklab, var(--brass) 5%, transparent) 0%,
      transparent 60%),
    color-mix(in oklab, var(--bg) 6%, var(--ink));
}
/* Flex-column .card-v for the two stacking cards: the Telefono card stacks
   two tel: links (fisso + cellulare), and the Orari card stacks the hours
   line above the live clock. The clock row is intentionally drawn from a
   different palette than the serif copy: tabular numerals, faded contrast —
   a stamped technical readout. It lands exactly one display-font line-box
   below the first line, matching the other cards' second line. */
.contact-card--phone .card-v,
.contact-card.presence .card-v {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
/* The two tel: links are the highest-intent controls on a law firm's page and
   were 20.8px tall with ZERO separation between them — failing even the 24px
   AA floor of WCAG 2.5.8, let alone 2.5.5's 44px. Padding lifts each row and
   opens a gap without changing the type. */
.contact-card--phone .card-v-tel {
  display: block;
  padding: 7px 0;
}
.contact-card--phone .card-v-tel + .card-v-tel {
  margin-top: 4px;
}
.card-clock {
  position: relative;
  width: 100%;
  /* One display-font line-box tall so total .card-v height matches the
     neighbouring cards' .card-v (= 2 display line-boxes). align-items:
     center keeps the inline content vertically centred in the row. */
  height: clamp(20.8px, 1.69vw, 24.7px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  /* Inherit .card-v's font (Cormorant Garamond, clamp(16px,1.3vw,19px),
     line-height 1.3, color var(--bg)) so the clock reads as a second
     display-font line, identical to "00192 Roma" in Studio. tnum keeps
     the time digits monospaced so HH:MM doesn't jitter on each tick. */
  font-feature-settings: "tnum";
}
.card-clock-time {
  display: inline-flex;
  align-items: baseline;
}
.card-clock-h,
.card-clock-m {
  display: inline-block;
  min-width: 1.6ch;
  text-align: center;
}
.card-clock-colon {
  margin: 0 1px;
  opacity: 0.5;
}
.card-clock-status {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.card-clock-state {
  /* 18.7px at weight 400 is small text: needs 4.5, and raw --brass gave 3.05 */
  color: var(--brass-inv-text);
  transition: color 0.4s ease;
}

/* Was an inline style at 45% — inline beat every sheet, so it sat below the
   other §VII small print at 2.81:1 and could not be corrected from CSS. */
.form-privacy-note {
  margin-top: 14px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--bg) 62%, transparent);
}
.card-clock-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--brass);
  box-shadow: 0 0 0 0 color-mix(in oklab, var(--brass) 60%, transparent);
  transition: background 0.4s ease, box-shadow 0.4s ease;
}
.contact-card.presence.is-open .card-clock-dot {
  animation: card-clock-pulse 2.6s ease-in-out infinite;
}
.contact-card.presence.is-closed .card-clock-state {
  color: color-mix(in oklab, var(--bg) 62%, transparent);
}
.contact-card.presence.is-closed .card-clock-dot {
  background: color-mix(in oklab, var(--bg) 32%, transparent);
  box-shadow: none;
}
@keyframes card-clock-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--brass) 60%, transparent); }
  50%      { box-shadow: 0 0 0 6px transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .contact-card.presence.is-open .card-clock-dot { animation: none; }
}

/* Studio + Telefono cards are interactive. Pointer cursor on the whole card
   plus a brass focus ring; .card-copy-trigger dissolves into the article's
   grid (display: contents) so it inherits the existing layout. */
.contact-card--copy,
.contact-card--tel {
  cursor: pointer;
}
.contact-card--copy {
  -webkit-tap-highlight-color: transparent;
}
.contact-card--copy:focus-within {
  outline: 2px solid var(--brass);
  outline-offset: 2px;
}
.card-copy-trigger {
  display: contents;
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0;
  color: inherit;
  font: inherit;
  text-align: inherit;
  cursor: pointer;
  appearance: none;
}

/* Copy badge — small icon pair on the right of the "Studio Roma" title row.
   Anchored inside .card-k via flex so the address below keeps the full card
   width and never wraps to 3 lines on narrow screens. Two stacked SVGs
   (copy + check) swap with a tiny rotate/scale on success. */
.contact-card--copy .card-k {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.card-copy-badge {
  position: relative;
  flex-shrink: 0;
  width: 13px;
  height: 13px;
  color: color-mix(in oklab, var(--bg) 50%, transparent);
  transition: color 0.3s ease;
  pointer-events: none;
  z-index: 2;
}
.contact-card--copy:hover .card-copy-badge,
.contact-card--copy:focus-within .card-copy-badge {
  color: var(--brass);
}
.card-copy-icon {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  color: inherit;
  transition: opacity 0.35s ease,
              transform 0.5s cubic-bezier(.16, 1, .3, 1),
              color 0.2s;
}
.card-copy-icon.ic-check {
  opacity: 0;
  transform: scale(.4) rotate(-12deg);
  color: var(--brass);
}
.contact-card--copy.is-copied .card-copy-icon.ic-copy {
  opacity: 0;
  transform: scale(.4) rotate(8deg);
}
.contact-card--copy.is-copied .card-copy-icon.ic-check {
  opacity: 1;
  transform: scale(1.05) rotate(0);
  animation: card-copy-check 0.55s cubic-bezier(.16, 1, .3, 1);
}
@keyframes card-copy-check {
  0%   { transform: scale(.4) rotate(-12deg); opacity: 0; }
  55%  { transform: scale(1.35) rotate(0); opacity: 1; }
  100% { transform: scale(1.05) rotate(0); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .card-copy-icon { transition: opacity 0.2s ease; }
  .contact-card--copy.is-copied .card-copy-icon.ic-check { animation: none; }
}

/* Telefono card: hovering anywhere on the card extends the brass underline
   beneath the phone number — so the whole card reads as the call link. */
.contact-card--tel:hover .card-v-tel::after,
.contact-card--tel:focus-within .card-v-tel::after {
  transform: scaleX(1);
}

/* Email · PEC card — two stacked mail rows with mono sub-tags */
.contact-card--mail .card-v {
  font-family: var(--font-body);
  font-size: 14px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* Stacked, not a 48px tag column. With `grid-template-columns: 48px 1fr` plus
   nowrap+ellipsis the address had ~125px at 1100px+ and ~70px at 375px, so
   neither of the Studio's two addresses was ever fully readable — 34 and 39
   characters clipped to 9–17 glyphs on every viewport. */
.mail-row {
  display: block;
}
.mail-tag {
  display: block;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--bg) 62%, transparent);
  margin-bottom: 2px;
}
.mail-row a {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(0.875rem, 1vw, 16px);
  line-height: 1.35;
  color: var(--bg);
  /* Wrap instead of truncating: an address the visitor cannot read is worse
     than one that takes two lines. `anywhere` because these have no spaces.
     Also lifts the target from ~20px tall toward the 24px AA floor. */
  overflow-wrap: anywhere;
  padding: 3px 0;
}
/* The .card-v a::after underline is clipped by .mail-row a's overflow:hidden
   (the ellipsis truncation); pin the underline inside the link box so it
   animates on hover just like the phone number. */
.mail-row a::after {
  bottom: 0;
}

/* Desktop ≥1100: rail becomes a 5-column grid that fills the container.
   Cards drop their fixed squared dimensions, stretch to equal width, and
   share a common min-height so they read as a balanced deck. Below this
   breakpoint, base rules apply (squared cards + horizontal scroll rail). */
@media (min-width: 1100px) {
  .contact-rail {
    overflow: visible;
    -webkit-mask-image: none;
            mask-image: none;
    padding: 0;
  }
  .contact-track {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: clamp(14px, 1.2vw, 20px);
    overflow: visible;
    scroll-snap-type: none;
    padding: 0;
  }
  .contact-card {
    width: auto;
  }
}

.form-card {
  background: color-mix(in oklab, var(--bg) 6%, var(--ink));
  border: 1px solid color-mix(in oklab, var(--bg) 10%, transparent);
  padding: clamp(28px, 3vw, 40px);
  position: relative;
  overflow: hidden;
}
.form-card::before {
  content: "";
  position: absolute; top: -1px; left: 24px;
  width: 48px; height: 2px;
  background: var(--brass);
}
/* Subtle radial brass glow following cursor */
.form-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at var(--mx, 50%) var(--my, 0%),
    color-mix(in oklab, var(--brass) 14%, transparent) 0%,
    transparent 38%);
  opacity: 0;
  transition: opacity 0.6s ease;
  pointer-events: none;
}
.form-card:hover::after, .form-card:focus-within::after { opacity: 1; }

.form-card h3 {
  color: var(--bg);
  font-size: clamp(24px, 2.2vw, 30px);
  font-weight: 500;
  margin-bottom: 4px;
  position: relative;
  z-index: 1;
}
.form-card .hint {
  color: color-mix(in oklab, var(--bg) 62%, transparent);
  font-size: 13px;
  margin-bottom: 18px;
  position: relative;
  z-index: 1;
}
.form-card form { position: relative; z-index: 1; }

/* Field reveal: each field slides in from below in sequence when the form
   scrolls into view. .form-card.in-view triggers the cascade. */
.field {
  position: relative;
  margin-bottom: 14px;
  padding-top: 22px;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.7s cubic-bezier(.2,.8,.2,1), transform 0.7s cubic-bezier(.2,.8,.2,1);
}
.form-card.in-view .field { opacity: 1; transform: none; }
.form-card.in-view .field:nth-of-type(1) { transition-delay: 0.05s; }
.form-card.in-view .field:nth-of-type(2) { transition-delay: 0.13s; }
.form-card.in-view .field:nth-of-type(3) { transition-delay: 0.21s; }
.form-card.in-view .field:nth-of-type(4) { transition-delay: 0.29s; }
.form-card.in-view .field:nth-of-type(5) { transition-delay: 0.37s; }
.form-card.in-view .form-submit { animation: fc-rise 0.8s cubic-bezier(.2,.8,.2,1) 0.45s both; }
@keyframes fc-rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* Floating label: sits inside the field at body size, rises and shrinks
   to brass mono caps on focus or when the field has a value. */
.field label {
  position: absolute;
  left: 0;
  top: 36px;
  pointer-events: none;
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: color-mix(in oklab, var(--bg) 62%, transparent);
  transition:
    top 0.28s cubic-bezier(.2,.8,.2,1),
    font-size 0.28s cubic-bezier(.2,.8,.2,1),
    letter-spacing 0.28s cubic-bezier(.2,.8,.2,1),
    color 0.3s ease;
}
.field input:not(:placeholder-shown) ~ label,
.field input:focus ~ label,
.field textarea:not(:placeholder-shown) ~ label,
.field textarea:focus ~ label,
.field-select:focus-within label,
.field-select.has-value label {
  top: 0;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brass);
}

/* Required marker: brass star, morphs to ◆ when the field is valid */
.field input[required] ~ label::after,
.field textarea[required] ~ label::after,
.field-select select[required] ~ label::after {
  content: " *";
  color: var(--brass);
  opacity: 0.7;
  transition: opacity 0.3s ease;
}
.field input[required]:valid:not(:placeholder-shown) ~ label::after,
.field textarea[required]:valid:not(:placeholder-shown) ~ label::after {
  content: " ◆";
  opacity: 1;
}
/* field-select: label comes before the hidden native select, so we drive
   the required marker off the wrapper class set by JS, not sibling order. */
.field-select label::after {
  content: " *";
  color: var(--brass);
  opacity: 0.7;
  transition: opacity 0.3s ease;
}
.field-select.has-value label::after {
  content: " ◆";
  opacity: 1;
}

/* Inputs: invisible until focused, with an animated brass underline that
   scales from the centre on focus. */
.field input, .field select, .field textarea {
  background: transparent;
  border: 0;
  border-bottom: 1px solid color-mix(in oklab, var(--bg) 62%, transparent);
  color: var(--bg);
  padding: 12px 0 14px;
  font-size: 15px;
  font-family: inherit;
  position: relative;
  width: 100%;
  transition: border-color 0.3s ease;
}
.field::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--brass);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.5s cubic-bezier(.2,.8,.2,1);
  pointer-events: none;
}
.field:focus-within::after { transform: scaleX(1); }

/* ── Custom combobox dropdown ── */
/* The native <select> stays in the DOM purely for form submission +
   :required validation; all interaction lives in the .select-trigger
   button and .select-listbox panel. */
.field-select .select-native {
  display: none;
}
.field-select .select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid color-mix(in oklab, var(--bg) 62%, transparent);
  color: var(--bg);
  padding: 12px 32px 14px 0;
  font-size: 15px;
  line-height: 1.2;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  position: relative;
  transition: border-color 0.3s ease;
}
.field-select .select-trigger:hover {
  border-bottom-color: color-mix(in oklab, var(--bg) 85%, transparent);
}
.field-select .select-value[data-empty="true"] {
  color: transparent;
}
.field-select .select-value {
  color: var(--bg);
}
/* Chevron lives inside the trigger so it rotates with focus + open state */
.field-select .select-chevron {
  position: absolute;
  right: 4px;
  bottom: 18px;
  width: 9px; height: 9px;
  border-right: 1.5px solid color-mix(in oklab, var(--bg) 65%, transparent);
  border-bottom: 1.5px solid color-mix(in oklab, var(--bg) 65%, transparent);
  transform: rotate(45deg);
  transition: transform 0.4s cubic-bezier(.2,.8,.2,1), border-color 0.3s ease;
  pointer-events: none;
}
.field-select.is-open .select-chevron,
.field-select:focus-within .select-chevron {
  border-color: var(--brass);
}
.field-select.is-open .select-chevron {
  transform: rotate(225deg);
}

/* Listbox panel anchored under the trigger */
.select-listbox {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  z-index: 30;
  list-style: none;
  margin: 0;
  padding: 8px 0;
  background: color-mix(in oklab, var(--bg) 6%, var(--ink));
  border: 1px solid color-mix(in oklab, var(--bg) 10%, transparent);
  box-shadow: 0 18px 36px rgba(0,0,0,0.32);
  opacity: 0;
  transform: scaleY(0.96) translateY(-6px);
  transform-origin: top;
  pointer-events: none;
  visibility: hidden;
  transition:
    opacity 0.18s ease,
    transform 0.18s cubic-bezier(.2,.8,.2,1),
    visibility 0s linear 0.18s;
}
.select-listbox::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 24px;
  width: 48px;
  height: 2px;
  background: var(--brass);
}
.field-select.is-open .select-listbox {
  opacity: 1;
  transform: scaleY(1) translateY(0);
  pointer-events: auto;
  visibility: visible;
  transition:
    opacity 0.24s ease,
    transform 0.24s cubic-bezier(.2,.8,.2,1),
    visibility 0s;
}

/* Caption header inside the panel */
.select-caption {
  padding: 8px 18px 12px;
  margin-bottom: 4px;
  border-bottom: 1px solid color-mix(in oklab, var(--bg) 8%, transparent);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--bg) 45%, transparent);
  pointer-events: none;
  user-select: none;
}

/* Options */
.select-listbox [role="option"] {
  position: relative;
  display: grid;
  grid-template-columns: 32px 1fr 14px;
  align-items: center;
  gap: 8px;
  padding: 13px 18px;
  font-size: 14.5px;
  color: var(--bg);
  cursor: pointer;
  opacity: 0;
  transform: translateX(-6px);
  transition:
    opacity 0.32s cubic-bezier(.2,.8,.2,1),
    transform 0.32s cubic-bezier(.2,.8,.2,1),
    padding-left 0.24s ease,
    box-shadow 0.24s ease,
    background 0.24s ease;
}
.field-select.is-open .select-listbox [role="option"] {
  opacity: 1;
  transform: translateX(0);
  transition-delay: calc(var(--i, 0) * 30ms + 60ms);
}
/* Roman numeral on the left */
.select-listbox [role="option"]::before {
  content: attr(data-num);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--brass);
  opacity: 0.85;
}
/* Selected glyph slot on the right */
.select-listbox [role="option"]::after {
  content: "";
  color: var(--brass);
  font-size: 9px;
  text-align: right;
}
.select-listbox [role="option"][aria-selected="true"]::after {
  content: "◆";
}
.select-listbox [role="option"][aria-selected="true"] {
  background: color-mix(in oklab, var(--brass) 8%, transparent);
}
.select-listbox [role="option"]:hover,
.select-listbox [role="option"].is-active {
  box-shadow: inset 2px 0 0 var(--brass);
  padding-left: 24px;
  background: color-mix(in oklab, var(--brass) 10%, transparent);
}
.select-listbox [role="option"].is-stamping {
  transform: scale(0.98);
  transition: transform 0.12s ease;
}

/* Invalid-state shake on submit-with-empty */
.field-select.is-invalid .select-trigger {
  animation: select-shake 0.32s cubic-bezier(.36,.07,.19,.97);
  border-bottom-color: var(--brass);
  box-shadow: 0 1px 0 0 var(--brass), 0 0 0 4px color-mix(in oklab, var(--brass) 14%, transparent);
}
@keyframes select-shake {
  10%, 90% { transform: translateX(-1px); }
  20%, 80% { transform: translateX(2px); }
  30%, 50%, 70% { transform: translateX(-3px); }
  40%, 60% { transform: translateX(3px); }
}

@media (prefers-reduced-motion: reduce) {
  .select-listbox,
  .field-select.is-open .select-listbox,
  .select-listbox [role="option"],
  .field-select.is-open .select-listbox [role="option"] {
    transition: none;
  }
  .field-select.is-open .select-listbox [role="option"] {
    transition-delay: 0s;
  }
  .field-select.is-invalid .select-trigger { animation: none; }
}

.field textarea {
  resize: vertical;
  min-height: 110px;
  line-height: 1.55;
}
.field input:hover, .field select:hover, .field textarea:hover {
  border-bottom-color: color-mix(in oklab, var(--bg) 85%, transparent);
}

.form-submit {
  margin-top: 18px;
  width: 100%;
  padding: 16px 24px;
  /* The site's only submit button was --ink on --brass: 4.35:1 in travertino,
     2.88 in foresta, 2.31 in porpora and 1.88 in notturno — illegible to
     marginal everywhere. A fixed near-black on the light brass is legible in
     every palette and keeps the brass identity. */
  background: #d9b675;
  color: #12141c;
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  position: relative;
  overflow: hidden;
  border: 0;
  cursor: pointer;
  transition: color 0.4s ease, letter-spacing 0.4s ease, transform 0.18s ease;
}
.form-submit::before {
  content: "";
  position: absolute; inset: 0;
  background: var(--bg);
  transform: translateY(101%);
  transition: transform 0.55s cubic-bezier(.7,0,.2,1);
}
/* Ink-stamp ring: expands from --rx/--ry click point on press */
.form-submit::after {
  content: "";
  position: absolute;
  left: var(--rx, 50%); top: var(--ry, 50%);
  width: 12px; height: 12px;
  margin-left: -6px; margin-top: -6px;
  border: 1.5px solid var(--brass);
  border-radius: 50%;
  opacity: 0;
  transform: scale(1);
  pointer-events: none;
}
.form-submit.stamping::after {
  animation: stamp-ring 0.55s cubic-bezier(.2,.8,.2,1) forwards;
}
@keyframes stamp-ring {
  0%   { opacity: 0.9; transform: scale(1); }
  100% { opacity: 0; transform: scale(28); }
}
.form-submit:active { transform: scale(0.97); }
.form-submit > * { position: relative; z-index: 1; display: inline-flex; align-items: center; gap: 12px; }.form-submit:hover { letter-spacing: 0.22em; }
.form-submit:hover::before { transform: translateY(0); }
/* aria-disabled, not [disabled]: a disabled button drops focus, which sends the
   sender back to the top of the tab order at the exact moment they need the
   status message. The button keeps focus and the JS guard rejects re-entry. */
.form-submit[aria-disabled="true"] { cursor: progress; opacity: 0.78; }
.form-submit[aria-disabled="true"]:hover { letter-spacing: 0.18em; }
.form-submit[aria-disabled="true"]:hover::before { transform: translateY(101%); }
.form-submit[aria-disabled="true"]:active { transform: none; }
.form-submit.is-error {
  background: var(--terra);
  border-color: var(--terra);
  color: var(--paper);
  animation: fc-shake 0.42s cubic-bezier(.36,.07,.19,.97);
}
@keyframes fc-shake {
  10%, 90% { transform: translate3d(-1px, 0, 0); }
  20%, 80% { transform: translate3d(2px, 0, 0); }
  30%, 50%, 70% { transform: translate3d(-4px, 0, 0); }
  40%, 60% { transform: translate3d(4px, 0, 0); }
}
/* ── Marquee pause (WCAG 2.2.2) ──────────────────────────────────────────
   Both marquees start on their own and never stop; hovering only eased the
   speed down. A quiet square control in the brass/mono register — a pause
   glyph built from two bars, swapping to a play triangle when paused. */
.marquee-pause {
  position: absolute;
  right: clamp(20px, 4vw, 56px);
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  background: var(--bg-alt);
  border: 1px solid var(--rule);
  color: var(--ink-soft);
  cursor: pointer;
  transition: color 0.3s ease, border-color 0.3s ease;
}
.marquee-pause:hover { color: var(--ink); border-color: var(--brass); }
.marquee-pause-ico {
  width: 12px;
  height: 12px;
  border-left: 3px solid currentColor;
  border-right: 3px solid currentColor;
}
/* Paused → play triangle */
.marquee-pause[aria-pressed="true"] .marquee-pause-ico {
  width: 0;
  height: 0;
  border-left: 10px solid currentColor;
  border-right: 0;
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  margin-left: 3px;
}
.voci-controls {
  display: flex;
  justify-content: flex-end;
  padding: 0 clamp(20px, 4vw, 56px);
  margin-bottom: 14px;
}
/* Also stops the coarse-pointer CSS fallback, which the rAF loop never drives. */
.voci-rail.is-paused .voci-track { animation-play-state: paused; }
.marquee-pause--voci { position: static; transform: none; }

.form-status {
  display: block;
  margin-top: 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--bg) 62%, transparent);
  min-height: 1.2em;
}

/* Field-level error. Same mono register as .form-status, built on --terra —
   the palette's one warm-warning token, which until now had a single
   consumer. §VII is inverted (background: var(--ink)), so raw --terra only
   reaches 3.84:1 there; mixing it toward the section's own text colour
   (--bg) lifts it clear of 4.5:1 in every palette.
   This is the real error signal — the .is-invalid shake is decoration and
   vanishes under prefers-reduced-motion. */
.field-error {
  display: block;
  margin-top: 8px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--terra) 62%, var(--bg));
}
.field-error[hidden] { display: none; }

/* ── Live Roma-time presence indicator ── */
.presence {
  margin-top: 28px;
  padding: 20px 22px;
  border: 1px solid color-mix(in oklab, var(--bg) 12%, transparent);
  display: grid;
  gap: 12px;
  background: linear-gradient(135deg,
    color-mix(in oklab, var(--brass) 5%, transparent) 0%,
    transparent 60%);
}.presence.is-closed .presence-state {
  color: color-mix(in oklab, var(--bg) 45%, transparent);
}.presence.is-closed .presence-dot {
  background: color-mix(in oklab, var(--bg) 30%, transparent);
  box-shadow: none;
}.presence.is-closed .presence-tag {
  color: color-mix(in oklab, var(--bg) 45%, transparent);
}
@media (prefers-reduced-motion: reduce) {
  .presence.is-open .presence-dot { animation: none; }
}

/* ------------ Footer ------------ */
footer {
  background: var(--bg-alt);
  padding: clamp(48px, 5vw, 80px) 0 32px;
  border-top: 1px solid var(--rule);
  position: relative; z-index: 2;
}
.foot-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
  margin-bottom: 40px;
}
@media (min-width: 800px) { .foot-grid { grid-template-columns: 1.4fr 1fr 1fr; } }
.foot h3 {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--brass-deep);
  margin: 0 0 14px;
}
.foot p, .foot a { font-size: 13.5px; color: var(--ink-soft); line-height: 1.7; }
/* Footer links were 16px tall with a 6px gap = 22px centre-to-centre, just under
   the 24px spacing exception of WCAG 2.5.8. Padding lifts each row past it
   without changing the type or the visual rhythm. */
.foot a { display: inline-block; padding: 5px 0; }
.foot a:hover { color: var(--brass-deep); }
.foot ul { list-style: none; padding: 0; margin: 0; display: grid; gap: 2px; }
.map-gate-link, .about-text .e-mail { display: inline-block; padding: 5px 0; }
.foot-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 24px;
  border-top: 1px solid var(--rule);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  flex-wrap: wrap;
  gap: 10px;
}
.foot-bottom .foot-credit a {
  /* .foot a padding does not reach here — .foot-bottom sits outside .foot — so
     the credit link was a 14px-tall target, under the 24px AA floor (2.5.8). */
  display: inline-block;
  padding: 6px 0;
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--brass);
  text-underline-offset: 3px;
  transition: color 220ms ease;
}
/* --brass-deep, not --brass: the hover/focus colour has to clear 4.5:1 like any
   other text, and raw brass on --bg-alt reads 3.12:1 in travertino and 4.26:1
   in foresta. Deep brass measures 4.70–8.48 across the four palettes. */
.foot-bottom .foot-credit a:hover,
.foot-bottom .foot-credit a:focus-visible { color: var(--brass-deep); }


/* ------------ About stats card backgrounds ------------ */
.about-stats .stat {
  background-image: var(--bg-img, none);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-position: center;
  position: relative;
  overflow: hidden;
}
/* Overlay so text remains legible */
.about-stats .stat::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg,
    color-mix(in oklab, var(--paper) 92%, transparent) 0%,
    color-mix(in oklab, var(--paper) 72%, transparent) 55%,
    color-mix(in oklab, var(--paper) 30%, transparent) 100%);
  pointer-events: none;
}
.about-stats .stat .num,
.about-stats .stat .lab { position: relative; z-index: 1; }
/* Stat-card backgrounds: each `.stat` element carries data-bg-light /
   data-bg-dark attrs in the HTML. The bg-image is injected as a
   `--bg-img` CSS var by initLazyBgImages() when the card nears the
   viewport, and re-applied by applyState() on mode change. */



/* ===================== was css/tweaks-chat.css ===================== */

/* ------------ Tweaks Panel ------------ */
#tweaks-panel {
  position: fixed;
  right: 20px; bottom: 20px;
  z-index: 9999;
  width: 320px;
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--rule);
  box-shadow: 0 20px 60px rgba(0,0,0,0.18);
  padding: 20px;
  font-family: var(--font-body);
  font-size: 13px;
  display: none;
  max-height: 80vh;
  overflow-y: auto;
}
#tweaks-panel.show { display: block; }
#tweaks-panel h5 {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brass);
  margin: 14px 0 8px;
}
#tweaks-panel h5:first-child { margin-top: 0; }
#tweaks-panel .header {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 14px; padding-bottom: 10px; border-bottom: 1px solid var(--rule);
}
#tweaks-panel .header .title {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 500;
}
#tweaks-panel .opts {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px;
}
#tweaks-panel .opt {
  border: 1px solid var(--rule);
  padding: 8px 10px;
  font-size: 11.5px;
  cursor: pointer;
  text-align: left;
  transition: background 0.2s, border-color 0.2s;
  background: var(--bg);
}
#tweaks-panel .opt:hover { background: var(--hover-bg); }
#tweaks-panel .opt.active { background: var(--ink); color: var(--bg); border-color: var(--ink); }
#tweaks-panel .opts.three { grid-template-columns: repeat(3, 1fr); }

/* Touch: disable hover-only affordances for coarse-pointer devices */
@media (hover: none) {
  /* Must mirror .contact-card's resting values exactly — a literal white here
     stopped matching once §VII's strokes became bg-relative. */
  .contact-card:hover {
    background: color-mix(in oklab, var(--bg) 6%, var(--ink));
    border-color: color-mix(in oklab, var(--bg) 10%, transparent);
  }
  .area:hover { background-color: transparent; }
  .area:hover::before { transform: none; }
  .area:hover .area-roman { color: var(--ink); transform: none; }
  .step:hover { background: transparent; }
  .value:hover { background: var(--bg); }
  .value:hover::after { transform: none; }
}
/* The global reduced-motion damper moved to base.css: this file is deferred,
   so motion-sensitive visitors saw animations play until it loaded — and the
   legal pages never load it at all. */

/* Critical chat-panel hide — keeps the panel out of flow and invisible
   from frame 0, BEFORE the deferred chat CSS at the end of <body>
   loads. Without these rules, the parser renders the panel inline at
   its DOM position with all its content visible, until the late
   <style> block applies position:fixed + opacity:0 — perceived as
   "the chatbot opens and then closes" on initial load. The deferred
   block re-declares these properties identically; specificity matches
   and source-order resolves cleanly, so .chat-panel.open still wins. */
.chat-panel {
  position: fixed; bottom: 96px; right: 28px; z-index: 9000;
  opacity: 0; transform: translateY(16px) scale(0.96); pointer-events: none;
  visibility: hidden;
}

/* ------------ Chat Widget ------------ */
.chat-toggle {
  position: fixed;
  bottom: 28px;
  right: 28px;
  z-index: 9000;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: 1px solid var(--brass);
  background: var(--paper);
  color: var(--brass);
  font-family: var(--font-display);
  font-size: 24px;
  font-style: italic;
  cursor: pointer;
  display: grid;
  place-items: center;
  box-shadow: 0 4px 24px rgba(0,0,0,0.12);
  transition: transform 0.3s ease, background 0.3s ease, color 0.3s ease;
}
.chat-toggle:hover {
  transform: scale(1.08);
  background: var(--brass);
  color: var(--paper);
}
.chat-toggle[aria-expanded="true"] {
  background: var(--brass);
  color: var(--paper);
}

.chat-panel {
  position: fixed;
  bottom: 96px;
  right: 28px;
  z-index: 9000;
  width: 400px;
  /* Height must follow the viewport, not just the width. The old fixed 520px
     with only a width-based media branch meant a rotated phone (844×390) put
     the header — and the close button — at y = −226px: the panel could not be
     closed except through the FAB. */
  max-height: min(520px, calc(100svh - 140px));
  display: flex;
  flex-direction: column;
  border: 1px solid var(--rule);
  border-top: 2px solid var(--brass);
  border-radius: 2px;
  background: var(--paper);
  box-shadow: 0 2px 8px rgba(0,0,0,0.08), 0 12px 48px rgba(0,0,0,0.15);
  opacity: 0;
  transform: translateY(16px) scale(0.96);
  pointer-events: none;
  /* opacity+pointer-events alone left the panel's five controls in the tab
     order while it was invisible. visibility removes them; the delay lets the
     close transition finish first. */
  visibility: hidden;
  transition: opacity 0.3s ease, transform 0.3s ease, visibility 0s linear 0.3s;
}
.chat-panel.open {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
  visibility: visible;
  transition-delay: 0s, 0s, 0s;
}

.chat-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  background: var(--ink);
  color: var(--bg);
  border-bottom: 2px solid var(--brass);
  flex-shrink: 0;
}
.chat-header-title {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 500;
  font-style: italic;
  letter-spacing: 0.02em;
}
.chat-header-title::before {
  content: "§ ";
  font-style: normal;
  opacity: 0.5;
}
.chat-header-actions {
  display: flex;
  align-items: center;
  gap: 6px;
}
.chat-header-action {
  background: none;
  border: 1px solid color-mix(in oklab, var(--bg) 22%, transparent);
  color: var(--bg);
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  cursor: pointer;
  border-radius: 2px;
  padding: 0;
  transition: border-color 0.25s ease, color 0.25s ease, background 0.25s ease;
}
.chat-header-action:hover {
  border-color: var(--brass);
  color: var(--brass);
}
/* Colour reinforcement only — the ring itself comes from the global
   :focus-visible rule in base.css. The 40%-alpha glow this used to substitute
   measured 1.73:1 against the header, i.e. effectively invisible. */
.chat-header-action:focus-visible {
  border-color: var(--brass);
  color: var(--brass);
}
.chat-header-action svg {
  display: block;
}

.chat-scroll-region {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 200px;
  max-height: 340px;
}
.chat-messages {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scroll-behavior: smooth;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in oklab, var(--brass) 55%, transparent) transparent;
}
.chat-messages::-webkit-scrollbar {
  width: 6px;
}
.chat-messages::-webkit-scrollbar-track {
  background: transparent;
}
.chat-messages::-webkit-scrollbar-thumb {
  background-color: color-mix(in oklab, var(--brass) 55%, transparent);
  background-clip: content-box;
  border: 4px solid transparent;
  border-left: 0;
  border-right: 0;
  border-radius: 1px;
}
.chat-messages::-webkit-scrollbar-thumb:hover {
  background-color: var(--brass-deep);
}
.chat-messages::-webkit-scrollbar-thumb:active {
  background-color: var(--ink);
}
.chat-messages::-webkit-scrollbar-button,
.chat-messages::-webkit-scrollbar-corner {
  display: none;
}

.chat-msg {
  max-width: 88%;
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink);
}
.chat-msg.bot {
  align-self: flex-start;
}
.chat-msg.bot p { margin: 0 0 8px; }
.chat-msg.bot p:last-child { margin-bottom: 0; }
.chat-msg.bot ul, .chat-msg.bot ol { margin: 6px 0 10px 18px; padding: 0; }
.chat-msg.bot ol { list-style: decimal; }
.chat-msg.bot li { margin-bottom: 5px; }
.chat-msg.bot li::marker { color: var(--brass); }
.chat-msg.bot strong { color: var(--ink); font-weight: 600; }
.chat-msg.bot em { font-style: italic; color: var(--brass-deep); }
.chat-msg.bot a {
  color: var(--brass-deep);
  text-decoration: underline;
  text-decoration-color: color-mix(in oklab, var(--brass) 50%, transparent);
  text-underline-offset: 2px;
  transition: color .2s, text-decoration-color .2s;
}
.chat-msg.bot a:hover {
  color: var(--ink);
  text-decoration-color: var(--brass);
}
.chat-msg.bot a[href^="tel:"],
.chat-msg.bot a[href^="mailto:"] {
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.02em;
  background: color-mix(in oklab, var(--brass) 8%, var(--paper));
  padding: 2px 6px;
  border: 1px solid color-mix(in oklab, var(--brass) 18%, var(--rule));
}

/* Contact info block — each link on its own row with icon */
.chat-msg.bot .chat-contact {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 10px 0;
}
.chat-msg.bot .chat-contact a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.01em;
  background: color-mix(in oklab, var(--brass) 8%, var(--paper));
  position: relative;
  transition: background .2s, transform .2s, border-color .2s;
  padding: 5px 9px;
  border: 1px solid color-mix(in oklab, var(--brass) 18%, var(--rule));
  border-radius: 4px;
  color: var(--brass-deep);
  text-decoration: none;
  overflow-wrap: anywhere;
}
.chat-msg.bot .chat-contact a::before {
  content: "";
  position: absolute;
  left: 0;
  top: 4px;
  bottom: 4px;
  width: 2px;
  background: var(--brass);
  opacity: 0;
  transition: opacity .2s;
}
.chat-msg.bot .chat-contact a:hover {
  background: color-mix(in oklab, var(--brass) 15%, var(--paper));
  color: var(--ink);
  transform: translateX(3px);
}
.chat-msg.bot .chat-contact a:hover::before {
  opacity: 1;
}
.chat-msg.bot .chat-contact svg {
  flex-shrink: 0;
  color: var(--brass);
  width: 14px;
  height: 14px;
}

/* Embedded map inside chat */
.chat-msg.bot .chat-map {
  margin: 10px 0 4px;
  border-radius: 6px;
  overflow: hidden;
  border: 1px solid var(--rule);
  position: relative;
}
.chat-msg.bot .chat-map::before {
  content: "";
  position: absolute;
  top: 0;
  left: 12px;
  width: 32px;
  height: 2px;
  background: var(--brass);
  z-index: 1;
  pointer-events: none;
}
.chat-msg.bot .chat-map iframe {
  width: 100%;
  height: 200px;
  border: 0;
}
/* Stands in for the embed when third-party content has not been consented to.
   Fills the same slot so the message keeps its rhythm. */
.chat-msg.bot .chat-map-fallback {
  display: block;
  padding: 22px 16px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brass-deep);
  text-decoration: none;
  background: repeating-linear-gradient(135deg,
    color-mix(in oklab, var(--brass) 10%, var(--paper)) 0 2px,
    var(--paper) 2px 18px);
}
.chat-msg.bot .chat-map-fallback:hover { color: var(--ink); }

.chat-msg.bot hr {
  border: none;
  border-top: 1px solid var(--rule);
  margin: 10px 0;
}

/* ── Rich chat components ── */

/* Eyebrow label */
.chat-msg.bot .chat-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 14px 0 8px;
}
.chat-msg.bot .chat-label:first-child { margin-top: 0; }
.chat-msg.bot .chat-label::before {
  content: "";
  width: 16px;
  height: 1px;
  background: var(--brass);
}

/* Key-value info card.
   The brass mark sits top-left as a 2px tick, the project's own idiom
   (CLAUDE.md §4.4), not as a thick coloured left border. A 2–3px accent rail
   down the side is the generic "callout" tab; this studio marks a block with a
   hairline instead. 32px rather than §4.4's 48px because the chat runs at a
   smaller scale — the tick keeps the same proportion to its box. */
.chat-msg.bot .chat-card {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 10px;
  background: color-mix(in oklab, var(--brass) 5%, var(--paper));
  border-top: 1px solid color-mix(in oklab, var(--brass) 28%, transparent);
  padding: 8px 10px 7px;
  margin: 4px 0;
}
.chat-msg.bot .chat-card::before {
  content: "";
  position: absolute;
  top: -1px; left: 0;
  width: 32px; height: 2px;
  background: var(--brass);
}
.chat-msg.bot .chat-card-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  flex-shrink: 0;
}
.chat-msg.bot .chat-card-value {
  font-family: var(--font-body);
  font-size: 13.5px;
  color: var(--ink);
}

/* Highlight / emphasis box — same top-left brass tick as .chat-card. */
.chat-msg.bot .chat-highlight {
  position: relative;
  border-top: 1px solid color-mix(in oklab, var(--brass) 28%, transparent);
  background: color-mix(in oklab, var(--brass) 4%, var(--paper));
  padding: 12px 14px 11px;
  margin: 10px 0;
}
.chat-msg.bot .chat-highlight::before {
  content: "";
  position: absolute;
  top: -1px; left: 0;
  width: 32px; height: 2px;
  background: var(--brass);
}
.chat-msg.bot .chat-highlight p { margin: 0; }

/* Diamond divider */
.chat-msg.bot .chat-divider {
  text-align: center;
  font-size: 8px;
  color: var(--brass);
  letter-spacing: 0.3em;
  margin: 12px 0;
  position: relative;
}
.chat-msg.bot .chat-divider::before,
.chat-msg.bot .chat-divider::after {
  content: "";
  position: absolute;
  top: 50%;
  height: 1px;
  width: calc(50% - 16px);
  background: var(--rule);
}
.chat-msg.bot .chat-divider::before { left: 0; }
.chat-msg.bot .chat-divider::after  { right: 0; }

/* Numbered process steps */
.chat-msg.bot .chat-steps {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 10px 0;
}
.chat-msg.bot .chat-step {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}
.chat-msg.bot .chat-step-num {
  font-family: var(--font-display);
  font-size: 18px;
  font-style: italic;
  color: var(--brass);
  line-height: 1.3;
  flex-shrink: 0;
  min-width: 20px;
}
.chat-msg.bot .chat-step p { margin: 0; }

/* Section wrapper */
.chat-msg.bot .chat-section { margin: 6px 0; }
.chat-msg.user {
  align-self: flex-end;
  background: color-mix(in oklab, var(--brass) 12%, var(--paper));
  padding: 10px 14px;
  border: 1px solid color-mix(in oklab, var(--brass) 20%, var(--rule));
  scroll-margin-top: 12px;
}

.chat-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 10px 0 4px;
}
.chat-chip {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.02em;
  padding: 6px 14px;
  background: color-mix(in oklab, var(--brass) 8%, var(--paper));
  border: 1px solid color-mix(in oklab, var(--brass) 25%, var(--rule));
  color: var(--ink);
  cursor: pointer;
  transition: background .2s, border-color .2s;
}
.chat-chip:hover {
  background: color-mix(in oklab, var(--brass) 18%, var(--paper));
  border-color: var(--brass);
}
.chat-chip:disabled {
  opacity: 0.5;
  cursor: default;
  pointer-events: none;
}
.chat-chip.reply {
  background: transparent;
  border-style: dashed;
}
.chat-chip.reply:hover {
  background: color-mix(in oklab, var(--brass) 12%, var(--paper));
  border-style: solid;
}

.chat-typing {
  align-self: flex-start;
  display: flex;
  gap: 5px;
}
.chat-typing span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--muted);
  animation: chatDot 1.4s infinite;
}
.chat-typing span:nth-child(2) { animation-delay: 0.2s; }
.chat-typing span:nth-child(3) { animation-delay: 0.4s; }
@keyframes chatDot {
  0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); }
  40% { opacity: 1; transform: scale(1); }
}

.chat-input-area {
  display: flex;
  gap: 8px;
  padding: 14px 20px;
  border-top: 1px solid var(--rule);
  flex-shrink: 0;
}
.chat-input {
  flex: 1;
  border: 1px solid var(--rule);
  border-radius: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 14px;
  padding: 10px 14px;
  transition: border-color 0.3s ease;
}
.chat-input::placeholder { color: var(--muted); }
.chat-input:focus { border-color: var(--brass); }
.chat-send {
  background: var(--ink);
  color: var(--bg);
  border: none;
  border-radius: 0;
  padding: 10px 16px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.3s ease;
  flex-shrink: 0;
}
.chat-send:hover { background: var(--brass-deep); }
.chat-send:disabled { opacity: 0.5; cursor: default; }

.chat-disclaimer {
  padding: 8px 20px 12px;
  border-top: 1px solid var(--rule);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  line-height: 1.5;
  flex-shrink: 0;
}

.chat-scroll-down {
  position: absolute;
  right: 20px;
  bottom: 20px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--paper);
  border: 1px solid var(--brass);
  color: var(--brass-deep);
  display: grid;
  place-items: center;
  cursor: pointer;
  padding: 0;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);
  opacity: 0;
  transform: translateY(6px);
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease, background 0.2s ease, color 0.2s ease;
  z-index: 5;
}
.chat-scroll-down.show {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.chat-scroll-down:hover {
  background: var(--brass);
  color: var(--paper);
}
/* Ring comes from the global :focus-visible rule; the old 40%-alpha glow it
   replaced measured 1.58:1 against the paper surface. */
.chat-scroll-down svg {
  display: block;
}

/* Short viewports — chiefly landscape phones — need the same treatment the
   width branch below gives narrow ones. */
@media (max-height: 600px) {
  .chat-panel {
    bottom: 76px;
    max-height: calc(100svh - 96px);
  }
  .chat-toggle { bottom: 16px; }
}
@media (max-width: 600px) {
  .chat-panel {
    width: calc(100vw - 32px);
    max-width: 360px;
    right: 16px;
    bottom: 88px;
    max-height: min(420px, calc(100svh - 128px));
  }
  .chat-toggle {
    bottom: 20px;
    right: 16px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .chat-panel { transition: none; }
  .chat-toggle { transition: none; }
  .chat-typing span { animation: none; opacity: 0.6; }
  .chat-scroll-down { transition: none; }
}
