/* ============================================================
   REVALUAR - Page & section styles
   ============================================================ */

/* route fade - opacity only; the rise (translateY) was removed 2026-09-10 at the
   owner's request so nothing above the fold moves at page open */
.route-fade { animation: routein .5s var(--ease) both; }
@keyframes routein { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .route-fade { animation: none; } }

/* ---- page-change sweep (navigate() in app.jsx) ----
   --d flips the direction for Arabic, so the panel always travels the way the page reads.
   0-24%: in (the route is swapped at ~160ms, i.e. while it covers the page), then a short
   hold, then out. The R fades in as the panel arrives and out before it leaves. The panel
   is only mounted while it plays and never takes pointer events. */
.route-sweep {
  --d: 1;
  position: fixed; inset: 0; z-index: 9000; pointer-events: none;
  display: grid; place-items: center; background: var(--ink); color: var(--paper);
  animation: sweep .72s cubic-bezier(.65, 0, .35, 1) both;
}
[dir="rtl"] .route-sweep { --d: -1; }
.route-sweep svg { animation: sweep-mark .72s ease both; }
@keyframes sweep { 0% { transform: translateX(calc(-101% * var(--d))); } 24%, 36% { transform: none; } 100% { transform: translateX(calc(101% * var(--d))); } }
@keyframes sweep-mark { 0%, 14% { opacity: 0; } 30%, 44% { opacity: 1; } 62%, 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .route-sweep { display: none; } }

/* ---- language switch as a View Transition (toggleLang in app.jsx) ----
   The names exist only while html.vt-lang is set, so nothing else on the site gets a
   view-transition-name (each one makes a stacking context). Each name is unique per
   page state: one nav, one h1, one lead, one hero image. Named elements morph from
   their old box to their new one (that is the mirroring); everything else cross-fades.
   .route-fade would fade the new page a second time, so it stands down. */
.vt-lang .nav-brand { view-transition-name: rv-brand; }
.vt-lang .nav-links { view-transition-name: rv-links; }
.vt-lang .nav-right { view-transition-name: rv-right; }
.vt-lang .hero-title, .vt-lang .page-hero-title { view-transition-name: rv-title; }
.vt-lang .hero-body, .vt-lang .page-hero-lead { view-transition-name: rv-lead; }
.vt-lang .hero-media { view-transition-name: rv-media; }
.vt-lang .route-fade { animation: none; }
::view-transition-group(*) { animation-duration: .6s; animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .4s; }

/* ---- Arabic display headings: comfortable leading so marks/descenders never clip.
   The leading itself now comes from --lh-d1/2/3, redefined once under [dir="rtl"]
   in styles.css; only the footer tagline (outside the scale) still needs it here. */
[dir="rtl"] .footer-tagline { line-height: 1.3; }
[dir="rtl"] .values-item .display { display: inline-block; padding-block: 0.04em; }

/* shared section title */
.sec-title { font-size: var(--fs-d2); line-height: var(--lh-d2); font-weight: 500; max-width: 18ch; letter-spacing: -0.02em; }
.sec-title.wide { max-width: 22ch; }
/* Rise (components.jsx): words climb out of a clipped line. The padding/negative-margin pair
   gives descenders room without changing the line height; Arabic marks need more of it. */
.rise-w { display: inline-block; overflow: hidden; vertical-align: top; padding-block: 0.06em 0.16em; margin-block: -0.06em -0.16em; }
[dir="rtl"] .rise-w { padding-block: 0.22em 0.3em; margin-block: -0.22em -0.3em; }
.rise-w > i { display: inline-block; font-style: normal; }
.js .rise-w > i { transform: translateY(112%); } /* hidden only once JS runs, as .js .reveal */
.rise.in .rise-w > i { transform: none; transition: transform .8s var(--ease) calc(var(--i) * 70ms + var(--rise-delay, 0ms)); }
@media (prefers-reduced-motion: reduce) { .js .rise-w > i { transform: none; transition: none; } }
.lead {
  font-size: var(--fs-lead); line-height: var(--lh-lead); max-width: 52ch;
  margin-top: 22px; color: var(--ink-soft);
}
.sec-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 30px; margin-bottom: clamp(40px, 6vw, 72px); flex-wrap: wrap;
}
.sec-head .sec-title { margin-top: 18px; }
.sec-head-link { padding-bottom: 8px; }

/* ============================================================
   HERO
   ============================================================ */
.hero { padding-top: clamp(96px, 12vh, 130px); } /* was 17vh/190: pushed CTAs ~900px deep */
.hero-grid {
  display: grid; grid-template-columns: 7fr 5fr;
  gap: var(--gutter); align-items: start;
}
.hero-title {
  font-size: var(--fs-d1); line-height: var(--lh-d1); font-weight: 500;
  margin: 26px 0 0; letter-spacing: -0.03em;
}
/* Orphan guard (REV-71): at 1440 the old headline broke with one word alone on a
   line. `text-wrap: balance` does the whole job, applied per .hero-line because
   each of the two title strings is its own block. A max-width: 20ch was tried
   alongside it and removed: measured at 1440 it caps at ~802px against a hero
   column of 621px, so it never binds - the column is already the measure. */
.hero-line { display: block; overflow: hidden; text-wrap: balance; }
/* Arabic letterforms have tall marks + deep descenders - don't clip them */
[dir="rtl"] .hero-line { overflow: visible; padding-block: 0.04em; }
.dot-orange { color: var(--orange); }
.hero-body {
  font-size: var(--fs-lead); line-height: var(--lh-lead); max-width: 46ch;
  margin-top: 30px; color: var(--ink-soft);
}
.hero-actions { display: flex; gap: 14px; margin-top: 34px; flex-wrap: wrap; }
/* the dialled number inside a CTA: never break it across lines, and keep it LTR
   inside an Arabic button (the dir="ltr" span does the ordering) */
.btn-num { white-space: nowrap; }
.hero-note {
  /* was 12.5px/.7 - it now carries the reassurance line ("live in a week"), and
     .7 on paper is below the .8 floor the accessibility pass set (CLAUDE.md #9) */
  display: inline-flex; align-items: center; gap: 9px; margin-top: 26px;
  font-size: 13.5px; letter-spacing: 0.04em; opacity: 0.8; max-width: 62ch;
}
.hero-note .tick, .proof-ticks .tick {
  width: 18px; height: 18px; display: grid; place-items: center; border-radius: 50%;
  background: var(--sage); color: var(--ink); font-size: 11px;
}
/* padding-bottom: the media clips its overflow, so the proof card's shadow needs room inside it */
.hero-media { position: relative; align-self: start; margin-top: 30px; overflow: hidden; padding-bottom: 28px; }
.hero-img { width: 100%; height: min(58vh, 560px); box-shadow: 0 40px 80px -50px rgba(64,37,48,.6); }
.hero-shape {
  position: absolute; bottom: -30px; left: -34px; z-index: 2;
}
[dir="rtl"] .hero-shape { left: auto; right: -34px; }

/* Drawn underline under home.heroMark (HeroMark in home.jsx). A background, not a pseudo-element,
   so box-decoration-break:clone repeats it on each line of a wrapped phrase. It sits a little above
   the bottom of the span's box: .hero-line clips its overflow in LTR. Visible at rest; with JS and
   motion allowed it draws in once from the reading-direction start. */
.hero-mark {
  background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 12' preserveAspectRatio='none'><path d='M3 8.5C40 4 88 3.5 124 5.5S178 9.5 197 4' fill='none' stroke='%23f15d3e' stroke-width='3.5' stroke-linecap='round' vector-effect='non-scaling-stroke'/></svg>")
    no-repeat 0 calc(100% - 0.06em) / 100% 0.2em;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}
[dir="rtl"] .hero-mark { background-position-x: 100%; }
@media (prefers-reduced-motion: no-preference) {
  .js .hero-mark { animation: hero-mark-draw .9s var(--ease) .6s both; }
}
@keyframes hero-mark-draw { from { background-size: 0% 0.2em; } }

/* Proof card (ProofCard in home.jsx): in flow under the image, pulled up over its bottom
   inline-end corner. The width leaves the R badge (bottom inline-start, 72px from 22px) clear. */
.proof {
  position: relative; z-index: 3;
  width: min(78%, calc(100% - 132px)); margin: -96px 0 0; margin-inline: auto 16px;
  padding: 16px 18px; background: var(--paper); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 20px 40px -24px rgba(64, 37, 48, .45);
}
.proof-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 26px; }
.proof-label { font-size: var(--fs-label); letter-spacing: 0.08em; color: var(--ink-soft); }
.proof-name { margin-top: 8px; font-size: 22px; line-height: 1.15; font-weight: 500; }
[dir="rtl"] .proof-name { font-family: var(--arabic-display); line-height: 1.32; }
.proof-kind { margin-top: 4px; font-size: 14px; line-height: 1.45; color: var(--ink-soft); }
.proof-ticks { display: grid; gap: 6px; margin-top: 12px; font-size: 14px; line-height: 1.35; }
.proof-ticks li { display: flex; align-items: center; gap: 8px; }
.proof-ticks .tick { flex: none; }
.proof-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 12px; }
.proof-link { font-size: 14px; font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }
.proof-link:hover { color: var(--orange-cta); }
.proof-dots { display: flex; }
/* 24px hit area (WCAG 2.5.8) around an 8px dot */
.proof-dot { width: 24px; height: 24px; display: grid; place-items: center; border-radius: 50%; }
/* inactive #907d81 (ink-soft at 65% over paper) = 3.42:1, the 3:1 non-text minimum; active is ink */
.proof-dot::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: #907d81; transition: background .25s var(--ease); }
.proof-dot:hover::before { background: var(--ink-soft); }
.proof-dot[aria-pressed="true"]::before { background: var(--ink); }

@media (max-width: 920px) {
  .hero-grid { grid-template-columns: minmax(0, 1fr); }
  .hero-media { max-width: 460px; }
}
@media (max-width: 640px) {
  .hero-img { height: min(52vh, 420px); }
  /* under the image, no overlap: a full-width card would cover the R badge */
  .proof { width: auto; margin: 14px 0 0; }
}
@media (max-width: 400px) { .proof-ticks { display: none; } }

/* ============================================================
   PROCESS - a ledger on paper, not a band (REV-71 phase 1)
   The home page already spends its one tinted band on the region section, and
   the ink CTA band follows this section: sage here made three bands in four
   sections and put two bands back to back.
   ============================================================ */
.process-list { border-top: 1px solid var(--line); padding-inline-start: 34px; }
.process-row {
  position: relative;
  display: grid; grid-template-columns: 5fr 7fr; gap: 24px; align-items: baseline;
  padding: clamp(22px, 3vw, 34px) 0; border-bottom: 1px solid var(--line);
}
/* The line that runs beside the steps (2026-09-29). Each row owns one segment: ::before is the
   grey track, ::after the coloured fill, and a dot sits on the title. At rest, with no
   scroll-driven animation, the fill is complete and every dot is lit, so browsers without
   animation-timeline (Firefox, older Safari) and reduced-motion visitors see a finished line.
   The segments touch, so together they read as one line drawing down the list. */
.process-row::before, .process-row::after {
  content: ""; position: absolute; inset-inline-start: -29px; top: 0; bottom: -1px; width: 2px;
}
.process-row::before { background: var(--line); }
.process-row::after { background: var(--orange-cta); transform-origin: top; }
.process-t { position: relative; font-size: var(--fs-d3); line-height: var(--lh-d3); font-weight: 500; }
.process-t::before {
  content: ""; position: absolute; inset-inline-start: -35px; top: 0.5em;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--orange-cta); border: 2px solid var(--orange-cta);
}
.process-row:first-child::before, .process-row:first-child::after { top: 0.5em; }
.process-b { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--ink-soft); max-width: 44ch; }
@media (max-width: 760px) {
  .process-row { grid-template-columns: minmax(0, 1fr); gap: 8px; }
}
/* Project card (ProcessCard in home.jsx), above 880px only: steps on the 7/12 start track, title
   stacked over body so they do not cramp, and a sticky card on the 5/12 end track. At 880px and
   below the card is hidden and the ledger is exactly as before. */
.process-card { display: none; }
@media (min-width: 881px) {
  .process-split { display: grid; grid-template-columns: 7fr 5fr; gap: var(--gutter); align-items: start; }
  .process-split .process-row { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .process-card {
    display: block; position: sticky; top: 100px; align-self: start;
    padding: 26px 28px; background: var(--paper); border: 1px solid var(--line); border-radius: 14px;
    box-shadow: var(--shadow-media);
  }
}
.pc-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.pc-label { font-size: var(--fs-label); letter-spacing: 0.08em; color: var(--ink-soft); }
/* neutral, not .pill-ok: green on this site means /api/status said the system is up */
.pill-neutral {
  display: inline-flex; align-items: center; padding: 5px 10px; border-radius: 999px; white-space: nowrap;
  color: var(--ink-soft); box-shadow: inset 0 0 0 1px var(--line); font-size: var(--fs-label); letter-spacing: 0.08em; line-height: 1.2;
}
.pc-now { margin-top: 18px; font-size: var(--fs-d3); line-height: var(--lh-d3); font-weight: 500; }
.pc-list { display: grid; gap: 10px; margin-top: 20px; padding-top: 20px; border-top: 1px solid var(--line); font-size: 15px; line-height: 1.4; }
.pc-list li { display: flex; align-items: center; gap: 10px; color: var(--ink-soft); }
.pc-list li.now { color: var(--ink); font-weight: 600; }
.pc-mark {
  flex: none; width: 18px; height: 18px; display: grid; place-items: center; border-radius: 50%;
  border: 1.5px solid var(--line); color: transparent; font-size: 10px; line-height: 1;
}
.pc-list .done .pc-mark { background: var(--ok); border-color: var(--ok); color: var(--paper); }
.pc-list .now .pc-mark { border: 2px solid var(--orange-cta); }
.pc-body { margin-top: 20px; font-size: var(--fs-body); line-height: var(--lh-body); color: var(--ink-soft); }
@media (prefers-reduced-motion: no-preference) {
  .pc-mark { transition: background .3s var(--ease), border-color .3s var(--ease), color .3s var(--ease); }
}
/* Scroll-driven: no scroll listener, no state. Each row is its own view timeline (a named
   one, so the pseudo-elements can use it). The ranges are tuned so every row crosses the
   same "reading line" about 60% of the way down the viewport: a row's segment is empty
   while its top is below that line and full once its bottom is above it, so the segments
   fill one after another and read as a single line. (cover 35% to 50% is that crossing for
   a ~130px row in an ~800px viewport; on other sizes it is a little early or late, which
   only shifts when the fill happens.) */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .process-row { view-timeline: --prow block; }
    .process-t, .process-b { animation: prow-text linear both; animation-timeline: --prow; animation-range: cover 28% cover 36%; }
    .process-row::after { animation: prow-fill linear both; animation-timeline: --prow; animation-range: cover 35% cover 50%; }
    .process-t::before { animation: prow-dot linear both; animation-timeline: --prow; animation-range: cover 34% cover 38%; }
  }
}
@keyframes prow-text { from { opacity: 0.4; } }
@keyframes prow-fill { from { transform: scaleY(0); } }
@keyframes prow-dot { from { background: var(--paper); border-color: var(--line); } }

/* ============================================================
   RECENTLY SHIPPED (Shipped in home.jsx) - editorial split, 5/7
   ============================================================ */
.ship-grid { display: grid; grid-template-columns: 5fr 7fr; gap: var(--gutter); align-items: start; }
.ship-list { display: grid; }
.ship-row { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) auto; gap: 16px; align-items: baseline; padding: 20px 0; }
a.ship-row:hover .ship-text { color: var(--orange-cta); }
.ship-row + .ship-row { border-top: 1px solid var(--line); }
.ship-text { font-size: var(--fs-d3); line-height: var(--lh-d3); font-weight: 500; transition: color .25s var(--ease); }
.ship-kind { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--ink-soft); }
/* Status pill (REV-125): a live system, shown only on a true from /api/status, never a red state.
   Reused by the hero proof card and the case-study frame (the process card uses .pill-neutral). 4.88:1 text on tint. */
.pill-ok {
  display: inline-flex; align-items: center; gap: 7px; padding: 5px 10px; border-radius: 999px;
  color: var(--ok); background: var(--ok-tint); box-shadow: inset 0 0 0 1px var(--ok-line);
  font-size: var(--fs-label); letter-spacing: 0.08em; line-height: 1.2; white-space: nowrap;
}
.pill-ok i { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); display: block; flex: none; }
@media (prefers-reduced-motion: no-preference) { .pill-ok i { animation: ship-beat 1.8s ease-in-out infinite; } }
@keyframes ship-beat { 50% { transform: scale(1.6); opacity: .45; } }
@media (max-width: 820px) {
  .ship-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .ship-row { grid-template-columns: minmax(0, 1fr); gap: 4px; }
}

/* ============================================================
   CTA BAND
   ============================================================ */
/* isolation: the sage ShapeCluster (.cta-shapes, z-index -1) used to paint BEHIND this band's own
   background and never showed. Isolating the band makes it the stacking context, so the cluster
   sits on the ink where the pointer-aware motion can be seen. */
.cta-band { --cta-pad: clamp(60px, 10vh, 170px); background: var(--ink); color: var(--paper); padding-block: var(--cta-pad); position: relative; overflow: hidden; isolation: isolate; }
@media (max-width: 768px) { .cta-band { --cta-pad: 60px; } }
/* A sheet pulled up over the section before it (REV-125). What precedes it is paper with at least
   60px of bottom padding (a .section, .work-more-sec, or the 404 hero, padded in its own rule), so
   the 40px overlap only covers padding. A new page that puts the band after something else needs
   the same. At 320px the sky arc's ends sit ~15px inside the 40px corner, so the radius does not
   clip them. */
.cta-band { margin-top: -40px; border-start-start-radius: 40px; border-start-end-radius: 40px; box-shadow: 0 -24px 48px -28px rgba(64, 37, 48, .35); }
/* Ambient drift (2026-09-29): two soft colour fields wander slowly behind the text over a faint
   grain. Transform only, on the compositor. z-index -2 keeps it under the sage cluster (-1) and
   the copy. The fields peak at about a third opacity, which keeps the paper text above 7:1 on
   the brightest point. Reduced motion freezes them where they start. */
.cta-fx { position: absolute; inset: 0; z-index: -2; pointer-events: none; overflow: hidden; }
.cta-fx i { position: absolute; border-radius: 50%; will-change: transform; }
.cta-b1 { width: 380px; height: 380px; top: -120px; inset-inline-end: -80px; background: radial-gradient(circle, var(--sky-glow, rgba(241,93,62,.34)), transparent 66%); }
.cta-b2 { width: 340px; height: 340px; bottom: -140px; inset-inline-start: 20%; background: radial-gradient(circle, rgba(182,190,170,.22), transparent 66%); }
.cta-fx::after {
  content: ""; position: absolute; inset: 0; opacity: .09; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}
/* Sky (useSky in components.jsx): the first field takes the hour's glow colour, a sun by day or
   moon by night crosses a faint arc, and stars come out at night. Everything is inert until the
   hook has set --sky-* (prerender, no JS), so the plain band is the fallback. Physical left/top
   on purpose: the sky is a picture, not text, so it does not mirror in Arabic. */
.cta-stars { position: absolute; inset: 0; opacity: var(--sky-stars, 0); transition: opacity 1.2s ease; background:
  radial-gradient(1.2px 1.2px at 12% 22%, #fff, transparent), radial-gradient(1px 1px at 27% 12%, #fff, transparent), radial-gradient(1.4px 1.4px at 41% 30%, #fff, transparent),
  radial-gradient(1px 1px at 58% 16%, #fff, transparent), radial-gradient(1.2px 1.2px at 71% 28%, #fff, transparent), radial-gradient(1px 1px at 84% 14%, #fff, transparent),
  radial-gradient(1.2px 1.2px at 92% 34%, #fff, transparent), radial-gradient(1px 1px at 6% 40%, #fff, transparent); }
/* The arc and its dot live in the band's top padding, not across the whole band: the copy is a
   centred column, so an arc spanning the band crossed the headline for the middle half of the day
   at every width (on a phone it also hit the lead). --sky-dx/--sky-dy stay percentages, now of this
   strip, so useSky is unchanged and every hour lands above the first line. */
.cta-sky { position: absolute; inset-inline: 0; top: 0; height: calc(var(--cta-pad) - 14px); }
.cta-arc { position: absolute; inset: 0; width: 100%; height: 100%; }
.cta-arc path { fill: none; stroke: rgba(244, 241, 234, .14); stroke-width: 1; stroke-dasharray: 3 5; vector-effect: non-scaling-stroke; }
.cta-sun { width: 10px; height: 10px; border-radius: 50%; left: var(--sky-dx, 50%); top: var(--sky-dy, 50%); transform: translate(-50%, -50%);
  background: var(--sky-dot, #ecf163); box-shadow: 0 0 18px 5px var(--sky-halo, rgba(236, 241, 99, .35)); opacity: 0; }
.cta-band[data-sky] .cta-sun { opacity: .85; }
@media (prefers-reduced-motion: no-preference) {
  .cta-sun { transition: left 2s linear, top 2s linear, opacity .6s ease; }
}
@media (prefers-reduced-motion: no-preference) {
  .cta-b1 { animation: cta-drift-1 17s ease-in-out infinite alternate; }
  .cta-b2 { animation: cta-drift-2 23s ease-in-out infinite alternate; }
}
@keyframes cta-drift-1 { to { transform: translate(-90px, 70px) scale(1.15); } }
@keyframes cta-drift-2 { to { transform: translate(110px, -60px) scale(.9); } }
.cta-inner { position: relative; text-align: center; display: flex; flex-direction: column; align-items: center; }
.cta-shapes { position: absolute; top: -60px; right: 4%; opacity: 0.22; z-index: -1; }
[dir="rtl"] .cta-shapes { right: auto; left: 4%; }
/* Below 768px the headline wraps to the full column, so the top corner is under the first line.
   Park the cluster in the bottom corner instead, its R peeking up from the band's bottom edge
   below the last line (the svg has ~43px of empty viewBox under the mark, hence -120px). */
@media (max-width: 768px) { .cta-shapes { top: auto; bottom: -120px; } }
.cta-title { font-size: var(--fs-d1); line-height: var(--lh-d1); font-weight: 500; letter-spacing: -0.02em; }
.cta-line { display: inline; }
[dir="rtl"] .cta-title { padding-block: 0.04em; }
.cta-body { font-size: var(--fs-lead); line-height: var(--lh-lead); max-width: 44ch; margin: 26px auto 36px; opacity: 0.82; }
.cta-actions { display: flex; gap: 14px; flex-wrap: wrap; justify-content: center; }
/* .btn-ghost is ink-on-paper by default, i.e. invisible on this ink band.
   Repaint it for the band rather than adding a fifth button variant. */
.cta-actions .btn-ghost { color: var(--paper); border-color: rgba(244, 241, 234, 0.5); }
.cta-actions .btn-ghost:hover { background: var(--paper); color: var(--ink); border-color: var(--paper); }
/* Same ink-band repaint as .btn-ghost above: .link-arrow's hover border
   defaults to --ink, invisible on this background. */
.cta-deck-link { margin-top: 22px; }
.cta-deck-link:hover { border-color: var(--paper); }
/* paper-on-ink micro-label - opacity .7 per the accessibility baseline
   (CLAUDE.md #9: .5/.62 fails AA on this background). */
.cta-deck-meta { display: block; margin-top: 6px; font-size: 12.5px; opacity: 0.7; }

/* ============================================================
   PAGE HERO (inner pages)
   ============================================================ */
.page-hero { padding-top: clamp(130px, 18vh, 200px); padding-bottom: clamp(20px, 4vw, 40px); }
/* Tiny-R grid (2026-09-29, owner asked for the R mark instead of dots): on the About and Services
   heroes a faint grid of small R marks sits behind the copy, and the ones near the pointer light
   up orange. Two pseudo-element layers of the same SVG tile - ink underneath, orange on top with
   a radial mask centred on --px/--py (set by usePointerGrid). Mouse devices without reduced
   motion only; everyone else gets the plain hero. --orange is decorative here, never text. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .r-grid { position: relative; isolation: isolate; }
  .r-grid > * { position: relative; z-index: 1; }
  .r-grid::before, .r-grid::after {
    content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
    background-size: 26px 26px; background-position: 6px 8px;
  }
  .r-grid::before {
    opacity: .1;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='26' height='26' viewBox='0 0 26 26'><g transform='translate(7 7.5) scale(.0208) translate(-212 -236)' fill='%23402430'><ellipse cx='585' cy='391' rx='162' ry='159'/><rect x='212' y='236' width='210' height='531'/><polygon points='425 550 702 550 788 765 508 765 425 550'/></g></svg>");
  }
  .r-grid::after {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='26' height='26' viewBox='0 0 26 26'><g transform='translate(7 7.5) scale(.0208) translate(-212 -236)' fill='%23f15d3e'><ellipse cx='585' cy='391' rx='162' ry='159'/><rect x='212' y='236' width='210' height='531'/><polygon points='425 550 702 550 788 765 508 765 425 550'/></g></svg>");
    -webkit-mask-image: radial-gradient(circle 130px at var(--px, -500px) var(--py, -500px), #000, transparent);
    mask-image: radial-gradient(circle 130px at var(--px, -500px) var(--py, -500px), #000, transparent);
  }
}
.page-hero-title { font-size: var(--fs-d1); line-height: var(--lh-d1); font-weight: 500; margin: 24px 0 0; letter-spacing: -0.03em; max-width: 16ch; }
.ph-line { display: block; }
[dir="rtl"] .page-hero-title { padding-block: 0.04em; }
.page-hero-lead { font-size: var(--fs-lead); line-height: var(--lh-lead); max-width: 56ch; margin-top: 30px; color: var(--ink-soft); }

/* 404 numeral - an ornament sized to its own geometry (outside the type
   scale, like the other ornaments): reads at a glance on desktop, and the
   clamp floor keeps all three digits on one line down to 320px screens. */
.page-hero-title .notfound-code { font-size: clamp(88px, 17vw, 220px); line-height: 1; font-weight: 500; letter-spacing: -0.04em; }
/* the numeral opens the title - halve the eyebrow gap so the label reads with it. */
.page-notfound .page-hero-title { margin-top: 12px; }
/* the 404 hero is followed straight by the CTA sheet, which pulls up 40px: give its buttons room */
.page-notfound .page-hero { padding-bottom: var(--section-y); }

/* ============================================================
   ABOUT
   ============================================================ */
.about-blocks { border-top: 1px solid var(--line); }
.about-block {
  display: grid; grid-template-columns: 5fr 7fr; gap: var(--gutter);
  align-items: baseline; padding-block: clamp(22px, 3vw, 32px);
  border-bottom: 1px solid var(--line);
}
.about-block-t { font-size: var(--fs-d3); line-height: var(--lh-d3); font-weight: 500; margin: 16px 0 14px; }
.about-block-b { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--ink-soft); }
@media (max-width: 820px) { .about-block { grid-template-columns: minmax(0, 1fr); gap: 10px; } }


/* A ledger on paper, not an ink band (owner, REV-71 round 9): the ink CtaBand
   follows this section, so ink here put two dark sections back to back and gave
   About two ink bands. One ink band per page, and it is the last one. */
.values-grid { display: grid; grid-template-columns: 5fr 7fr; gap: var(--gutter); align-items: start; }
.values-shape { margin-top: 30px; opacity: 0.85; }
.values-list { border-top: 1px solid var(--line); }
.values-item {
  padding: clamp(20px, 3vw, 32px) 0; border-bottom: 1px solid var(--line);
  font-size: var(--fs-d2); line-height: var(--lh-d2); transition: padding-inline .4s var(--ease), color .3s;
}
.values-item .display { font-weight: 500; }
/* yellow-on-paper is ~1.2:1 - the ink band it used to hover against is gone */
.values-item:hover { padding-inline-start: 16px; color: var(--orange-cta); }
@media (max-width: 820px) {
  .values-grid { grid-template-columns: minmax(0, 1fr); }
  .values-shape { display: none; }
}

/* ============================================================
   WORK - & more
   ============================================================ */
.work-more-sec {
  border-top: 1px solid var(--line);
  padding-block: clamp(60px, 9vh, 110px);
}
.work-more-inner {
  display: flex; align-items: baseline; gap: clamp(30px, 6vw, 90px);
  flex-wrap: wrap;
}
.work-more-amp {
  font-size: clamp(64px, 11vw, 150px); font-weight: 500;
  letter-spacing: -0.04em; line-height: 0.9;
  color: var(--ink); opacity: 0.13;
  flex-shrink: 0; user-select: none;
  transition: opacity .5s var(--ease);
}
.work-more-sec:hover .work-more-amp { opacity: 0.22; }
[dir="rtl"] .work-more-amp { font-family: var(--arabic-display); opacity: 0.15; }
.work-more-copy { display: flex; flex-direction: column; gap: 18px; max-width: 44ch; }
.work-more-body { font-size: var(--fs-lead); line-height: var(--lh-lead); color: var(--ink-soft); }
@media (max-width: 600px) {
  .work-more-inner { flex-direction: column; gap: 20px; }
  .work-more-amp { font-size: clamp(64px, 18vw, 100px); }
}

/* ============================================================
   CONTACT
   ============================================================ */
.contact-grid { display: grid; grid-template-columns: 7fr 5fr; gap: var(--gutter); align-items: start; }
.contact-deck-prompt { margin-bottom: 18px; font-size: 14.5px; }
.contact-deck-prompt .link-arrow { margin-inline-start: 6px; }
.contact-form { display: flex; flex-direction: column; gap: 22px; }
/* Honeypot spam trap: off-screen, invisible to humans, present for bots */
/* honeypot: clipped rather than pushed 5000px off-canvas - an off-canvas element
   on an RTL page extends the document's scrollWidth and can produce a horizontal
   scrollbar. clip-path removes it from paint without moving it. */
.gotcha { position: absolute; width: 1px; height: 1px; overflow: hidden; opacity: 0; clip-path: inset(50%); }
.field-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 22px; }
.field { display: flex; flex-direction: column; gap: 9px; }
.field-label { font-size: var(--fs-label); letter-spacing: 0.08em; color: var(--ink-soft); } /* 8.3:1 on paper. A colour, not opacity .8: opacity also faded the asterisk and (optional) to 3.2:1 and 3.8:1 (REV-101) */
/* which fields are compulsory has to be visible before the browser rejects the
   submit, not after: phone is required here and an EN/AR visitor cannot guess it */
.field-req { color: var(--orange-text); margin-inline-start: 4px; } /* 5.80:1 on paper (REV-101) */
.field-optional { margin-inline-start: 6px; text-transform: none; letter-spacing: 0.04em; }
.field-input {
  font-family: var(--sans); font-size: 16px; color: var(--ink);
  background: transparent; border: none; border-bottom: 1.5px solid var(--line);
  padding: 11px 2px; transition: border-color .3s var(--ease);
}
/* text-align follows the page direction: without it the phone and email fields
   (which browsers keep LTR) leave the typed value stranded on the left of an
   otherwise right-aligned Arabic form */
[dir="rtl"] .field-input { font-family: var(--arabic-sans); text-align: right; }
/* Underline that draws in on focus (2026-09-29): the orange line is .field::after, scaled from the
   reading-direction start, and the input's own border stays neutral so the draw is visible.
   Reduced motion keeps the original instant border-colour change. */
@media (prefers-reduced-motion: no-preference) {
  .field { position: relative; }
  .field::after {
    content: ""; position: absolute; inset-inline: 0; bottom: 0; height: 1.5px; background: var(--orange-cta);
    transform: scaleX(0); transform-origin: left; transition: transform .45s var(--ease); pointer-events: none;
  }
  [dir="rtl"] .field::after { transform-origin: right; }
  .field:focus-within::after { transform: none; }
  .field .field-input:focus { border-color: var(--line); }
}
.field-input:focus { outline: none; border-color: var(--orange-cta); } /* --orange was 2.9:1 vs paper; -cta = 4.1:1 (WCAG 1.4.11) */
textarea.field-input { resize: vertical; min-height: 120px; }
.contact-submit { align-self: flex-start; margin-top: 8px; margin-bottom: 16px; }
.form-error {
  display: flex; align-items: flex-start; gap: 14px;
  margin-top: 4px; padding: 14px 16px; border-radius: 12px;
  background: var(--paper-2);
  font-size: 15px; line-height: 1.5; max-width: 52ch;
}
.form-error-tile { flex: none; width: 44px; height: 44px; display: grid; place-items: center; border-radius: 10px; background: var(--orange-text); color: var(--paper); }
.form-error-ribbon { display: block; width: 24px; height: 4px; border-radius: 2px; background: var(--orange); margin-block: 4px 8px; }
.form-error-title { font-weight: 600; }
/* busy submit (Contact in pages.jsx): one press only; the spinner takes the arrow's 16px box */
.contact-submit[aria-busy="true"] { pointer-events: none; }
.spin { display: inline-block; flex: none; width: 16px; height: 16px; border-radius: 50%; border: 2px solid currentColor; border-inline-end-color: transparent; }
@media (prefers-reduced-motion: no-preference) { .spin { animation: spin .8s linear infinite; } }
@keyframes spin { to { transform: rotate(1turn); } }
/* privacy line under the submit button - 13.5px at the .8 opacity AA floor, and
   the link is underlined so it is not distinguished by colour alone */
.form-privacy { font-size: 13.5px; line-height: 1.55; opacity: 0.8; max-width: 52ch; margin-top: 4px; }
.form-privacy a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.form-privacy a:hover { color: var(--orange-cta); }

.contact-details { background: var(--paper-2); border-radius: var(--radius-lg); padding: clamp(28px, 3.5vw, 44px); }
.contact-details-h { font-size: var(--fs-label); letter-spacing: 0.08em; opacity: 0.8; margin-bottom: 28px; } /* was .5: 2.8:1 on paper-2; .8 = 6.5:1 (AA) */
.contact-detail { padding: 20px 0; border-top: 1px solid var(--line); }
.contact-detail:first-of-type { border-top: none; padding-top: 0; }
.copy-btn { margin-inline-start: 12px; min-height: 24px; padding: 2px 10px; border: 1px solid currentColor; border-radius: 999px; background: transparent; color: inherit; opacity: .82; font-size: 11.5px; letter-spacing: .06em; text-transform: uppercase; cursor: pointer; vertical-align: middle; }
.copy-btn:hover { opacity: 1; }
.copy-status { margin-inline-start: 10px; font-size: 12.5px; vertical-align: middle; }
.copy-ok { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; }
.contact-detail-l { display: block; font-size: var(--fs-label); letter-spacing: 0.08em; opacity: 0.8; margin-bottom: 10px; } /* was .55: 3.2:1 on paper-2; .8 = 6.5:1 (AA) */
/* block, so the city line and the phone link below it do not run together as
   one string ("Tripoli, Libya+218 94 403 2503") */
.contact-detail-v { display: block; font-size: var(--fs-d3); line-height: var(--lh-d3); font-weight: 500; transition: color .25s; }
a.contact-detail-v:hover { color: var(--orange-cta); text-decoration: underline; }
.contact-detail-p { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--ink-soft); margin-bottom: 12px; }
/* the reply promise sits above the first detail row, so it carries its own gap */
.contact-promise { margin-bottom: 24px; }
@media (max-width: 820px) { .contact-grid { grid-template-columns: minmax(0, 1fr); }
  .field-row { grid-template-columns: minmax(0, 1fr); }
}

/* ---- book a phone call (Calendly embed) ---- */
.contact-book-sec { background: var(--sage); scroll-margin-top: 90px; }
.contact-book-head { max-width: 60ch; margin-bottom: clamp(30px, 4vw, 52px); }
.contact-book-title { font-size: var(--fs-d2); line-height: var(--lh-d2); font-weight: 500; margin-top: 18px; }
.contact-book-lead { font-size: var(--fs-lead); line-height: var(--lh-lead); color: var(--ink-soft); margin-top: 22px; max-width: 52ch; }
/* Arabic-only WhatsApp CTA above the English-only Calendly widget */
.contact-book-alt { display: flex; margin-bottom: 22px; }

.calendly-frame {
  position: relative;
  min-height: 700px;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--line);
  background: #b5bfaa; /* matches widget bg so it blends seamlessly during load */
  box-shadow: 0 18px 50px -28px rgba(64, 37, 48, 0.45);
}
/* no min-width: 320px here - with the section padding it overflowed the
   viewport on a 320px phone and scrolled the whole page sideways */
.calendly-target { width: 100%; height: 700px; }
@media (max-width: 600px) {
  .calendly-frame { min-height: 1000px; }
  .calendly-target { height: 1000px; }
}
.calendly-loading {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  pointer-events: none;
}
.calendly-loading .mono {
  font-size: var(--fs-label); letter-spacing: 0.08em;
  color: var(--ink-soft); opacity: 0.7;
  animation: calendly-pulse 1.6s var(--ease) infinite;
}
@keyframes calendly-pulse { 0%, 100% { opacity: 0.35; } 50% { opacity: 0.8; } }
@media (prefers-reduced-motion: reduce) {
  .calendly-loading .mono { animation: none; }
}

/* ============================================================
   NEW SECTIONS (five-pillar restructure)
   All contrast values kept at the AA baseline set in commit c027471:
   micro-labels at opacity .8, ink-soft or full ink for body copy.
   ============================================================ */

/* ---- credibility strip (home) ---- */
/* Light strips (credibility, credentials) sit tighter than full sections so the page
   rhythm is not one metronomic padding value (de-slop pass, 2026-09-10). */
.cred-sec, .svc-cred-sec, .about-cred-sec { padding-block: clamp(48px, 7vh, 90px); }
.cred-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--gutter); margin-top: 30px;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding-block: clamp(22px, 3vw, 30px);
}
.cred-item { display: flex; flex-direction: column; gap: 8px; }
.cred-k { font-size: var(--fs-d3); line-height: var(--lh-d3); font-weight: 500; }
/* Online dot before a product name (SystemNames in components.jsx). Green is the one place the site
   uses a status colour; --ok is 5.76:1 on paper, above the 3:1 non-text minimum. */
.sys-name { white-space: nowrap; }
.sys-up { position: relative; display: inline-block; width: 0.32em; height: 0.32em; margin-inline-end: 0.28em; border-radius: 50%; background: var(--ok); vertical-align: 0.3em; }
@media (prefers-reduced-motion: no-preference) {
  .sys-up::after { content: ""; position: absolute; inset: -0.22em; border-radius: 50%; border: 1.5px solid var(--ok); opacity: 0; animation: sys-ring 2.6s ease-out infinite; }
}
@keyframes sys-ring { 0% { transform: scale(.6); opacity: .7; } 100% { transform: scale(1.7); opacity: 0; } }
.cred-v { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--ink-soft); }
/* privacy page analytics opt-out (REV-122): the button sits under its status line */
.optout .btn { margin-top: 20px; }
.cred-note { margin-top: 28px; font-size: 13.5px; line-height: 1.6; color: var(--ink-soft); max-width: 68ch; }
/* Ledger rules draw in (2026-09-29): the two hairlines that frame a ledger are pseudo-elements
   that run across from the reading-direction start when the ledger scrolls into view, then the
   rows' own reveals settle in behind them. .ledger goes on a <Reveal>, which supplies .in.
   At rest (in, reduced motion, noscript) the rules are simply there. The grid container itself
   does not fade: its rows do. */
.ledger { position: relative; border-block: none; }
.ledger.reveal { opacity: 1; transform: none; }
.ledger::before, .ledger::after {
  content: ""; position: absolute; inset-inline: 0; height: 1px; background: var(--line);
  transform-origin: left; transition: transform 1s var(--ease);
}
.js .ledger::before, .js .ledger::after { transform: scaleX(0); }
.ledger::before { top: 0; }
.ledger::after { bottom: 0; transition-delay: .25s; }
.ledger.in::before, .ledger.in::after { transform: none; }
[dir="rtl"] .ledger::before, [dir="rtl"] .ledger::after { transform-origin: right; }
@media (prefers-reduced-motion: reduce) { .js .ledger::before, .js .ledger::after { transform: none; transition: none; } }
@media (max-width: 900px) { .cred-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) {
  .cred-grid { grid-template-columns: minmax(0, 1fr); gap: 0; padding-block: 0; border-bottom: none; }
  .cred-grid.ledger::after { display: none; } /* the last row carries its own rule here */
  .cred-item { padding-block: 15px; border-bottom: 1px solid var(--line); }
}

/* ---- problems (home) ---- */
.problems-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; }
.problem-card { background: var(--paper); padding: clamp(26px, 3vw, 40px); }
.problem-t { font-size: var(--fs-d3); line-height: var(--lh-d3); font-weight: 500; margin-bottom: 12px; }
.problem-b { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--ink-soft); max-width: 46ch; }
@media (max-width: 760px) { .problems-grid { grid-template-columns: minmax(0, 1fr); } }

/* ---- pillar list (home) ---- */
.pillar-list { border-top: 1px solid var(--line); }
.pillar-hit {
  display: grid; grid-template-columns: 5fr 7fr 30px; gap: 22px; align-items: baseline;
  padding: clamp(22px, 3vw, 32px) 0; border-bottom: 1px solid var(--line);
  transition: padding-inline .4s var(--ease), background .3s var(--ease);
}
.pillar-hit:hover { padding-inline-start: 14px; background: var(--paper-2); }
.pillar-name { font-size: var(--fs-d3); line-height: var(--lh-d3); font-weight: 500; }
.pillar-body { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--ink-soft); }
.pillar-arrow { margin-inline-end: 8px; color: var(--orange-cta); opacity: 0; transform: translateX(-6px); transition: opacity .3s var(--ease), transform .3s var(--ease); }
.pillar-hit:hover .pillar-arrow { opacity: 1; transform: none; }
[dir="rtl"] .pillar-arrow { transform: translateX(6px) scaleX(-1); }
[dir="rtl"] .pillar-hit:hover .pillar-arrow { transform: scaleX(-1); }
@media (max-width: 860px) {
  .pillar-hit { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .pillar-arrow { display: none; }
}

/* ---- region advantage (home) ---- */
.region-sec { background: var(--sage); }
.region-grid { display: grid; grid-template-columns: 7fr 5fr; gap: var(--gutter); align-items: start; }
.region-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 26px; margin-top: 8px; }
.region-item {
  padding: 15px 0; border-bottom: 1px solid var(--line-strong);
  font-size: var(--fs-body); line-height: var(--lh-body);
}
@media (max-width: 900px) {
  .region-grid { grid-template-columns: minmax(0, 1fr); }
  .region-list { grid-template-columns: minmax(0, 1fr); }
}

/* ---- credentials (about + services) ---- */
.cred-logos { display: flex; flex-wrap: wrap; gap: clamp(24px, 4vw, 56px); margin-top: 34px; align-items: baseline; }
.cred-logo { font-size: var(--fs-d2); line-height: var(--lh-d2); font-weight: 500; letter-spacing: -0.02em; }
.cred-tags { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 26px; }
.cred-tag {
  font-size: var(--fs-label); letter-spacing: 0.08em;
  padding: 8px 14px; border: 1px solid var(--line); border-radius: 999px;
}
.svc-cred-sec { background: var(--paper-2); }

/* ---- case studies (work) ---- */
.studies { display: flex; flex-direction: column; gap: clamp(48px, 8vw, 110px); }
/* The same 5/7 split for every study in both languages (owner, REV-71 round 10):
   image on the narrow leading track, text on the wide one. The zigzag it
   replaces flipped the image to `order: 2` on even studies and needed an RTL
   reset, which put the image on a different track in EN and AR. */
.study { display: grid; grid-template-columns: 5fr 7fr; gap: var(--gutter); align-items: center; }
/* Browser frame around a study's screen (Study in pages.jsx). The frame carries the shadow; the
   inner .study-mask is what wipes open, so the clip never cuts the shadow off. */
.study-frame { background: var(--paper); border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--shadow-media); overflow: hidden; }
.study-bar { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-bottom: 1px solid var(--line); }
.study-dots { display: flex; gap: 5px; flex: none; }
.study-dots i { width: 8px; height: 8px; border-radius: 50%; background: var(--line-strong); }
.study-addr {
  flex: 1; min-width: 0; padding: 3px 12px; border-radius: 999px; background: var(--paper-2);
  font-size: 12.5px; color: var(--ink-soft); text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.study-frame .ph { border-radius: 0; }
@media (prefers-reduced-motion: no-preference) {
  .study-mask { transition: clip-path 1s var(--ease) .1s; }
  .study-mask .ph-img { transition: filter .5s ease, transform 1.2s var(--ease) .1s; }
  .js .study:not(.in) .study-mask { clip-path: inset(0 0 100% 0); }
  .js .study:not(.in) .study-mask .ph-img { transform: scale(1.06); }
}
/* a study with no real screen: the copy takes all 12 columns, no empty track */
.study-copy:only-child { grid-column: 1 / -1; }
.study-name { font-size: var(--fs-d2); line-height: var(--lh-d2); font-weight: 500; letter-spacing: -0.02em; }
.study-kind { display: block; font-size: var(--fs-label); letter-spacing: 0.08em; opacity: 0.8; margin: 10px 0 18px; }
.study-body { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--ink-soft); max-width: 48ch; }
/* client-supplied number and quote - render only when the client gave us one */
.study-metric { margin-top: 18px; font-size: var(--fs-label); letter-spacing: 0.08em; opacity: 0.9; }
.study-quote {
  margin-top: 18px; padding-inline-start: 16px; border-inline-start: 3px solid var(--orange);
  font-size: var(--fs-lead); line-height: var(--lh-lead); max-width: 48ch;
}
.study-quote-by { display: block; margin-top: 10px; font-size: var(--fs-label); letter-spacing: 0.08em; opacity: 0.8; font-style: normal; }
.study-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; }
.study-tag { font-size: var(--fs-label); letter-spacing: 0.08em; padding: 6px 12px; border: 1px solid var(--line); border-radius: 999px; }
.study-link { margin-top: 22px; display: inline-flex; }
@media (max-width: 820px) {
  .study { grid-template-columns: minmax(0, 1fr); gap: 22px; }
}

/* ---- services pillars (services page) ---- */
.pillars { display: flex; flex-direction: column; gap: clamp(56px, 9vw, 120px); }
.pillar { display: grid; grid-template-columns: 5fr 7fr; gap: var(--gutter); align-items: start; scroll-margin-top: 100px; }
.pillar-head { grid-column: 1 / -1; }
.pillar-title { font-size: var(--fs-d2); line-height: var(--lh-d2); font-weight: 500; letter-spacing: -0.02em; margin: 12px 0 16px; }
.pillar-lead { font-size: var(--fs-lead); line-height: var(--lh-lead); color: var(--ink-soft); max-width: 62ch; }
.pillar-media .ph { box-shadow: var(--shadow-media); }
/* Three chunks side by side, one column each (owner, REV-71 round 10). The
   two-per-row grid inside each chunk left an orphan row whenever a chunk held
   an odd number of items, which is most of them. */
.pillar-items { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gutter); align-self: start; }
/* a pillar with no real screen renders as a ledger: the items take the full
   12 columns instead of sitting in the text track with an empty image track */
.pillar-items:nth-child(2), .pillar-diagram + .pillar-items { grid-column: 1 / -1; }
/* AI pillar diagram (PillarDiagram in pages.jsx). It takes the full row like the ledger, capped
   so the type inside stays close to body size. Line art in the ink/paper tokens. */
.pillar-diagram { grid-column: 1 / -1; max-width: 720px; display: grid; gap: 12px; margin: 4px 0 8px; }
.pillar-diagram svg { width: 100%; height: auto; display: block; }
.pillar-diagram figcaption { font-size: var(--fs-label); letter-spacing: 0.06em; opacity: 0.8; }
.dg-bound { fill: none; stroke: var(--ink); stroke-width: 1.2; stroke-dasharray: 5 4; opacity: 0.55; }
.dg-bound-t { font: 600 9.5px var(--sans); letter-spacing: 0.08em; text-transform: uppercase; fill: var(--ink); opacity: 0.8; }
[dir="rtl"] .dg-bound-t { letter-spacing: 0; }
.dg-node { fill: var(--paper); stroke: var(--ink); stroke-width: 1.4; }
.dg-node-t { font: 600 11.5px var(--sans); fill: var(--ink); }
.dg-wire { stroke: var(--ink); stroke-width: 1.4; opacity: 0.5; }
.dg-pulse { fill: var(--orange-cta); opacity: 0; }
@media (prefers-reduced-motion: no-preference) {
  .dg-pulse { animation: dg-pulse 2.2s cubic-bezier(.4, 0, .2, 1) infinite; }
}
.dg-loop { fill: none; stroke: var(--orange-cta); stroke-width: 1.4; stroke-dasharray: 4 5; }
.dg-arrow { fill: var(--orange-cta); }
.dg-loop-t { font: 600 9.5px var(--sans); letter-spacing: 0.06em; text-transform: uppercase; fill: var(--ink); opacity: 0.8; }
[dir="rtl"] .dg-loop-t { letter-spacing: 0; }
@media (prefers-reduced-motion: no-preference) { .dg-loop { animation: dg-dash 1.4s linear infinite; } }
@keyframes dg-dash { to { stroke-dashoffset: -18; } }
@keyframes dg-pulse { 0% { transform: translateX(0); opacity: 0; } 15%, 85% { opacity: 1; } 100% { transform: translateX(var(--tx)); opacity: 0; } }
/* one rule per chunk, not per row: twelve hairlines under twelve one-line items
   read as a table of contents, three read as three groups */
.pillar-chunk { padding-top: 14px; border-top: 1px solid var(--line); }
.pillar-chunk li { padding: 5px 0; font-size: var(--fs-body); line-height: var(--lh-body); }
@media (max-width: 820px) {
  .pillar { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .pillar-items { grid-template-columns: minmax(0, 1fr); gap: 22px; }
}

/* ---- insights ---- */
/* the CTA band pulls up 40px over what precedes it, so the index ends on a full section's paper */
.insights-index { padding-bottom: var(--section-y); }
.ins-index-list { border-top: 1px solid var(--line); }
.ins-index-list li a {
  display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap;
  padding: 16px 0; border-bottom: 1px solid var(--line);
  transition: padding-inline .35s var(--ease);
}
.ins-index-list li a:hover { padding-inline-start: 12px; }
/* Kicker is a fixed column and the title wraps inside its own: a long title stays beside its
   kicker instead of dropping to its own row. Below ~400px of room the title takes the next row. */
.ins-index-kicker { font-size: var(--fs-label); letter-spacing: 0.08em; opacity: 0.8; flex: 0 0 112px; }
.ins-index-title { font-size: var(--fs-d3); line-height: var(--lh-d3); font-weight: 500; flex: 1 1 260px; min-width: 0; }
.ins-article { max-width: 68ch; margin: 0 auto; }
.ins-body p { font-size: var(--fs-body); line-height: var(--lh-body); margin-bottom: 20px; }
.ins-body p:last-child { margin-bottom: 0; }
.ins-byline { font-size: var(--fs-label); letter-spacing: 0.08em; opacity: 0.8; margin-top: 22px; }
.ins-back { margin-top: 44px; }

/* ---- services FAQ ----
   Native <details>/<summary>: no JS, and a non-JS crawler reads every answer
   (the same Q&As ship as FAQPage JSON-LD, see build.mjs). */
.faq-list { border-top: 1px solid var(--line); max-width: 80ch; margin-top: clamp(24px, 3vw, 38px); }
.faq-item { border-bottom: 1px solid var(--line); }
.faq-q {
  display: flex; align-items: baseline; gap: 16px; cursor: pointer;
  padding: 18px 0; font-size: var(--fs-d3); line-height: var(--lh-d3); font-weight: 500;
  list-style: none; /* Firefox marker */
}
.faq-q::-webkit-details-marker { display: none; }
.faq-q::after {
  content: "+"; margin-inline-start: auto; font-family: var(--mono);
  font-size: 20px; line-height: 1; opacity: 0.8; transition: transform .25s var(--ease);
}
.faq-item[open]:not([data-closing]) .faq-q::after { content: "-"; }
.faq-q:hover { color: var(--orange-cta); }
.faq-a { padding-bottom: 22px; font-size: var(--fs-body); line-height: var(--lh-body); color: var(--ink-soft); max-width: 68ch; }
[dir="rtl"] .faq-q { font-family: var(--arabic-display); line-height: 1.5; }
