/* ============================================================================
   ABiL — inner pages, ported from the v3p-* block in AbilV3Pages.tsx
   (lines 1864-2425).

   In the React source the inner pages carry a full second copy of the shell
   under a v3p- prefix. Comparing the two showed the base layer is the same:
   of the typography, mask and reveal primitives only four rules actually
   differ, and 28 of the shell rules are byte for byte identical. Duplicating
   all of that here would mean maintaining the same styles twice, so the theme
   keeps one base in main.css and expresses the inner pages as a modifier on
   body.abil-inner. Only the rules that genuinely differ live below.

   Component classes keep their v3p-* names so they still map onto the source.
   ============================================================================ */

/* ---------- what differs between the home shell and the inner shell ---------- */

/* The bar is opaque from the start here, where the home page starts transparent. */
.abil-inner .v3-nav { background: var(--ab-alpin); }
/* The bar turns citron once the page is scrolled, on the inner pages as
   much as on the home page: the white above wins on equal specificity
   because this file loads last, so the scrolled state is restated here. */
.abil-inner .v3-nav.rolled { background: var(--ab-citron); }

/* Lists on the inner pages carry no markers. In the source this is a blanket
   rule on the page root (.v3p-root ul); the home page never needed it because
   every list there sets list-style itself. */
.abil-inner ul, .abil-inner ol { list-style: none; }

/* Paragraphs are set larger and lighter on the inner pages, and not uppercased. */
.abil-inner .v3-p { line-height: 1.35; font-weight: 400; text-transform: none; }

/* Short pages must still push the footer below the fold. */
.abil-inner .v3-main { min-height: 60vh; }

/* The counter next to a menu item shows inside the overlay at every width. */
.abil-inner .v3-overlay .v3-count { display: inline; }

/* The overlay links are set smaller and further apart than on the home page. */
.abil-inner .v3-overlay-links { gap: 2vw; }
.abil-inner .v3-overlay-links .v3-biglink { font-size: 6vw; padding: .2em 0 .3em; margin: -.2em 0 -.3em; }

/* ---------- page head: title, count, filter, view toggle ---------- */

.v3p-workhead { padding-top: 1vw; display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; column-gap: 2vw; align-items: end; margin-bottom: 2.4vw; }
.v3p-workhead-title { display: flex; align-items: flex-start; overflow: hidden; min-width: min-content; padding: .32em .06em .78em; margin: -.32em -.06em -.78em; }
.v3p-worknum { margin-top: .3vw; margin-left: .8vw; font-size: 1.6vw; line-height: 1; }
.v3p-filterwrap { position: relative; grid-column: 3/4; align-self: end; padding-bottom: .6vw; }

/* Opens to its measured height over 1s; closes on outside click, Escape or scroll. */
.v3p-dropdown {
	position: absolute; top: 100%; left: 0; z-index: 40; margin-top: .6vw;
	background: var(--ab-alpin); border: 1px solid var(--ab-leman); border-radius: 5px;
	overflow: hidden; min-width: 14vw; height: 0; visibility: hidden;
	transition: height 1s cubic-bezier(.25,1,.5,1), visibility 0s linear 1s;
}
.v3p-dropdown.open { visibility: visible; transition: height 1s cubic-bezier(.25,1,.5,1), visibility 0s; }
.v3p-dropdown > div { display: flex; flex-direction: column; }
.v3p-droplabel { padding: .8vw .9vw; white-space: nowrap; }
.v3p-droplabel:hover { background: var(--ab-leman); }
.v3p-droplabel.on { background: var(--ab-noir); color: var(--ab-alpin); }
.v3p-filterwrap .v3p-dropdown { margin-top: 28px; }

/* A capsule with a dark pill that slides under the labels and follows the
   pointer on hover, returning to the active item when it leaves. */
.v3p-viewtoggle {
	grid-column: 4/5; justify-self: end; align-self: end; margin-bottom: .4vw;
	display: flex; padding: 4px; border: 1px solid var(--ab-leman); border-radius: 10vw; position: relative;
}
.v3p-hoverpill {
	position: absolute; top: 4px; bottom: 4px; left: 0; background: var(--ab-noir); border-radius: 999px;
	transition: transform .2s cubic-bezier(.645,.045,.355,1), width .2s cubic-bezier(.645,.045,.355,1);
}
.v3p-switch { padding: 8px 18px; border-radius: 999px; position: relative; z-index: 1; transition: color .2s cubic-bezier(.645,.045,.355,1); }
.v3p-switch.lit { color: var(--ab-alpin); }

/* An element that sets its own display ignores the hidden attribute: a plain
   class selector outranks the browser's [hidden] { display: none }. The filter
   and the view toggle both hide things this way, so it has to be restated. */
.v3p-work[hidden],
.v3p-listrow[hidden],
.v3p-workgrid[hidden],
.v3p-worklist[hidden] { display: none; }

/* ---------- grid view ---------- */

.v3p-workgrid { position: relative; margin: 0 1vw; min-height: 100vh; }
.v3p-bordv { position: absolute; left: 50%; top: 1vw; width: 1px; height: 0; background: var(--ab-noir); transition: height 6s cubic-bezier(.3,.3,0,1); transition-delay: var(--d,0s); }
.v3-io.in .v3p-bordv { height: calc(100% - 1vw); }
.v3p-works { position: relative; display: grid; grid-template-columns: 1fr 1fr; }
.v3p-work { position: relative; display: flex; flex-direction: column; justify-content: space-between; padding: 1vw 1vw 0; cursor: pointer; }
.v3p-work-visual { position: relative; width: 100%; height: 34vw; overflow: hidden; display: flex; align-items: center; justify-content: center; }
.v3p-work-visual img, .v3p-work-visual video { width: 100%; height: 100%; object-fit: cover; transition: transform 1.5s cubic-bezier(.075,.82,.165,1); }
.v3p-work:hover .v3p-work-visual img, .v3p-work:hover .v3p-work-visual video { transform: scale(1.045); }
.v3p-work-info { display: flex; flex-direction: column; align-items: flex-start; margin-top: 1.2vw; margin-bottom: 0; width: 100%; flex: 1; }
.v3p-work-meta { display: flex; flex-wrap: wrap; align-items: center; }
.v3p-work-dash { margin: 0 4px; }
.v3p-work-title { margin-top: .8vw; font-size: 1.48vw; line-height: .9; }
/* The hairline fills from the left in odd columns and from the right in even ones. */
.v3p-work-line { width: 100%; overflow: hidden; display: flex; justify-content: flex-start; margin-top: 3vw; }
.v3p-work-line.rev { justify-content: flex-end; }
.v3p-work:last-child .v3p-work-line, .v3p-work:nth-last-child(2) .v3p-work-line { display: none; }
/* Once a filter hides cards the pseudo-classes above describe the wrong two
   cards, so archive.js marks the last two visible ones instead. */
.v3p-work.is-tail .v3p-work-line { display: none; }
.v3p-work:nth-last-child(-n+2) .v3p-work-info { margin-bottom: 0; }
/* Only the first four cards animate their line; the rest start fully drawn. */
.v3-io.in .v3-fillw.filled, .v3-fillw.filled { width: 100%; transition: none; }

/* Cards that move because of a filter change are shifted back and released,
   so the browser animates the difference (a FLIP transition, see archive.js). */
.v3p-work[data-flip] { will-change: transform; }

/* ---------- list view ---------- */

.v3p-worklist { margin: 2vw; min-height: 100vh; }
.v3p-listrow { position: relative; }
.v3p-listhead { width: 100%; display: grid; grid-template-columns: 47fr 40fr 5fr; column-gap: 2vw; align-items: center; padding: 1.4vw 0; }
.v3p-listtags { justify-self: start; }
.v3p-listyear { justify-self: end; }
.v3p-acc { display: grid; grid-template-rows: 0fr; opacity: 0; transition: grid-template-rows .6s cubic-bezier(.165,.84,.44,1), opacity .6s cubic-bezier(.165,.84,.44,1); }
.v3p-acc.open { grid-template-rows: 1fr; opacity: 1; }
.v3p-acc > div { overflow: hidden; min-height: 0; }
.v3p-liststrip { display: flex; gap: 2vw; padding: 1vw 0 2vw; overflow-x: auto; scrollbar-width: none; }
.v3p-liststrip::-webkit-scrollbar { display: none; }
.v3p-liststrip img { height: 15vw; width: 22.5vw; object-fit: cover; flex: 0 0 auto; }
.v3p-listslide { padding: 0; flex: 0 0 auto; cursor: pointer; }
/* On hover the hairline sweeps in from the left over 1.4s and out to the right
   over 1.6s; it stays put while the row is open. */
.v3p-rowline { position: relative; height: 1px; width: 100%; overflow: hidden; background: var(--ab-leman); }
.v3p-rowline i { position: absolute; inset: 0; background: var(--ab-noir); transform: scaleX(0); transform-origin: right center; transition: transform 1.6s cubic-bezier(.16,1,.3,1); }
.v3p-listrow:hover .v3p-rowline i { transform: scaleX(1); transform-origin: left center; transition: transform 1.4s cubic-bezier(.165,.84,.44,1); }
.v3p-rowline.on i { transform: scaleX(1); transform-origin: left center; transition: transform .6s cubic-bezier(.165,.84,.44,1); }

/* ---------- responsive ---------- */

@media (min-width: 769px) and (max-width: 1280px) {
	.abil-inner .v3-p { font-size: 14px; }
}

@media (max-width: 768px) {
	.abil-inner .v3-p { font-size: 16px; }
	.v3p-workhead { grid-template-columns: 1fr 1fr; row-gap: 4vw; padding-top: 24vw; }
	.v3p-worknum { font-size: 2vw; line-height: 1; }
	.v3p-filterwrap { display: none; }
	.v3p-viewtoggle { grid-column: 1/-1; justify-self: start; }
	.v3p-workgrid { margin: 0 4vw; }
	.v3p-works { grid-template-columns: 1fr; row-gap: 3vw; padding-top: 3vw; }
	.v3p-bordv { display: none; }
	.v3p-work { padding: 0; }
	.v3p-work-visual { height: 64vw; }
	.v3p-work:nth-last-child(2) .v3p-work-line { display: flex; }
	.v3p-worklist { margin: 4vw; }
	.v3p-listhead { grid-template-columns: 1fr auto; padding: 3.4vw 0; }
	.v3p-listtags { display: none; }
	.v3p-liststrip img { height: 34vw; width: 52vw; }
	.v3p-dropdown { min-width: 52vw; }
	.v3p-droplabel { padding: 3vw 4vw; }
}

@media (max-width: 480px) {
	.v3p-worknum { font-size: 5vw; }
}

@media (prefers-reduced-motion: reduce) {
	.v3p-bordv { height: calc(100% - 1vw) !important; }
}

/* ============================================================================
   Services page. Port of ServicesBody in AbilV3Pages.tsx (lines 1547-1691).
   ============================================================================ */

.v3p-pagehero { padding: 6vw 0 4vw; display: grid; grid-template-columns: repeat(8,1fr); column-gap: 2vw; }
.v3p-pagehero h1 { grid-column: 1/-1; }
.v3p-pagehero-sub { grid-column: 1/3; margin-top: 3vw; display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
.v3p-pagehero-desc { grid-column: 5/8; margin-top: 3vw; display: flex; flex-direction: column; gap: 1vw; align-items: flex-start; }

/* Wide banner. It widens from the margins to the full width as --p grows, and
   the picture inside settles from -14% to 0. main.js writes --p. */
.v3p-lrg { --p: 0; margin-top: 2vw; margin-bottom: 0; }
.v3p-lrg-box { width: calc(100% - 4vw * (1 - var(--p))); margin: 0 auto; height: 45vw; overflow: hidden; position: relative; }
.v3p-lrg-up { position: absolute; inset: 0; transform: translateY(120%); transition: transform 2.4s cubic-bezier(.4,.4,.1,1); transition-delay: var(--d,0s); }
.v3-io.in .v3p-lrg-up { transform: translateY(0); }
.v3p-lrg-img { width: 100%; height: 118%; object-fit: cover; transform: translateY(calc(-14% * (1 - var(--p)))); }

/* One block per service: the text on the left, the related project on the right. */
.v3p-servblock { display: grid; grid-template-columns: repeat(2,1fr); column-gap: 2vw; padding: 4vw 0; border-bottom: 1px solid var(--ab-rhone); }
/* Consecutive blocks overlap by the height of the info column, so the projects
   form one continuous column down the page. */
.v3p-servblock + .v3p-servblock { padding-top: calc(2vw + 158px); margin-top: -158px; }
.v3p-servinfo { width: 34.75vw; display: flex; flex-direction: column; gap: 1.6vw; align-items: flex-start; }
.v3p-servcase { cursor: pointer; display: flex; flex-direction: column; width: 100%; }
.v3p-servcase-visual { overflow: hidden; height: 34vw; width: 100%; }
.v3p-servcase-visual img, .v3p-servcase-visual video { width: 100%; height: 100%; object-fit: cover; transition: transform 1.5s cubic-bezier(.075,.82,.165,1); }
.v3p-servcase:hover .v3p-servcase-visual img, .v3p-servcase:hover .v3p-servcase-visual video { transform: scale(1.045); }
.v3p-servcase-info { margin-top: 1.2vw; margin-bottom: 3vw; display: flex; flex-direction: column; align-items: flex-start; }
.v3p-servcase-tags { margin-bottom: .8vw; color: var(--ab-rhone); }

/* What each service covers. */
.v3p-pillars { margin-top: 8vw; margin-bottom: 4vw; display: grid; grid-template-columns: repeat(2,1fr); column-gap: 2vw; row-gap: 2vw; }
.v3p-pillars-head { width: 34.75vw; display: flex; flex-direction: column; gap: 2vw; align-items: flex-start; }
.v3p-pillars-grid { display: grid; grid-template-columns: repeat(2,1fr); column-gap: 2vw; row-gap: 4vw; }
.v3p-pillar { display: flex; flex-direction: column; gap: 1vw; position: relative; }
.v3p-pillar:focus { outline: none; }
.v3p-pillar:focus-visible { outline: 2px solid var(--ab-noir); outline-offset: 6px; }
.v3p-pillar li { margin-bottom: .2vw; }
/* A citron frame marks the block a link pointed at. */
.v3p-pillar:before { content: ""; position: absolute; left: -1vw; right: -1vw; top: -1vw; bottom: -1vw; border: 1px solid var(--ab-citron); opacity: 0; transition: opacity .4s linear; pointer-events: none; }
.v3p-pillar.hit:before { opacity: 1; }
/* Below 768px the grid gives way to an accordion. */
.v3p-pillars-acc { display: none; grid-column: 1/-1; }
.v3p-accbtn { width: 100%; display: flex; justify-content: space-between; align-items: center; padding: 6vw 0; }
.v3p-accbody { padding: 0 0 4vw; }
.v3p-accbody li { margin-bottom: 1vw; }

/* Repères, restated at the foot of the services page. */
.v3p-awards { margin-top: 8vw; margin-bottom: 4vw; display: grid; grid-template-columns: repeat(8,1fr); column-gap: 2vw; row-gap: 2vw; }
.v3p-awards h2 { grid-column: 1/-1; }
.v3p-awards-p { grid-column: 1/4; margin-top: 1vw; }
.v3p-awards-groups { grid-column: 1/-1; margin-top: 3vw; display: grid; grid-template-columns: repeat(3,1fr); column-gap: 14.25vw; row-gap: 3vw; }
.v3p-award { display: flex; flex-direction: column; gap: 1vw; border-top: 1px solid var(--ab-leman); padding-top: 1.4vw; }
.v3p-award li { margin-bottom: .2vw; color: var(--ab-rhone); }

@media (max-width: 768px) {
	.v3p-pagehero { padding: 24vw 0 16vw; }
	.v3p-pagehero-sub, .v3p-pagehero-desc { grid-column: 1/-1; }
	.v3p-lrg-box { height: 80vw; }
	.v3p-servblock { grid-template-columns: 1fr; row-gap: 6vw; padding: 12vw 0; }
	.v3p-servblock + .v3p-servblock { padding-top: 12vw; margin-top: 0; }
	.v3p-servinfo { width: 100%; }
	.v3p-servcase-visual { height: 60vw; }
	.v3p-pillars { grid-template-columns: 1fr; row-gap: 10vw; margin-top: 20vw; }
	.v3p-pillars-head { width: 100%; }
	.v3p-pillars-grid { display: none; }
	.v3p-pillars-acc { display: block; }
	.v3p-awards { grid-template-columns: 1fr; margin-top: 20vw; }
	.v3p-awards-p { grid-column: 1/-1; }
	.v3p-awards-groups { grid-template-columns: 1fr; column-gap: 2vw; row-gap: 8vw; }
}

@media (max-width: 480px) {
	.v3p-lrg-box { height: 140vw; }
}

@media (prefers-reduced-motion: reduce) {
	.v3p-lrg-box { width: 100% !important; }
	.v3p-lrg-up, .v3p-lrg-img { transform: none !important; }
}

/* ============================================================================
   Journal index. Port of JournalBody in AbilV3Pages.tsx (lines 1168-1283).
   ============================================================================ */

.v3p-newshead { padding: 6vw 0 1.4vw; display: grid; grid-template-columns: repeat(8,1fr); column-gap: 2vw; row-gap: 3vw; }
.v3p-newstitle { grid-column: 1/-1; }
.v3p-newssub { grid-column: 1/3; display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
.v3p-newsp { grid-column: 5/8; margin-bottom: 3vw; }
.v3p-newssort { position: relative; grid-column: 5/7; align-self: center; }
.v3p-newssort .v3p-droplabel { padding: 16px 20px; }

.v3p-newswrap { position: relative; display: grid; grid-template-columns: repeat(2,1fr); column-gap: 2vw; margin-top: 1vw; }
/* The rule above the first row draws itself in, like the hairlines elsewhere. */
.v3p-newsbordh { grid-column: 1/-1; height: 1px; overflow: hidden; }

.v3p-article { display: grid; grid-template-columns: 1fr 1fr; column-gap: 2vw; padding: 2vw 0; position: relative; cursor: pointer; }
/* Each row is separated by one line spanning both columns, drawn by the card on
   the left, so the even cards and the final row suppress theirs. */
.v3p-article:after { content: ""; position: absolute; bottom: 0; left: 0; width: calc(200% + 2vw); height: 1px; background: var(--ab-leman); opacity: .5; }
.v3p-article:nth-of-type(even):after, .v3p-article:nth-last-of-type(-n+2):after { display: none; }
.v3p-article-img { position: relative; overflow: hidden; }
.v3p-article-img img { width: 100%; height: auto; aspect-ratio: 1296/1120; object-fit: cover; transition: transform 1.5s cubic-bezier(.075,.82,.165,1); }
.v3p-article:hover .v3p-article-img img { transform: scale(1.045); }
.v3p-article-info { display: flex; flex-direction: column; justify-content: space-between; gap: 12px; }
.v3p-article-meta { display: flex; align-items: baseline; }
.v3p-article-title { margin-top: .4vw; }
/* The card itself is clickable, so this link only exists for the keyboard and
   stays out of the way until it takes focus. */
.v3p-artlink { position: absolute; left: -9999px; top: 0; }
.v3p-artlink:focus { position: static; left: auto; align-self: flex-start; }

@media (max-width: 915px) {
	.v3p-newswrap { grid-template-columns: 1fr; }
	.v3p-article:after { width: 100%; }
	.v3p-article:nth-of-type(even):after, .v3p-article:nth-last-of-type(-n+2):after { display: block; }
	.v3p-article:last-of-type:after { display: none; }
}

@media (max-width: 768px) {
	.v3p-newshead { padding: 24vw 0 3vw; grid-template-columns: 1fr 1fr; }
	.v3p-newstitle, .v3p-newssub, .v3p-newsp, .v3p-newssort { grid-column: 1/-1; }
	.v3p-newswrap { grid-template-columns: 1fr; }
	.v3p-article { grid-template-columns: 1fr; row-gap: 6vw; padding: 8vw 0; }
	.v3p-article-img img { height: 56vw; }
}

@media (prefers-reduced-motion: reduce) {
	.v3p-article:after, .v3p-rowline i { transform: none !important; }
}

/* ============================================================================
   Contact page. Port of ContactBody in AbilV3Pages.tsx (lines 1284-1546).
   ============================================================================ */

.v3p-contact {
	padding-top: 2vw; min-height: calc(100vh - 56px - 2vw); padding-bottom: 6vw;
	display: grid; grid-template-columns: repeat(2,1fr);
	grid-template-areas: "t f" "d c"; column-gap: 2vw; row-gap: 0; align-items: start;
}
.v3p-contact-title { grid-area: t; overflow: hidden; padding: .32em 0 .44em; margin: -.32em 0 -.44em; }
.v3p-contact-form { grid-area: f; margin-bottom: 4vw; }
.v3p-contact-desc { width: 22.5vw; grid-area: d; }
.v3p-contact-cols { grid-area: c; display: flex; align-items: flex-start; gap: 2vw; flex-wrap: wrap; }
.v3p-contact-cols > div { width: 22.5vw; }
.v3p-contact-cols .v3p-colh { color: var(--ab-noir); margin-bottom: .5vw; }
.v3p-contact-cols li { margin-bottom: 4px; }

@media (max-width: 768px) {
	.v3p-contact { padding-top: 24vw; grid-template-columns: 1fr; grid-template-areas: "t" "f" "d" "c"; row-gap: 12vw; margin-bottom: 12vw; }
	.v3p-contact-form { margin-bottom: 8vw; }
	.v3p-contact-desc { width: 100%; }
	.v3p-contact-cols { flex-direction: column; gap: 8vw; }
	.v3p-contact-cols > div { width: auto; }
}

/* ============================================================================
   Ninja Forms, dressed to match the contact form of the React site.

   Written against the markup the plugin actually renders, which it builds in
   the browser rather than on the server:

     div.nf-field-container.<type>-container
       div.nf-field > div.field-wrap
         div.nf-field-label > label
         div.nf-field-element > input.nf-element
       div.nf-after-field > nf-section > div.nf-error-wrap

   The label cannot float on :placeholder-shown, because Ninja renders no
   placeholder in label-above mode, so contact.js marks a filled container
   with .is-filled and the rule below hangs off that.
   ============================================================================ */

/* The design has no form title and no "required" note. */
.v3p-contact-form .nf-form-title,
.v3p-contact-form .nf-form-fields-required { display: none; }

/* Two columns; the message and the submit span both.
   nf-field is a custom element, so it steps out of the way with display:contents
   and the containers themselves become the grid items. */
.v3p-contact-form nf-fields-wrap { display: grid; grid-template-columns: repeat(2,1fr); column-gap: 2vw; }
.v3p-contact-form nf-field { display: contents; }
.v3p-contact-form .textarea-container,
.v3p-contact-form .submit-container,
.v3p-contact-form .listcheckbox-container,
.v3p-contact-form .listmultiselect-container { grid-column: 1 / -1; }

.v3p-contact-form .nf-field-container { position: relative; margin-bottom: 2vw; padding-bottom: 18px; }
.v3p-contact-form .field-wrap { position: relative; display: block; }

/* Label sits over the field and lifts once it has content or focus. */
.v3p-contact-form .nf-field-label { position: absolute; top: 24px; left: 0; margin: 0; pointer-events: none; z-index: 1; }
.v3p-contact-form .nf-field-label label {
	display: block; margin: 0;
	font-family: "mundial", "Figtree", "Helvetica Neue", sans-serif;
	font-size: 1.111vw; font-weight: 400; line-height: 1.35; letter-spacing: -.01em;
	color: var(--ab-noir); text-transform: none;
	transform-origin: 0 0; transition: transform .15s, color .15s;
}
.v3p-contact-form .nf-field-container:focus-within .nf-field-label label,
.v3p-contact-form .nf-field-container.is-filled .nf-field-label label {
	color: var(--ab-rhone); transform: translateY(-100%) scale(.75);
}

.v3p-contact-form .nf-field-element input,
.v3p-contact-form .nf-field-element textarea,
.v3p-contact-form .nf-field-element select {
	width: 100%; padding: 24px 0 8px; min-height: 56px;
	background: none; border: 0; border-bottom: 1px solid var(--ab-leman); border-radius: 0;
	color: var(--ab-noir); box-shadow: none;
	font-family: "mundial", "Figtree", "Helvetica Neue", sans-serif;
	font-size: 1.111vw; line-height: 1.35;
}
.v3p-contact-form .nf-field-element textarea { min-height: 180px; resize: vertical; }
.v3p-contact-form .nf-field-element input:focus,
.v3p-contact-form .nf-field-element textarea:focus,
.v3p-contact-form .nf-field-element select:focus { outline: none; border-bottom-color: var(--ab-noir); }

/* The hairline that sweeps in from the left on hover and focus. */
.v3p-contact-form .nf-field-element { position: relative; }
.v3p-contact-form .nf-field-element:after {
	content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: var(--ab-noir);
	transform: scaleX(0); transform-origin: right center; transition: transform 1.6s cubic-bezier(.16,1,.3,1);
}
.v3p-contact-form .nf-field-container:hover .nf-field-element:after,
.v3p-contact-form .nf-field-container:focus-within .nf-field-element:after {
	transform: scaleX(1); transform-origin: left center; transition-duration: 1.4s;
}
.v3p-contact-form .submit-container .nf-field-element:after { display: none; }

/* Errors sit under the field, where the original put them.
   Anchored to the top of that band rather than to the container's bottom edge:
   pinned at the bottom, a message that ran to two lines grew upwards and
   crossed the input's own line. Given a right edge as well, so a long sentence
   wraps inside its column instead of reaching into the next one. */
.v3p-contact-form .nf-after-field { position: absolute; left: 0; right: 0; top: calc(100% - 18px); }
.v3p-contact-form .nf-error-wrap, .v3p-contact-form .nf-error-msg {
	margin: 0; color: #c8102e; font-size: 12px; line-height: 1.17; text-transform: none; letter-spacing: 0;
}
.v3p-contact-form .nf-error .nf-field-element:after,
.v3p-contact-form .nf-field-container.nf-error .nf-field-element:after {
	background: #c8102e; transform: scaleX(1); transform-origin: left center; transition: none;
}
.v3p-contact-form .nf-error .nf-field-label label { color: #c8102e; }
.v3p-contact-form .nf-error .nf-field-element input,
.v3p-contact-form .nf-error .nf-field-element textarea { border-bottom-color: #c8102e; }
.v3p-contact-form .nf-form-errors { color: #c8102e; font-size: 12px; }

/* Checkbox list for the subject, drawn as the chips of the original. */
.v3p-contact-form .list-container .nf-field-element ul { display: flex; flex-wrap: wrap; gap: 6px; margin: 24px 0 8px; padding: 0; }
.v3p-contact-form .list-container .nf-field-element li { list-style: none; margin: 0; }
.v3p-contact-form .list-container .nf-field-element li input { position: absolute; opacity: 0; pointer-events: none; }
.v3p-contact-form .list-container .nf-field-element li label {
	display: inline-block; margin: 0; padding: 3px 9px 4px;
	border: 1px solid var(--ab-leman); border-radius: 999px;
	font-size: 12px; line-height: 1.17; text-transform: uppercase; letter-spacing: -.01em;
	cursor: pointer; transition: background .2s linear, color .2s linear, border-color .2s linear;
}
.v3p-contact-form .list-container .nf-field-element li label:hover { border-color: var(--ab-noir); }
.v3p-contact-form .list-container .nf-field-element li input:checked + label { background: var(--ab-noir); border-color: var(--ab-noir); color: var(--ab-alpin); }
/* A checkbox list carries its own label above the chips rather than over them. */
.v3p-contact-form .list-container .nf-field-label { position: static; }
.v3p-contact-form .list-container .nf-field-label label { transform: translateY(0) scale(.75); color: var(--ab-rhone); }

/* Submit. contact.js wraps the input in the same pill markup used elsewhere,
   so the hover behaviour comes from the .v3-btn rules in main.css: the citron
   layer widens to the longer label while the black one clips back to a dot.
   The input stays on top, transparent, so it remains the click target. */
.v3p-contact-form .submit-container { margin-top: 24px; padding-bottom: 0; }
.v3p-contact-form .submit-container .nf-field-label { display: none; }
.v3p-contact-form .v3p-nfbtn .v3-btn-in { position: relative; }
.v3p-contact-form .submit-container .nf-field-element input {
	position: absolute; inset: 0; z-index: 3;
	width: 100%; height: 100%; min-height: 0; padding: 0;
	background: none; border: 0; border-radius: 999px;
	color: transparent; font-size: 0; cursor: pointer;
}
.v3p-contact-form .submit-container .nf-field-element input:focus-visible { outline: 2px solid var(--ab-citron); outline-offset: 4px; }
.v3p-contact-form .nf-field-container.submit-container:hover .nf-field-element:after { display: none; }

.v3p-contact-form .nf-response-msg { padding-top: 24px; }
.v3p-contact-form .nf-response-msg p { font-size: 1.111vw; line-height: 1.35; }

@media (max-width: 768px) {
	.v3p-contact-form nf-fields-wrap { grid-template-columns: 1fr; }
	.v3p-contact-form .nf-field-label label,
	.v3p-contact-form .nf-field-element input,
	.v3p-contact-form .nf-field-element textarea,
	.v3p-contact-form .nf-field-element select,
	.v3p-contact-form .nf-response-msg p { font-size: 16px; }
}

/* ============================================================================
   Detail pages and the pieces they share, ported from CSS_V3D in
   AbilV3Detail.tsx (611 lines).

   The detail shell turned out to be the same shell again: of its base and
   navigation rules 42 match the home page byte for byte and only ten differ,
   most of which the abil-inner modifier above already covers. What is left is
   below.

   Not ported: .v3d-pgbar. Despite the name it is not a reading indicator but
   the editing control of the React admin — position in the project, move up,
   move down, delete. WordPress admin does that job.
   ============================================================================ */

/* The detail pages fade content up by a share of its own height rather than a
   fixed distance, and their overlay links are set larger than on list pages. */
.abil-detail .v3-fadeup { transform: translateY(80%); }
.abil-detail .v3-overlay-links .v3-biglink { font-size: 8.5vw; }

/* ---------- compact footer ----------
   Only the contact page uses it: the contact details are already in the page,
   so repeating the full footer would say everything twice. */
.v3-footer.meta { min-height: 0; margin-top: 0; background: var(--ab-tela); }
.v3-footer.meta .v3-footer-base {
	display: grid; grid-template-columns: repeat(8,1fr); column-gap: 2vw;
	align-items: center; height: 4vw; padding: 0 2vw; border-top: 1px solid var(--ab-leman);
}
.v3-footer.meta .v3-base-copy { grid-column: 1/3; }
.v3-footer.meta .v3-socials { grid-column: 5/8; }
.v3-footer.meta .v3-footer-base > a:last-child { grid-column: 8/9; justify-self: end; }

@media (max-width: 768px) {
	.v3-footer.meta .v3-footer-base { display: flex; height: auto; padding: 4vw; flex-wrap: wrap; }
}

/* ---------- gallery lightbox ----------
   Used by the case pages: the panel rises from the bottom over a dimmed page,
   the images scroll sideways with snapping, and the citron bar tracks position. */
.v3d-lbveil { position: fixed; inset: 0; z-index: 1040; background: rgba(10,10,11,.5); opacity: 0; transition: opacity 1s cubic-bezier(.4,.4,.1,1); }
.v3d-lbveil.open { opacity: 1; }
.v3d-lb {
	position: fixed; top: 56px; left: 0; right: 0; bottom: 0; z-index: 1050;
	background: var(--ab-noir); color: var(--ab-alpin);
	border-radius: 12px 12px 0 0; overflow: hidden; display: flex; flex-direction: column;
	transform: translateY(100%); transition: transform 1s cubic-bezier(.4,.4,.1,1);
}
.v3d-lb.open { transform: translateY(0); }
.v3d-lb-bar { display: flex; align-items: center; justify-content: space-between; gap: 2vw; padding: 1vw 2vw; }
.v3d-lb-prog { flex: 1; height: 1px; background: rgba(255,255,255,.3); margin: 0 2vw; overflow: hidden; }
.v3d-lb-prog i { display: block; height: 100%; background: var(--ab-citron); transition: width .4s cubic-bezier(.4,.4,.1,1); }
.v3d-lb-track { flex: 1; display: flex; gap: 2vw; overflow-x: auto; scroll-snap-type: x proximity; padding: 0 2vw 2vw; scrollbar-width: none; }
.v3d-lb-track::-webkit-scrollbar { display: none; }
.v3d-lb-track img { flex: 0 0 48vw; width: 48vw; height: auto; max-height: 78vh; object-fit: cover; scroll-snap-align: center; }
/* The close link sits on a dark bar, so it inverts. */
.v3d-lb .v3-lnk:after { background: var(--ab-alpin); }

@media (max-width: 768px) {
	.v3d-lb-track img { flex: 0 0 84vw; width: 84vw; }
}

@media (prefers-reduced-motion: reduce) {
	.v3d-lb, .v3d-lbveil { transition: none; }
}

/* ============================================================================
   Case page. Port of AbilV3Case in AbilV3Detail.tsx (2828-3010).
   ============================================================================ */

/* The case sits on white rather than the site's tela. */
.v3d-proj { background: #ffffff; }
.v3d-projcapa { width: 100%; height: min(78vh,52vw); overflow: hidden; background: var(--ab-leman); }
.v3d-projcapa img, .v3d-projcapa video { width: 100%; height: 100%; object-fit: cover; display: block; }

.v3d-projtxt { max-width: 1440px; margin: 0 auto; padding: 6vw 2vw 4vw; }
.v3d-projtxt h1 { font-size: 4.86vw; line-height: .9; font-weight: 300; letter-spacing: -.03em; margin: 0 0 2.4vw; text-transform: uppercase; }
.v3d-projtxt .lede { font-size: 1.6vw; line-height: 1.3; font-weight: 300; max-width: 34ch; margin: 0 0 2vw; }
.v3d-projtxt p { font-size: 1.111vw; line-height: 1.5; font-weight: 300; max-width: 62ch; margin: 0 0 1em; }
/* The way through to the live site, under the text that describes it. */
.v3d-projlink { margin-top: 2vw; }

/* Credits, as a row of hairline-topped cells. */
.v3d-ficha { max-width: 1440px; margin: 0 auto; padding: 0 2vw 6vw; display: grid; grid-template-columns: repeat(6,1fr); column-gap: 2vw; row-gap: 2vw; }
.v3d-ficha .lin { border-top: 1px solid var(--ab-leman); padding-top: .8vw; }
.v3d-ficha .papel { display: block; font-size: 12px; letter-spacing: .02em; color: var(--ab-rhone); margin-bottom: .35vw; }
.v3d-ficha .quem { display: block; font-size: 1.111vw; line-height: 1.2; font-weight: 300; }

/* Gallery pages, stacked edge to edge with no seams. */
.v3d-projimgs { display: block; font-size: 0; line-height: 0; max-width: 1440px; margin: 0 auto; padding: 0 2vw; }
.v3d-projimgs img, .v3d-projimgs video { display: block; width: 100%; height: auto; margin: 0; padding: 0; }
.v3d-projimgs button { display: block; width: 100%; overflow: hidden; padding: 0; }

/* Related projects. The covers round into circles on hover. */
.v3d-rel { display: flex; flex-direction: column; align-items: flex-start; gap: 2vw; margin-top: 4vw; padding-bottom: 2vw; }
.v3d-relgrid { width: 100%; display: grid; grid-template-columns: repeat(4,1fr); column-gap: 2vw; }
.v3d-card { position: relative; cursor: pointer; }
.v3d-card-num { position: absolute; left: -1.6vw; top: 0; transform: rotate(-90deg); transform-origin: 100% 0; color: var(--ab-rhone); }
.v3d-card-img { overflow: hidden; aspect-ratio: 16 / 10; }
.v3d-card-img img, .v3d-card-img video { width: 100%; height: 100%; object-fit: cover; border-radius: 0; transition: border-radius .5s cubic-bezier(.165,.84,.44,1); }
.v3d-card:hover .v3d-card-img img, .v3d-card:hover .v3d-card-img video { border-radius: 50%; }
.v3d-card-line { width: 100%; height: 1px; margin-top: 1vw; background: var(--ab-noir); }
.v3d-card-info { display: flex; justify-content: space-between; gap: 1vw; padding-top: .8vw; margin-bottom: .5vw; }

@media (max-width: 900px) {
	.v3d-projtxt { padding: 10vw 4vw 6vw; }
	.v3d-projtxt h1 { font-size: 9vw; }
	.v3d-projtxt .lede { font-size: 4.4vw; max-width: none; }
	.v3d-projtxt p { font-size: 3.8vw; max-width: none; }
	.v3d-projlink { margin-top: 6vw; }
	.v3d-ficha { grid-template-columns: 1fr 1fr; padding: 0 4vw 10vw; }
	.v3d-ficha .quem { font-size: 3.8vw; }
	.v3d-projimgs { padding: 0 2vw; }
}

@media (max-width: 768px) {
	.v3d-relgrid { grid-template-columns: 1fr; row-gap: 8vw; }
	.v3d-card-num { display: none; }
}

/* ============================================================================
   Service page. Port of AbilV3Service in AbilV3Detail.tsx (3030-3186).
   ============================================================================ */

.v3d-hero { padding: 6vw 0 4vw; display: grid; grid-template-columns: repeat(8,1fr); column-gap: 2vw; row-gap: 1vw; }
.v3d-hero h1 { grid-column: 1/-1; }
.v3d-hero-sub { grid-column: 1/3; margin-top: 3vw; display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
.v3d-hero-desc { grid-column: 5/8; margin-top: 3vw; display: flex; flex-direction: column; gap: 2vw; align-items: flex-start; }
.v3d-hero-desc .v3-p, .v3d-svclist-head .v3-p, .v3d-proc-head .v3-p { line-height: 1.6; max-width: 52ch; }
.v3d-svclist-head, .v3d-tours-head { display: flex; flex-direction: column; align-items: flex-start; gap: 1.2vw; }

/* The wide image starts inset and opens to the full width as it is revealed. */
.v3d-expand { width: 96vw; margin: 0 auto; overflow: hidden; transition: width 1.5s cubic-bezier(.4,.4,.1,1); }
.v3-io.in .v3d-expand { width: 100%; }
.v3d-imgmask { overflow: hidden; }
.v3d-imgup { transform: translateY(20%); transition: transform 2.4s cubic-bezier(.4,.4,.1,1); transition-delay: var(--d,0s); will-change: transform; }
.v3-io.in .v3d-imgup { transform: translateY(0); }
.v3d-herolrg { height: 45vw; overflow: hidden; margin-bottom: 4vw; }
.v3d-herolrg img { width: 100%; height: 100%; object-fit: cover; }

.v3d-svclist { margin-top: 8vw; margin-bottom: 8vw; display: grid; grid-template-columns: repeat(2,1fr); column-gap: 2vw; row-gap: 2vw; align-items: start; }
.v3d-svclist-head { width: 34.75vw; }
.v3d-svclist-grid { display: grid; grid-template-columns: repeat(2,1fr); column-gap: 2vw; row-gap: 4vw; }
.v3d-svclist-grid li { margin-bottom: .2vw; }

/* How we work: the same rows as elsewhere, but the hairline slides across
   rather than growing from a corner. */
.v3d-proc { margin-top: 8vw; margin-bottom: 8vw; display: grid; grid-template-columns: repeat(2,1fr); column-gap: 2vw; row-gap: 2vw; align-items: start; }
.v3d-proc-head { display: flex; flex-direction: column; width: 34.75vw; gap: 2.6vw; }
.v3d-proc-row { width: 100%; padding: 1.4vw 0; display: flex; justify-content: space-between; align-items: center; gap: 2vw; }
/* The sign is a marker, not running text: a question long enough to wrap
   used to push it onto a line of its own. It keeps its width, the label
   takes whatever is left. */
.v3d-proc-row [data-sign], .v3p-accbtn [data-sign] { flex: 0 0 auto; white-space: nowrap; }
.v3d-proc-row > span:first-child, .v3p-accbtn > span:first-child { flex: 1 1 auto; min-width: 0; }
.v3d-acc { display: grid; grid-template-rows: 0fr; opacity: 0; transition: grid-template-rows .6s cubic-bezier(.165,.84,.44,1), opacity .6s cubic-bezier(.165,.84,.44,1); }
.v3d-acc.open { grid-template-rows: 1fr; opacity: 1; }
.v3d-acc > div { overflow: hidden; min-height: 0; }
.v3d-acc .v3-p { padding: .6vw 0 2.4vw; line-height: 1.6; max-width: 60ch; }
.v3d-rowline { position: relative; height: 1px; width: 100%; overflow: hidden; background: var(--ab-leman); }
.v3d-rowline i { position: absolute; inset: 0; background: var(--ab-noir); transform: translateX(-101%); transition: transform .6s cubic-bezier(.165,.84,.44,1); }
.v3d-rowline.on i { transform: translateX(0); }

/* Whatever the questions did not cover. */
.v3d-faq-cta { margin-top: 2.6vw; }

/* Related work, two columns with the central line. */
.v3d-relwork { margin-top: 8vw; margin-bottom: 4vw; }
.v3d-relwork-grid { position: relative; display: grid; grid-template-columns: 1fr 1fr; margin: 0 1vw; }
.v3d-bordv { position: absolute; left: 50%; top: 1vw; width: 1px; height: 0; background: var(--ab-noir); transition: height 6s cubic-bezier(.3,.3,0,1); transition-delay: var(--d,0s); }
.v3-io.in .v3d-bordv { height: calc(100% - 2vw); }
.v3d-work { position: relative; display: flex; flex-direction: column; justify-content: space-between; padding: 1vw 1vw 0; cursor: pointer; }
.v3d-work-visual { position: relative; width: 100%; height: 34vw; overflow: hidden; }
.v3d-work-visual img, .v3d-work-visual video { width: 100%; height: 100%; object-fit: cover; transition: transform 1.5s cubic-bezier(.075,.82,.165,1); }
.v3d-work:hover .v3d-work-visual img, .v3d-work:hover .v3d-work-visual video { transform: scale(1.045); }
.v3d-work-info { display: flex; flex-direction: column; align-items: flex-start; margin-top: 1.2vw; margin-bottom: 3vw; width: 100%; }
.v3d-work-title { margin-top: .8vw; }
.v3d-work-line { margin-top: 3vw; width: 100%; overflow: hidden; }

@media (max-width: 768px) {
	.v3d-hero { padding: 24vw 0 16vw; }
	.v3d-hero-sub, .v3d-hero-desc { grid-column: 1/-1; }
	.v3d-svclist, .v3d-proc { grid-template-columns: 1fr; row-gap: 10vw; margin-top: 20vw; margin-bottom: 20vw; }
	.v3d-proc-row { padding: 3.4vw 0; gap: 4vw; }
	.v3d-svclist-head, .v3d-proc-head { width: 100%; }
	.v3d-svclist-head, .v3d-tours-head { gap: 4vw; }
	.v3d-svclist-grid { grid-template-columns: 1fr; row-gap: 8vw; }
	.v3d-faq-cta { margin-top: 8vw; }
	.v3d-relwork-grid { grid-template-columns: 1fr; row-gap: 6vw; margin: 0 4vw; }
	.v3d-bordv { display: none; }
	.v3d-work { padding: 0; }
	.v3d-work-visual { height: 64vw; }
}

@media (prefers-reduced-motion: reduce) {
	.v3d-expand { width: 100% !important; }
	.v3d-imgup { transform: none !important; }
	.v3d-bordv { height: calc(100% - 2vw) !important; }
}

/* ============================================================================
   Article page. Port of AbilV3Article in AbilV3Detail.tsx (3463-3566).
   ============================================================================ */

.v3d-art { background: #ffffff; }
.v3d-artcapa { width: 100%; height: min(78vh,52vw); overflow: hidden; background: var(--ab-leman); }
.v3d-artcapa img { width: 100%; height: 100%; object-fit: cover; display: block; }

.v3d-arthead { max-width: 1440px; margin: 0 auto; padding: 6vw 2vw 3vw; text-align: center; }
.v3d-arthead .v3d-arttag { font-size: 12px; letter-spacing: .02em; color: var(--ab-rhone); text-transform: uppercase; margin-bottom: 1.2vw; display: block; }
.v3d-arthead h1 { font-size: 4.86vw; line-height: .9; font-weight: 300; letter-spacing: -.03em; margin: 0 auto 2vw; max-width: 22ch; text-transform: uppercase; }
.v3d-arthead .lede { font-size: 1.6vw; line-height: 1.3; font-weight: 300; max-width: 44ch; margin: 0 auto; }

.v3d-artficha { max-width: 1440px; margin: 0 auto; padding: 0 2vw 4vw; display: grid; grid-template-columns: repeat(4,1fr); column-gap: 2vw; row-gap: 2vw; }
.v3d-artficha .lin { border-top: 1px solid var(--ab-leman); padding-top: .8vw; }
.v3d-artficha .papel { display: block; font-size: 12px; letter-spacing: .02em; color: var(--ab-rhone); margin-bottom: .35vw; text-transform: uppercase; }
.v3d-artficha .quem { display: block; font-size: 1.111vw; line-height: 1.2; font-weight: 300; }
.v3d-art-autor { display: flex; align-items: center; gap: .8vw; }
.v3d-art-avatar { width: 3vw; height: 3vw; background: var(--ab-noir); object-fit: contain; padding: .6vw; flex: 0 0 auto; }
.v3d-art-bio { display: block; font-size: 14px; font-weight: 300; line-height: 1.45; color: var(--ab-rhone); margin-top: 1.6vw; max-width: 34ch; }

/* One narrow measure for the whole body, whatever the editor put in it. */
.v3d-artbody { --coluna: 43.2vw; max-width: 1440px; margin: 0 auto; padding: 2vw 2vw 6vw; }
.v3d-artbody p { font-size: 1.111vw; line-height: 1.6; font-weight: 300; max-width: var(--coluna); margin: 0 auto 1em; }
.v3d-artbody h2 { font-size: 1.6vw; line-height: 1.15; font-weight: 400; letter-spacing: -.02em; max-width: var(--coluna); margin: 2.2em auto .8em; }
.v3d-artbody h3, .v3d-artbody ul, .v3d-artbody ol, .v3d-artbody blockquote { max-width: var(--coluna); margin-left: auto; margin-right: auto; }
.v3d-artbody figure { width: 100%; max-width: var(--coluna); margin: 3vw auto; font-size: 0; line-height: 0; }
.v3d-artbody figure img { width: 100%; height: auto; display: block; }
.v3d-artbody figcaption { font-size: 11px; line-height: 1.3; color: var(--ab-rhone); padding-top: .5vw; text-align: right; }

.v3d-artoutros { max-width: 1440px; margin: 0 auto; padding: 0 2vw 8vw; }
.v3d-artoutros-h { display: flex; align-items: flex-start; margin-bottom: 2.6vw; }
.v3d-artoutros-grid { display: grid; grid-template-columns: repeat(3,1fr); column-gap: 2vw; row-gap: 4vw; }
.v3d-artcard { display: flex; flex-direction: column; align-items: flex-start; text-align: left; cursor: pointer; border-top: 1px solid var(--ab-noir); padding-top: 1.2vw; }
.v3d-artcard-img { width: 100%; aspect-ratio: 1296/1120; overflow: hidden; margin-bottom: 1.2vw; }
.v3d-artcard-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.v3d-artcard .meta { font-size: 12px; color: var(--ab-rhone); text-transform: uppercase; margin-bottom: .6vw; }
.v3d-artcard .tit { font-size: 1.5vw; line-height: .9; font-weight: 400; letter-spacing: -.03em; text-transform: uppercase; }

@media (max-width: 900px) {
	.v3d-arthead { padding: 12vw 4vw 6vw; }
	.v3d-arthead h1 { font-size: 9vw; }
	.v3d-arthead .lede { font-size: 4.4vw; max-width: none; }
	.v3d-artficha { grid-template-columns: 1fr 1fr; padding: 0 4vw 8vw; }
	.v3d-art-avatar { width: 10vw; height: 10vw; padding: 1.8vw; }
	.v3d-artbody { padding: 4vw 4vw 10vw; }
	.v3d-artbody p { font-size: 3.8vw; max-width: none; }
	.v3d-artbody h2 { font-size: 5.4vw; max-width: none; }
	.v3d-artoutros { padding: 0 4vw 16vw; }
	.v3d-artoutros-grid { grid-template-columns: 1fr; row-gap: 10vw; }
	.v3d-artcard .tit { font-size: 5.6vw; }
}

/* ============================================================================
   Legal pages, case studies overview and 404.
   Ported from AbilV3Legal, AbilV3CaseOverview and AbilV3NotFound.
   ============================================================================ */

/* ---------- legal ---------- */
.v3d-legalhead { margin-top: 6vw; padding-bottom: 2vw; border-bottom: 1px solid var(--ab-noir); }
.v3d-legalhead h1 { margin-bottom: 2vw; }
.v3d-legalmeta { display: flex; gap: 2vw; align-items: baseline; flex-wrap: wrap; }
.v3d-legalsec { position: relative; display: flex; align-items: flex-start; justify-content: space-between; margin: 4vw 2vw 8vw; gap: 4vw; }
.v3d-legalnav { position: sticky; top: calc(55px + 2vw); }
.v3d-legallinks { display: flex; align-items: flex-start; flex-direction: column; gap: .4vw; }
.v3d-legalbody { display: flex; flex-direction: column; row-gap: 2vw; width: 34.75vw; }
/* The offset keeps a heading clear of the fixed bar when jumped to. */
.v3d-legalblock { padding-top: calc(55px + 2vw); margin-top: calc(-55px - 2vw); }
.v3d-legalblock h2 { margin-bottom: 1vw; }
.v3d-legalblock p { margin-bottom: .5vw; }

/* ---------- case studies overview ---------- */
.v3d-co { position: relative; scroll-snap-type: y proximity; }
.v3d-coslide { position: relative; min-height: 100svh; width: 100%; overflow: clip; clip-path: inset(0); scroll-snap-align: start; cursor: pointer; }
/* clip-path on the slide turns the fixed image into one that scrolls with it,
   which is what gives each case its own full-bleed backdrop. */
.v3d-coimg { position: fixed; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; }
.v3d-coveil { position: absolute; inset: 0; background: rgba(10,10,11,.25); }
.v3d-cocontent { position: absolute; inset: 0; display: flex; align-items: flex-end; justify-content: flex-end; padding: 0 2vw 2vw; color: var(--ab-alpin); }
.v3d-cobox { width: 47vw; display: flex; flex-direction: column; align-items: flex-start; gap: 1vw; }
.v3d-cotags { display: flex; flex-direction: column; align-items: flex-start; }
.v3d-conum { position: fixed; left: 2vw; bottom: 2vw; z-index: 20; color: var(--ab-alpin); mix-blend-mode: difference;
	transition: opacity .35s linear, transform .5s cubic-bezier(.16,1,.3,1); }
/* Out of the way once the footer is on screen: the count belongs to the
   slides, not to what follows them. */
.v3d-conum.gone { opacity: 0; transform: translateY(140%); pointer-events: none; }

/* ---------- 404 ---------- */
.v3d-nf { position: relative; min-height: calc(100vh - 56px); overflow: hidden; display: flex; flex-direction: column; justify-content: center; }
.v3d-nfgrid { display: grid; grid-template-columns: repeat(8,1fr); grid-template-rows: auto auto auto; column-gap: 2vw; row-gap: 2vw; padding-bottom: 8vw; align-items: start; }
.v3d-nfnext { grid-column: 1/5; grid-row: 1; margin-bottom: 8vw; display: flex; flex-direction: column; gap: 1vw; align-items: flex-start; }
.v3d-nfcontact { grid-column: 1/3; grid-row: 2/4; }
.v3d-nfcontact-h { margin-bottom: 2vw; }
.v3d-nfcompany { grid-column: 5/9; grid-row: 2; display: flex; align-items: flex-start; gap: 2vw; }
.v3d-nfaddr { grid-column: 5/9; grid-row: 3; display: flex; align-items: flex-start; gap: 2vw; }
.v3d-nflist { width: 22.5vw; display: flex; flex-direction: column; align-items: flex-start; }
.v3d-nflist li { margin-bottom: .2vw; }
.v3d-nfmeta { position: absolute; bottom: 0; left: 0; right: 0; min-height: 4vw; display: flex; align-items: center; justify-content: space-between; gap: 2vw; border-top: 1px solid var(--ab-leman); }
.v3d-nflinks { display: flex; gap: 2vw; flex-wrap: wrap; }

@media (max-width: 768px) {
	.v3d-legalsec { flex-direction: column; margin-right: 0; padding: 0; margin-bottom: 12vw; gap: 6vw; }
	.v3d-legalnav { position: relative; top: 0; width: 100%; }
	.v3d-legallinks { flex-direction: row; flex-wrap: nowrap; white-space: nowrap; overflow-x: auto; gap: 3vw; scrollbar-width: none; }
	.v3d-legallinks::-webkit-scrollbar { display: none; }
	.v3d-legalbody { width: 100%; row-gap: 6vw; border-top: 1px solid var(--ab-leman); padding-top: 8vw; }
	.v3d-legalblock { padding-top: calc(55px + 4vw); margin-top: calc(-55px - 4vw); }
	.v3d-cobox { width: 100%; }
	.v3d-nfgrid { grid-template-columns: 1fr; row-gap: 8vw; padding-top: 18vw; padding-bottom: 20vw; }
	.v3d-nfnext, .v3d-nfcontact, .v3d-nfcompany, .v3d-nfaddr { grid-column: 1/-1; }
	.v3d-nfcompany, .v3d-nfaddr { flex-direction: column; gap: 8vw; }
	.v3d-nflist { width: 100%; }
	.v3d-nfmeta { position: relative; height: auto; flex-wrap: wrap; padding: 4vw; row-gap: 4vw; }
}

@media (prefers-reduced-motion: reduce) {
	.v3d-co { scroll-snap-type: none; }
}

/* The whole slide is a link; it sits under the content so the title stays
   clickable in its own right. */
.v3d-coslide-link { position: absolute; inset: 0; z-index: 1; }
.v3d-cocontent { z-index: 2; }

/* The summary label above the legal navigation. In the source this reuses the
   footer's .v3d-colh, which is white — invisible on the light page — so it
   takes the grey every other small label on the site uses. */
.v3d-legalnav .v3d-colh { margin-bottom: 1vw; }
.v3d-legallinks li { list-style: none; }

/* ============================================================================
   Agency page. Port of AbilV3Agence in AbilV3Detail.tsx (3187-3463).
   ============================================================================ */

.v3d-agvidwrap { position: relative; margin: 0 2vw; overflow: hidden; }
.v3d-agvidload { position: absolute; left: 50%; top: 50%; width: 10vw; height: 1px; background: var(--ab-leman); transform: translate(-50%,-50%); overflow: hidden; z-index: 1; }
.v3d-agvidload i { position: absolute; inset: 0; background: var(--ab-noir); animation: v3dVidLoad 2s linear infinite; }
@keyframes v3dVidLoad { 0% { transform: translateX(-100%); } 50% { transform: translateX(0); } to { transform: translateX(100%); } }
.v3d-agvid { position: relative; z-index: 2; display: block; width: 100%; height: 45vw; object-fit: cover; }

/* The service slider. The left column stays put while the right one scrolls;
   whichever group of items is in view drives the name, the rolling number and
   the progress bar on the left. */
.v3d-agsp { margin-top: 4vw; margin-bottom: 4vw; display: flex; align-items: flex-start; }
.v3d-agsp-left { position: sticky; top: 80px; flex: 0 0 50%; padding: 0 1vw .8vw 2vw; display: flex; flex-direction: column; align-items: flex-start; }
/* One name at a time. The height is a starting value only: agence.js measures
   the longest name in the language being read and locks every row to it, so a
   two-line title is not cut off. */
.v3d-agsp-mask { overflow: hidden; height: 6.5vw; --step: 6.5vw; margin-top: .6vw; margin-bottom: 2vw; }
.v3d-agsp-stack { display: flex; flex-direction: column; transition: transform .8s cubic-bezier(.075,.82,.165,1); }
.v3d-agsp-stack .v3-l { height: 6.5vw; display: flex; align-items: center; }
.v3d-agsp-countwrap { display: flex; align-items: center; margin-bottom: 1.6vw; }
.v3d-agsp-count { display: flex; align-items: center; justify-content: space-between; width: 22.5vw; }
.v3d-agsp-total { margin-left: 2vw; }
/* Only the last digit rolls, so "001" becomes "002" without the zeros moving. */
.v3d-agsp-digits { display: inline-block; height: 1em; overflow: hidden; line-height: 1; vertical-align: baseline; }
.v3d-agsp-roll { display: block; transition: transform .8s cubic-bezier(.075,.82,.165,1); will-change: transform; }
.v3d-agsp-roll span { display: block; height: 1em; line-height: 1; }
.v3d-agsp-prog { flex: none; width: 8vw; height: 1px; background: var(--ab-leman); overflow: hidden; }
.v3d-agsp-prog i { display: block; height: 100%; background: var(--ab-noir); transform: translateX(calc(var(--p,0) * 100% - 100%)); transition: transform .8s cubic-bezier(.075,.82,.165,1); }
.v3d-agsp-para { margin: 0 0 2vw; max-width: 34.75vw; line-height: 1.6; }
.v3d-agsp-right { flex: 0 0 50%; border-left: 1px solid var(--ab-noir); padding: 0 2vw 0 1vw; overflow: hidden; }
/* Wraps rather than running off the edge: a line that fits in French can be
   half again as long in German. */
.v3d-agsp-item { font-size: 2.5vw; line-height: 1.2; text-transform: uppercase; letter-spacing: -.03em;
	font-weight: 300; overflow-wrap: break-word; }
/* The resting place. agence.js pushes these to the right and lets them ride
   back in with the scroll; without the script they simply sit where they are. */
.v3d-agsp-sep { height: 1px; background: var(--ab-noir); margin-top: 4vw; margin-bottom: 4vw; will-change: transform; }
.v3d-agsp-item { will-change: transform; }

/* Team. The portraits round into circles on hover, as the project cards do. */
.v3d-agteam { margin-top: 10vw; margin-bottom: 10vw; display: grid; grid-template-columns: repeat(4,1fr); column-gap: 1.6vw; row-gap: 4vw; }
.v3d-agteam-head { grid-column: 1/-1; display: flex; align-items: flex-start; margin-bottom: 2vw; }
.v3d-agteam-num { font-size: 1.2vw; margin: .6vw 0 0 1vw; }
.v3d-agteam-sub { grid-column: 1/-1; margin-bottom: 2.6vw; max-width: 34.75vw; line-height: 1.6; }
.v3d-agteam-row { display: contents; }
.v3d-agcard { border-top: 1px solid var(--ab-noir); padding: 1.2vw 0 3vw; display: flex; flex-direction: column; align-items: flex-start; }
.v3d-agcard.bot { border-bottom: 1px solid var(--ab-noir); }
.v3d-agcard-info { display: block; max-width: 14vw; min-height: 2.34em; }
.v3d-agcard-info span { display: block; }
.v3d-agcard-photo { width: 14vw; aspect-ratio: 242 / 346; height: auto; overflow: hidden; margin: 1.2vw 0; border-radius: 0; transition: border-radius .5s cubic-bezier(.165,.84,.44,1); }
.v3d-agcard:hover .v3d-agcard-photo { border-radius: 50%; }
.v3d-agcard-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.v3d-agcard-name { margin-top: .4vw; }

.v3d-agoff { margin-top: 8vw; margin-bottom: 4vw; display: grid; grid-template-columns: repeat(8,1fr); column-gap: 2vw; row-gap: 2vw; }
.v3d-agoff-h { grid-column: 1/-1; display: flex; align-items: flex-start; }
.v3d-agoff-sub { grid-column: 1/4; max-width: 72%; }
.v3d-agoff-in { grid-column: 5/8; display: flex; flex-direction: column; align-items: flex-start; gap: 2vw; }
.v3d-agoff-in .v3-p { line-height: 1.6; max-width: 52ch; }

.v3d-agstrip { margin-top: 8vw; display: flex; gap: 2vw; height: 24vw; overflow-x: auto; padding: 0 2vw; scrollbar-width: none; cursor: grab; }
.v3d-agstrip.drag { cursor: grabbing; }
.v3d-agstrip::-webkit-scrollbar { display: none; }
.v3d-agstrip img { height: 100%; width: auto; flex: 0 0 auto; object-fit: cover; pointer-events: none; user-select: none; }

@media (max-width: 768px) {
	.v3d-agvidwrap { margin: 0 4vw; }
	.v3d-agvid { height: 80vw; }
	.v3d-agsp { flex-direction: column; margin-top: 8vw; margin-bottom: 8vw; }
	.v3d-agsp-left { position: sticky; top: 56px; flex: none; width: 100%; background: var(--ab-tela); z-index: 1; padding: 0 4vw 4vw; }
	.v3d-agsp-mask { height: 12vw; --step: 12vw; }
	.v3d-agsp-stack .v3-l { height: 12vw; font-size: 9vw; }
	.v3d-agsp-count { width: 44vw; }
	.v3d-agsp-prog { width: 20vw; }
	.v3d-agsp-total { margin-left: 4vw; }
	.v3d-agsp-para { max-width: 100%; margin-bottom: 4vw; }
	.v3d-agsp-right { flex: none; width: 100%; border-left: 0; border-top: 1px solid var(--ab-noir); padding: 4vw; }
	.v3d-agsp-item { font-size: 5.6vw; }
	.v3d-agteam { margin-top: 20vw; margin-bottom: 20vw; display: block; }
	.v3d-agteam-head, .v3d-agteam-sub { margin-bottom: 6vw; }
	.v3d-agteam-row { display: flex; overflow-x: auto; scrollbar-width: none; gap: 4vw; margin-right: -4vw; }
	.v3d-agteam-row::-webkit-scrollbar { display: none; }
	.v3d-agteam-num { font-size: 4vw; }
	.v3d-agcard { flex: 0 0 80vw; border-bottom: 1px solid var(--ab-noir); padding: 4vw 0 8vw; }
	.v3d-agcard-info { max-width: 60vw; }
	.v3d-agcard-photo { width: 60vw; height: 86vw; aspect-ratio: auto; margin: 4vw 0; }
	.v3d-agcard:hover .v3d-agcard-photo { border-radius: 0; }
	.v3d-agoff { grid-template-columns: 1fr; row-gap: 4vw; margin-top: 12vw; margin-bottom: 12vw; }
	.v3d-agoff-h, .v3d-agoff-sub, .v3d-agoff-in { grid-column: 1/-1; max-width: 100%; }
	.v3d-agstrip { height: 44vw; padding: 0 4vw; gap: 4vw; }
}

/* Embedded examples on a service page: live frames of the virtual tours.
   The frame keeps a 4:3 box so a slow tour does not shift the page as it loads. */
.v3d-tours-head{max-width:42vw;margin-bottom:3vw}
.v3d-tours-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:2vw}
.v3d-tour{margin:0}
.v3d-tour-frame{position:relative;width:100%;padding-top:66%;overflow:hidden;background:var(--ab-noir)}
.v3d-tour-frame iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
.v3d-tour figcaption{margin-top:.6vw}
@media (max-width:900px){
  .v3d-tours-head{max-width:none}
  .v3d-tours-grid{grid-template-columns:1fr;gap:6vw}
  .v3d-tour figcaption{margin-top:2vw}
}

/* ============================================================================
   Long-form content on a service page.

   Everything an editor writes past the opening paragraphs lands here, so the
   section has to make plain Gutenberg output — headings, lists, quotes,
   tables, images — look like the rest of the page rather than like an editor
   dump. The grid is the eight columns the hero uses: an H2 spans all of them
   and reads as a section title, and the prose that follows sits in the right
   half, on the same 49vw line as the process rows and the pillar grid.
   ============================================================================ */

.v3d-rich { margin-top: 8vw; margin-bottom: 8vw; display: grid; grid-template-columns: repeat(8,1fr); column-gap: 2vw; }
.v3d-rich > * { grid-column: 5/-1; max-width: 52ch; }
.v3d-rich > *:first-child { margin-top: 0; }

/* Editor output carries no entrance classes, so the whole block rises at
   once when the section is reached, rather than element by element. */
.v3d-rich > * { opacity: 0; transform: translateY(40px);
	transition: opacity 1s cubic-bezier(.075,0,.165,0), transform 1.5s cubic-bezier(.075,.82,.165,1); }
.v3d-rich.in > * { opacity: 1; transform: translateY(0); }

/* An editor heading is a section heading: full width, on the left margin. */
.v3d-rich > h2 { grid-column: 1/-1; max-width: none; font-size: 4.86vw; line-height: .8; font-weight: 300;
	text-transform: uppercase; letter-spacing: -.03em; margin: 6vw 0 2.6vw -.03em; }
.v3d-rich > h2:first-child { margin-top: 0; }

.v3d-rich h3 { font-size: 1.5vw; line-height: 1.1; font-weight: 400; text-transform: uppercase;
	letter-spacing: -.03em; margin: 3vw 0 1vw; }
.v3d-rich h4 { font-size: 1.111vw; line-height: 1.2; font-weight: 400; text-transform: uppercase;
	letter-spacing: -.02em; margin: 2.4vw 0 .8vw; }
.v3d-rich h5, .v3d-rich h6 { font-size: 12px; line-height: 1.2; font-weight: 400; text-transform: uppercase;
	letter-spacing: var(--ab-ls-meta); color: var(--ab-rhone); margin: 2.4vw 0 .8vw; }

.v3d-rich p, .v3d-rich li { font-size: 1.111vw; line-height: 1.6; font-weight: 300; letter-spacing: -.01em; }
.v3d-rich p { margin-bottom: 1.2vw; }
.v3d-rich > p:last-child { margin-bottom: 0; }
.v3d-rich strong { font-weight: 600; }
.v3d-rich em { font-style: italic; }

/* Links in running text, wherever running text appears: the long-form body of a
   case or a service, the opening paragraphs above it, and a journal article.
   They carry a resting hairline, because in a block of text a link has to be
   visible before it is pointed at.

   On hover the line does not change colour, it leaves: anchored to its right
   edge it retracts to nothing, and on the way out it is anchored left again and
   grows back from the left. The two anchors are switched with a zero-length
   transition so the switch itself is never animated -- animating the position
   would slide the line across instead of drawing it. */
.v3d-rich a,
.v3d-projtxt p a,
.v3d-hero-desc p a,
.v3d-artbody a {
	position: relative; padding-bottom: 1px;
	background-image: linear-gradient(var(--ab-noir), var(--ab-noir));
	background-repeat: no-repeat;
	background-position: left bottom;
	background-size: 100% 1px;
	transition: background-size .45s var(--ab-e-hover), background-position 0s; }

.v3d-rich a:hover,
.v3d-rich a:focus-visible,
.v3d-projtxt p a:hover,
.v3d-projtxt p a:focus-visible,
.v3d-hero-desc p a:hover,
.v3d-hero-desc p a:focus-visible,
.v3d-artbody a:hover,
.v3d-artbody a:focus-visible {
	background-size: 0 1px;
	background-position: right bottom; }

@media (prefers-reduced-motion: reduce) {
	.v3d-rich a,
	.v3d-projtxt p a,
	.v3d-hero-desc p a,
	.v3d-artbody a { transition: none; }
}

.v3d-rich ul:not(.v3-blk-list), .v3d-rich ol { margin: 1.4vw 0 1.8vw; display: flex; flex-direction: column; gap: .7vw; }
.v3d-rich li:not(.v3-blk-item) { position: relative; padding-left: 1.6vw; }
.v3d-rich ul:not(.v3-blk-list) > li::before { content: ""; position: absolute; left: 0; top: .82em; width: .6vw; height: 1px; background: var(--ab-noir); }
.v3d-rich ol { counter-reset: v3d-rich-n; }
.v3d-rich ol > li:not(.v3-blk-item) { counter-increment: v3d-rich-n; padding-left: 2.4em; }
.v3d-rich ol > li::before { content: counter(v3d-rich-n,decimal-leading-zero); position: absolute; left: 0; top: .1em;
	width: 2.4em; font-size: 12px; line-height: 1.6; letter-spacing: var(--ab-ls-meta); color: var(--ab-rhone); }

.v3d-rich blockquote { grid-column: 3/-1; max-width: none; margin: 4vw 0; padding-left: 2vw;
	border-left: 1px solid var(--ab-noir); }
.v3d-rich blockquote p { font-size: 2.1vw; line-height: 1.15; font-weight: 300; letter-spacing: -.03em; margin-bottom: .8vw; }
.v3d-rich blockquote cite { display: block; font-size: 12px; font-style: normal; text-transform: uppercase;
	letter-spacing: var(--ab-ls-meta); color: var(--ab-rhone); }

/* Anything that wants room takes the whole grid. */
.v3d-rich > figure, .v3d-rich > .wp-block-image, .v3d-rich > .wp-block-embed,
.v3d-rich > .wp-block-table, .v3d-rich > .v3-blk,
.v3d-rich > .alignwide, .v3d-rich > .alignfull { grid-column: 1/-1; max-width: none; }
.v3d-rich figure { margin: 4vw 0; }
.v3d-rich figure img { width: 100%; height: auto; }
.v3d-rich figcaption { margin-top: .8vw; font-size: 12px; line-height: 1.2; text-transform: uppercase;
	letter-spacing: var(--ab-ls-meta); color: var(--ab-rhone); }
.v3d-rich hr, .v3d-rich .wp-block-separator { grid-column: 1/-1; max-width: none; border: 0; height: 1px;
	background: var(--ab-leman); margin: 5vw 0; }

/* Tables: hairlines only, the way the rest of the site draws its rules. */
/* The core table block draws a box around every cell; the site draws rules
   under rows and nothing else, so the sides are cleared first. */
.v3d-rich table { width: 100%; border: 0; border-collapse: collapse; margin: 3vw 0; }
.v3d-rich thead th { text-align: left; font-size: 12px; line-height: 1.2; font-weight: 400; text-transform: uppercase;
	letter-spacing: var(--ab-ls-meta); color: var(--ab-rhone); padding: 0 2vw 1vw 0;
	border: 0; border-bottom: 1px solid var(--ab-noir); }
.v3d-rich tbody th { text-align: left; font-weight: 400; }
.v3d-rich tbody td, .v3d-rich tbody th { font-size: 1.111vw; line-height: 1.4; font-weight: 300; letter-spacing: -.01em;
	padding: 1.2vw 2vw 1.2vw 0; border: 0; border-bottom: 1px solid var(--ab-leman); vertical-align: top; }
.v3d-rich tbody tr td:last-child, .v3d-rich tbody tr th:last-child { padding-right: 0; }
.v3d-rich .wp-block-table { overflow-x: auto; }

/* ---------- the core button block ----------
   An editor can drop a button into a case or a service page. It is given the
   same movement as the pills the theme prints: on hover the black collapses
   into a circle on the left and the citron underneath comes out. The one
   difference is the label, which stays put -- the theme's own pill swaps two
   labels behind a mask, and this markup has only one to show.
   --cut is measured in main.js, the same value the masked pills use. */
.v3d-rich .wp-block-buttons { grid-column: 5/-1; max-width: 52ch; display: flex; flex-wrap: wrap;
	gap: 1vw; margin: 3vw 0; }
.v3d-rich .wp-block-buttons.alignwide,
.v3d-rich .wp-block-buttons.alignfull { grid-column: 1/-1; max-width: none; }

.v3d-rich .wp-block-button__link {
	position: relative; isolation: isolate; display: inline-block;
	/* Room on both sides for the circle the black collapses into, the way the
	   theme's own pills are wide enough that their centred label clears it. */
	padding: 1em 4.2em; border: 0; border-radius: var(--ab-r-pill);
	background: transparent; color: var(--ab-alpin);
	font-size: 12px; line-height: 1; font-weight: 400; text-transform: uppercase;
	letter-spacing: var(--ab-ls-meta); text-decoration: none; white-space: nowrap;
	transition: color .6s cubic-bezier(.4,.4,.1,1); }

/* The citron underneath, uncovered as the black one shrinks. */
.v3d-rich .wp-block-button__link::before {
	content: ""; position: absolute; inset: 0; z-index: -2;
	border-radius: var(--ab-r-pill); background: var(--ab-citron); }

/* The black on top, which becomes the circle. */
.v3d-rich .wp-block-button__link::after {
	content: ""; position: absolute; inset: 0; z-index: -1;
	border-radius: var(--ab-r-pill); background: var(--ab-noir);
	clip-path: inset(0px 0px 0px 0px round 999px);
	transition: clip-path .6s cubic-bezier(.4,.4,.1,1); }

.v3d-rich .wp-block-button__link:hover,
.v3d-rich .wp-block-button__link:focus-visible { color: var(--ab-noir); }
.v3d-rich .wp-block-button__link:hover::after,
.v3d-rich .wp-block-button__link:focus-visible::after {
	clip-path: inset(4px var(--cut, 60%) 4px 4px round 999px); }

/* The outline variation has no fill to collapse, so it keeps the plain swap. */
.v3d-rich .is-style-outline .wp-block-button__link {
	color: var(--ab-noir); box-shadow: inset 0 0 0 1px var(--ab-noir);
	transition: color .35s var(--ab-e-hover), box-shadow .35s var(--ab-e-hover); }
.v3d-rich .is-style-outline .wp-block-button__link::before,
.v3d-rich .is-style-outline .wp-block-button__link::after { content: none; }
.v3d-rich .is-style-outline .wp-block-button__link:hover,
.v3d-rich .is-style-outline .wp-block-button__link:focus-visible {
	color: var(--ab-alpin); box-shadow: inset 0 0 0 3em var(--ab-noir); }

@media (max-width: 768px) {
	.v3d-rich .wp-block-buttons { margin: 6vw 0; gap: 3vw; }
}

@media (prefers-reduced-motion: reduce) {
	.v3d-rich .wp-block-button__link,
	.v3d-rich .wp-block-button__link::after { transition: none; }
}

/* ---------- the two ABiL blocks ---------- */

.v3d-rich .v3-blk { margin: 5vw 0; }
.v3d-rich .v3-blk-h { margin-bottom: 2vw; }

/* What is included: a checklist read as a grid, so a long list stays scannable. */
.v3d-rich .v3-blk-list { display: grid; grid-template-columns: repeat(3,1fr); column-gap: 2vw; row-gap: 0; margin: 0; }
.v3d-rich .v3-blk-item { position: relative; padding: 1.4vw 0 1.4vw 1.6vw; border-bottom: 1px solid var(--ab-leman);
	display: flex; flex-direction: column; gap: .5vw; }
.v3d-rich .v3-blk-item::before { content: ""; position: absolute; left: 0; top: 1.85vw; width: .6vw; height: 1px; background: var(--ab-noir); }
.v3d-rich .v3-blk-n { display: block; }
.v3d-rich .v3-blk-d { display: block; line-height: 1.5; color: var(--ab-rhone); }

/* Then and now: two headed columns of pairs. The second column is the older
   voice, so it is set in italic and a shade back. */
.v3d-rich .v3-blk-cmp-grid { display: grid; grid-template-columns: 1fr 1fr; column-gap: 2vw; }
.v3d-rich .v3-blk-cmp-head { padding-bottom: 1vw; border-bottom: 1px solid var(--ab-noir);
	color: var(--ab-rhone); text-transform: uppercase; letter-spacing: var(--ab-ls-meta); }
.v3d-rich .v3-blk-cmp-cell { padding: 1.6vw 0; border-bottom: 1px solid var(--ab-leman); line-height: 1.5; }
.v3d-rich .v3-blk-cmp-then { font-style: italic; color: var(--ab-rhone); }

/* Outcome: the figures, given the size the page gives its numbers elsewhere. */
.v3d-rich .v3-blk-figs { display: grid; grid-template-columns: repeat(3,1fr); column-gap: 2vw; row-gap: 3vw; }
.v3d-rich .v3-blk-fig { margin: 0; padding-top: 1.4vw; border-top: 1px solid var(--ab-noir); }
.v3d-rich .v3-blk-val { margin-bottom: 1vw; }
.v3d-rich .v3-blk-cap { font-size: 1.111vw; line-height: 1.5; text-transform: none;
	letter-spacing: -.01em; color: var(--ab-noir); margin-top: 0; max-width: 32ch; }

@media (min-width: 769px) and (max-width: 1280px) {
	.v3d-rich p, .v3d-rich li, .v3d-rich tbody td, .v3d-rich tbody th, .v3d-rich .v3-blk-cap { font-size: 14px; }
}

@media (max-width: 900px) {
	.v3d-rich .v3-blk-list, .v3d-rich .v3-blk-figs { grid-template-columns: repeat(2,1fr); }
}

@media (max-width: 768px) {
	.v3d-rich { grid-template-columns: 1fr; margin-top: 20vw; margin-bottom: 20vw; }
	.v3d-rich > *, .v3d-rich > h2, .v3d-rich blockquote { grid-column: 1/-1; max-width: none; }
	.v3d-rich > h2 { font-size: 9.5vw; margin: 14vw 0 6vw -.03em; }
	.v3d-rich h3 { font-size: 4.4vw; margin: 8vw 0 3vw; }
	.v3d-rich h4 { font-size: 16px; margin: 6vw 0 2vw; }
	.v3d-rich p, .v3d-rich li, .v3d-rich tbody td, .v3d-rich tbody th, .v3d-rich .v3-blk-cap { font-size: 16px; }
	.v3d-rich p { margin-bottom: 4vw; }
	.v3d-rich ul, .v3d-rich ol { margin: 4vw 0 6vw; gap: 2.4vw; }
	.v3d-rich li:not(.v3-blk-item) { padding-left: 5vw; }
	.v3d-rich ol > li:not(.v3-blk-item) { padding-left: 2.4em; }
	.v3d-rich ul > li::before { width: 2.4vw; }
	.v3d-rich blockquote { margin: 10vw 0; padding-left: 5vw; }
	.v3d-rich blockquote p { font-size: 6.9vw; margin-bottom: 3vw; }
	.v3d-rich figure { margin: 10vw 0; }
	.v3d-rich hr, .v3d-rich .wp-block-separator { margin: 12vw 0; }
	.v3d-rich table { margin: 8vw 0; }
	.v3d-rich thead th { padding: 0 4vw 3vw 0; }
	.v3d-rich tbody td, .v3d-rich tbody th { padding: 3vw 4vw 3vw 0; }
	.v3d-rich .v3-blk { margin: 14vw 0; }
	.v3d-rich .v3-blk-h { margin-bottom: 6vw; }
	.v3d-rich .v3-blk-list, .v3d-rich .v3-blk-figs { grid-template-columns: 1fr; row-gap: 0; }
	/* Stacked, a pair needs its own label or the two halves run together. */
	.v3d-rich .v3-blk-cmp-grid { grid-template-columns: 1fr; }
	.v3d-rich .v3-blk-cmp-head { display: none; }
	.v3d-rich .v3-blk-cmp-cell { padding: 4vw 0; }
	.v3d-rich .v3-blk-cmp-cell:nth-child(odd) { border-bottom: 0; padding-bottom: 1.5vw; }
	.v3d-rich .v3-blk-item { padding: 4vw 0 4vw 5vw; gap: 1.6vw; }
	.v3d-rich .v3-blk-item::before { top: 5.6vw; width: 2.4vw; }
	.v3d-rich .v3-blk-figs { row-gap: 8vw; }
	.v3d-rich .v3-blk-fig { padding-top: 4vw; }
	.v3d-rich .v3-blk-val { margin-bottom: 3vw; }
	.v3d-rich .v3-blk-cap { max-width: none; }
}

@media (prefers-reduced-motion: reduce) {
	.v3d-rich > * { opacity: 1 !important; transform: none !important; }
}

/* ============================================================================
   How we work, on a service page.

   The steps used to be an accordion, which hid four fifths of the method
   behind a click. They read in sequence now, all open, on a dark band that
   separates them from the questions above and the work below. Nothing opens
   or closes: the pointer only picks a step out of the sequence.
   ============================================================================ */

.v3d-steps { background: var(--ab-noir); color: var(--ab-alpin); padding: 7vw 0 5vw; margin: 8vw 0; }
.v3d-steps-in { display: grid; grid-template-columns: repeat(2,1fr); column-gap: 2vw; align-items: start; }
.v3d-steps-head { width: 34.75vw; position: sticky; top: 8vw; }
.v3d-steps-list { list-style: none; margin: 0; padding: 0; counter-reset: none; }

.v3d-step { position: relative; display: grid; grid-template-columns: 3.4vw 1fr; column-gap: 1vw;
	padding: 2.2vw 0 2.6vw; opacity: 0; transform: translateY(40px);
	transition: opacity 1s cubic-bezier(.075,0,.165,0), transform 1.5s cubic-bezier(.075,.82,.165,1);
	transition-delay: var(--d,0s); }
.v3d-steps.in .v3d-step { opacity: 1; transform: translateY(0); }

.v3d-step-n { padding-top: .35vw; color: var(--ab-rhone); transition: color .4s var(--ab-e-hover); }
.v3d-step-body { transition: transform .6s var(--ab-e-out); }
.v3d-step-h { margin-bottom: .9vw; }
.v3d-step-p { line-height: 1.6; max-width: 52ch; color: var(--ab-leman); transition: color .4s var(--ab-e-hover); }

/* The rule under each step fills in citron under the pointer, the way the
   hairlines elsewhere on the site travel rather than fade. */
.v3d-step-line { position: absolute; left: 0; right: 0; bottom: 0; height: 1px; overflow: hidden;
	background: rgba(255,255,255,.2); }
.v3d-step-line::after { content: ""; position: absolute; inset: 0; background: var(--ab-citron);
	transform: scaleX(0); transform-origin: left center; transition: transform .7s var(--ab-e-out); }

.v3d-step:hover .v3d-step-line::after { transform: scaleX(1); }
.v3d-step:hover .v3d-step-n { color: var(--ab-citron); }
.v3d-step:hover .v3d-step-p { color: var(--ab-alpin); }
.v3d-step:hover .v3d-step-body { transform: translateX(.7vw); }

@media (max-width: 768px) {
	.v3d-steps { padding: 20vw 0 14vw; margin: 20vw 0; }
	.v3d-steps-in { grid-template-columns: 1fr; row-gap: 10vw; }
	.v3d-steps-head { width: 100%; position: static; }
	.v3d-step { grid-template-columns: 10vw 1fr; column-gap: 2vw; padding: 6vw 0 7vw; }
	.v3d-step-n { padding-top: 1vw; }
	.v3d-step-h { margin-bottom: 3vw; }
	.v3d-step-p { max-width: none; }
	.v3d-step:hover .v3d-step-body { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
	.v3d-step { opacity: 1 !important; transform: none !important; }
	.v3d-step:hover .v3d-step-body { transform: none; }
}

/* ---------- the services behind a case or an article ----------
   A line of links, not a row of buttons: the page already has its own call to
   action, and this is only the step between "I want this" and the page that
   explains it. */
.v3d-svcused { margin-top: 6vw; margin-bottom: 6vw; display: grid; grid-template-columns: repeat(8,1fr); column-gap: 2vw; row-gap: 1.2vw; }
.v3d-svcused-h { grid-column: 1/-1; color: var(--ab-rhone); text-transform: uppercase;
	letter-spacing: var(--ab-ls-meta); }
.v3d-svcused-list { grid-column: 1/-1; display: flex; flex-wrap: wrap; gap: 1vw 2.4vw; list-style: none; }

/* The accent, as a state rather than as decoration: a citron rule at rest, and
   the whole word filled on hover, the way a highlighter is drawn across it.
   The same background-size trick the prose links use, only vertical. */
.v3d-svcused-list a { position: relative; text-transform: uppercase; padding: .06em .18em .12em;
	margin: 0 -.18em; background-image: linear-gradient(var(--ab-citron), var(--ab-citron));
	background-repeat: no-repeat; background-position: 0 100%; background-size: 100% 3px;
	transition: background-size .38s var(--ab-e-hover); }
.v3d-svcused-list a:hover,
.v3d-svcused-list a:focus-visible { background-size: 100% 100%; }

@media (prefers-reduced-motion: reduce) { .v3d-svcused-list a { transition: none; } }

/* ---------- the pill that closes the two browsing archives ---------- */
.v3d-archcta { margin-top: 6vw; margin-bottom: 8vw; display: flex; justify-content: center; }

@media (max-width: 768px) {
	.v3d-svcused { margin-top: 12vw; margin-bottom: 12vw; row-gap: 3vw; }
	.v3d-svcused-list { gap: 3vw 5vw; }
	.v3d-svcused-list a { font-size: 18px; }
	.v3d-archcta { margin-top: 12vw; margin-bottom: 14vw; }
}
