/* ============================================================
   V2 homepage overrides — loaded by index.html.
   Every rule is scoped under html[data-v2] so this file can sit
   in the shared css/ folder without touching index_old.html.

   Contents:
     1. Token adjustments (wire spirit ink)
     2. Site-wide grain overlay
     3. Duotone utility (.duo)
     4. Hero — filled CTA + media chip
     5. V2 seam (Arpeggio sticky color flip → How We Work)
     6. Services — compressed rest state
     7. Team cloud — soft ground + wire-language mesh
     8. Our Work — featured case card + browser frame
     9. Wide-desktop container
   ============================================================ */


/* ---- 1. Token adjustments ---------------------------------- */

html[data-v2] {
    /* Wire spirit reads as a deliberate signature, not a ghost —
       0.8 proved too noisy against the hero scribble density */
    --wire-opacity: 0.65;
    /* Pull the depth fog in so far strands dissolve sooner: fewer
       visible strokes, cleaner drawing, same shape recipes (the
       strand layout itself is fixed at 24 by the icon geometry). */
    --wire-fog-far: 9;
}


/* ---- 2. Site-wide grain ------------------------------------
   Fine static noise over every flat color flood. Fixed, so it
   costs one compositing layer; pointer-transparent; sits below
   the overlay dialogs (menu/story panels are z-index >= 100). */

html[data-v2] body::after {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 90;
    pointer-events: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size: 160px 160px;
    opacity: 0.05;
    mix-blend-mode: overlay;
}


/* ---- 3. Duotone utility ------------------------------------
   Brand-blue duotone: grayscale image multiplied over a blue
   plate. Keeps a visually-dated capture on-brand and consistent
   with every other visual on the page. */

html[data-v2] .duo {
    position: relative;
    display: block;
    overflow: hidden;
    background: var(--blue);
}
html[data-v2] .duo > img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Shadow lift (partial invert) + brightness so even dark source
       photos map to blue tones instead of crushing to black under
       the multiply against the blue plate */
    filter: grayscale(1) invert(0.18) brightness(2) contrast(0.9);
    mix-blend-mode: multiply;
}
/* Warm lift in the highlights so the duotone doesn't go muddy */
html[data-v2] .duo::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(160deg, rgba(240, 82, 35, 0.18), transparent 55%);
    mix-blend-mode: screen;
    pointer-events: none;
}


/* ---- 4. Hero ------------------------------------------------ */

/* Conversion CTA promoted to a filled button (v1 keeps both as
   underline links). The underline pseudo is repurposed as none. */
html[data-v2] .hero__cta--fill {
    padding: 0.85em 1.6em;
    background: var(--orange);
    color: var(--paper);
    border-radius: 100px;
    transition: background var(--dur-fast) var(--ease-out),
                transform var(--dur-fast) var(--ease-out);
}
html[data-v2] .hero__cta--fill::after { display: none; }
html[data-v2] .hero__cta--fill .hero__cta-arrow { color: var(--paper); }
html[data-v2] .hero__cta--fill:hover,
html[data-v2] .hero__cta--fill:focus-visible {
    background: #d84317;
    transform: translateY(-2px);
}

/* Media chip — duotone photo as the third item in the hero foot row.
   TEMP: hidden for the next deploy. Restore: display:block (and drop
   `hidden` on the markup in index.html). */
html[data-v2] .hero__media {
    display: none;
    flex: none;
    width: clamp(12rem, 15vw, 16rem);
    text-decoration: none;
    color: var(--dark-gray);
}
html[data-v2] .hero__media-frame {
    aspect-ratio: 4 / 3;
    border-radius: var(--radius);
    box-shadow: 0 18px 50px rgba(13, 15, 20, 0.22);
    transition: transform var(--dur-med) var(--ease-out),
                box-shadow var(--dur-med) var(--ease-out);
}
html[data-v2] .hero__media:hover .hero__media-frame,
html[data-v2] .hero__media:focus-visible .hero__media-frame {
    transform: translateY(-4px) rotate(-0.5deg);
    box-shadow: 0 26px 60px rgba(13, 15, 20, 0.3);
}
html[data-v2] .hero__media-cap {
    display: block;
    margin-top: 0.7rem;
    font-family: var(--font-body);
    font-size: var(--fs-paragraph-sm);
    line-height: 1.45;
    color: var(--muted);
}
html[data-v2] .hero__media-k {
    display: block;
    font-weight: var(--wt-body-bold);
    font-size: 0.7rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--orange);
}
html[data-v2] .hero__media-arrow {
    display: inline-block;
    color: var(--orange);
    transition: transform var(--dur-fast) var(--ease-out);
}
html[data-v2] .hero__media:hover .hero__media-arrow { transform: translateX(0.35em); }

@media (max-width: 1279px), (max-height: 720px) {
    html[data-v2] .hero__media { display: none; }
}


/* ---- 5. V2 seam — Arpeggio scaling-circle flip ---------------
   Exact port of the reference mechanism, colors reversed.

   .v2-dot        24px strip at the seam (matches the reference's
                  "Dot Enlarge" strip); no clipping so the disc can
                  flood past it.
   .v2-dot__disc  500px deep-ink circle, scale 0 → ~9 scrubbed by
                  v2.js as the strip crosses the viewport.
   .v2-hww        the incoming header block: structurally TRANSPARENT
                  (paper shows through, mirroring the reference where
                  the section stays the outgoing color and the disc
                  paints the incoming one). Holds the giant fit-width
                  title in the incoming text color (paper), scale
                  0.2 → 1 — invisible on white until the dark circle
                  sweeps in behind it.

   Stacking: services (auto) < disc (z2) < title/process (z3).     */

/* Extra paper after the lattice so the last service row can leave
   the viewport before the disc starts growing from the seam. */
html[data-v2] .services {
    padding-bottom: 50vh;
}

html[data-v2] .v2-dot {
    position: relative;
    z-index: 2;
    height: 24px;
    display: grid;
    place-items: center;
    overflow: visible;
    /* The grown disc sweeps over interactive content (service cards,
       work links) — it must never eat their clicks. */
    pointer-events: none;
}
html[data-v2] .v2-dot__disc {
    position: absolute;
    left: 50%;
    top: 50%;
    /* 500px on desktop; never wider than the viewport so phones
       don't grow a horizontal scrollbar from the unscaled disc. */
    width: min(500px, 100vw);
    aspect-ratio: 1;
    border-radius: 50%;
    /* Trial: match process plate. Revert to --deep. */
    background: var(--blue);
    transform: translate(-50%, -50%) scale(0);
    transform-origin: center center;
    will-change: transform;
}

/* Title lives in the strip so it shares the disc origin. Circle
   center would be translateY(-50%); the extra -20% lifts it above
   that so the landed line sits further from the section header. */
html[data-v2] .v2-hww__title {
    --v2-title-lift: -70%; /* -50% = circle center; extra -20% of self */
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    z-index: 3;
    margin: 0;
    padding: 0 var(--gutter);
    width: 100%;
    box-sizing: border-box;
    text-align: center;
    /* Fallback size; v2.js fits both titles to the same capped size. */
    font-size: clamp(4rem, 14.5vw, 17rem);
    font-family: var(--font-display);
    font-weight: var(--wt-display);
    letter-spacing: -0.04em;
    line-height: 1em;
    white-space: nowrap;
    color: var(--paper);
    transform: translateY(var(--v2-title-lift)) scale(0.2);
    transform-origin: center center;
    will-change: transform;
}
html[data-v2] .v2-hww__title [data-v2-hww-fit] {
    display: block;
    width: 100%;
    text-align: center;
    /* Tracking must live HERE, in em, so it resolves against the
       fitted font-size. Inherited from the p it computes to fixed px
       (vs the p's font-size) and stops scaling with the fit — the
       glyph run ends up wider than the box and overflows to the
       right. The -0.02em nudge cancels the trailing letter-space the
       centering includes after the last glyph. */
    letter-spacing: -0.04em;
    transform: translateX(-0.02em);
}

/* Spacer only — just enough room for the landed title's lower half
   so #process copy sits tight beneath it (the reference lands "what
   we do" with its sub-copy directly below). */
html[data-v2] .v2-hww {
    position: relative;
    z-index: 3;
    /* Extra runway so the landed giant title can shrink into the
       numbered kicker before the section head fills the viewport. */
    min-height: 28vh;
    pointer-events: none;
}

html[data-v2] #process {
    position: relative;
    z-index: 3;
    /* Head now carries the numbered kicker (the giant title morphs
       into it), so restore real top padding. Extra dark runway at the
       bottom mirrors the entry seam: the paper exit disc rises through
       it before overtaking the step cards. */
    padding-top: var(--space-xl);
    padding-bottom: 40vh;
    /* Trial: brand-blue plate. Revert: drop this background. */
    background: var(--blue);
}

/* ---- Exit seam: How We Work → Our Work. Same move, colors flipped
   back — a paper disc floods the dark, carrying a giant ink "our
   work". Sits above #process (z3) so the paper can paint over the
   deep ground; pointer-events stay off. */
html[data-v2] .v2-dot--out {
    z-index: 4;
    /* Outgoing plate continues through the 24px strip. */
    background: var(--blue);
}
/* Trial: var(--deep) flood + paper title so the seam matches #work. */
html[data-v2] .v2-dot--out .v2-dot__disc { background: var(--deep); }
html[data-v2] .v2-dot--out .v2-hww__title { color: var(--paper); }
/* Same spacer as the entry seam — both titles now share one max size.
   Paint the outgoing blue so paper cannot show under the growing disc;
   the shadow extends that plate to the bottom of the viewport without
   adding scroll (incoming #work sits above it at z5). */
html[data-v2] .v2-hww--out {
    min-height: 28vh;
    background: var(--blue);
    box-shadow: 0 100vh 0 0 var(--blue);
}

/* z5 lifts the content above the exit disc (z4) the same way
   #process (z3) rides the entry disc (z2). */
html[data-v2] #work {
    position: relative;
    z-index: 5;
    padding-top: var(--space-xl);
    /* Trial: var(--deep) plate. Revert: drop background + type overrides. */
    background: var(--deep);
}
html[data-v2] #work .work-carousel__head .process__headline {
    color: var(--paper);
}
html[data-v2] #work .work-carousel__head .process__headline em {
    color: var(--orange);
}
html[data-v2] #work .work-carousel__sub {
    color: color-mix(in srgb, var(--paper) 82%, transparent);
}

/* Trial: tone-on-tone cards — darker brown plate, inverted (warm) type.
   Revert: drop this block. */
html[data-v2] #work .work-carousel-card {
    background: var(--deep);
    border-color: color-mix(in srgb, var(--paper-warm) 14%, transparent);
}
html[data-v2] #work .work-carousel-card__panel,
html[data-v2] #work .work-carousel-card__panel--light {
    background: var(--deep);
}
html[data-v2] #work .work-carousel-card__panel--light .work-carousel-card__title {
    color: var(--paper-warm);
}
html[data-v2] #work .work-carousel-card__panel--light .work-carousel-card__excerpt {
    color: color-mix(in srgb, var(--paper-warm) 78%, transparent);
}
html[data-v2] #work .work-carousel-card__panel--light .work-carousel-card__specs li {
    color: color-mix(in srgb, var(--paper-warm) 72%, transparent);
    border-color: color-mix(in srgb, var(--paper-warm) 28%, transparent);
}
html[data-v2] #work .work-carousel-card__photo {
    background: var(--deep);
}
html[data-v2] #work .work-carousel-card__photo--placeholder {
    background: var(--deep);
}
html[data-v2] #work .work-carousel-card__mono {
    color: color-mix(in srgb, var(--paper-warm) 32%, transparent);
}

/* JS: the giant seam title shrinks into this kicker, so the real
   label stays invisible until the morph hands off. No-JS / reduced
   motion / v2-static show the label in place. */
html[data-v2].js:not(.no-motion):not(.v2-static) #process-label,
html[data-v2].js:not(.no-motion):not(.v2-static) #work-label {
    opacity: 0;
}

/* Fixed clone of the seam title — v2.js FLIP-scrubs it from the
   landed giant size into the numbered section-label slot. */
html[data-v2] .v2-hww__title--morph {
    position: fixed;
    left: auto;
    right: auto;
    top: auto;
    z-index: 6;
    margin: 0;
    padding: 0;
    width: auto;
    overflow: visible;
    white-space: nowrap;
    transform: none;
    pointer-events: none;
    will-change: transform, color, opacity;
    transform-origin: center center;
}

/* Fallback — no JS or reduced motion: hard color flip instead of
   the scaling disc. Phones keep the live seam (disc + shrink-to-
   eyebrow); only these static flags skip it. */
html[data-v2]:not(.js) .v2-dot__disc,
html[data-v2].no-motion .v2-dot__disc,
html[data-v2].v2-static .v2-dot__disc {
    display: none;
}
html[data-v2]:not(.js) .v2-dot,
html[data-v2].no-motion .v2-dot,
html[data-v2].v2-static .v2-dot {
    height: auto;
    min-height: 38vh;
    background: var(--blue);
}
html[data-v2]:not(.js) .v2-hww__title,
html[data-v2].no-motion .v2-hww__title,
html[data-v2].v2-static .v2-hww__title {
    position: static;
    transform: none;
    padding-block: var(--space-lg);
}
html[data-v2]:not(.js) .v2-hww,
html[data-v2].no-motion .v2-hww,
html[data-v2].v2-static .v2-hww {
    min-height: 0;
}
/* Exit strip flips the other way in the static fallback: a paper
   block carrying the ink title (color set by the --out variant). */
html[data-v2]:not(.js) .v2-dot--out,
html[data-v2].no-motion .v2-dot--out,
html[data-v2].v2-static .v2-dot--out {
    background: var(--deep);
}
html[data-v2]:not(.js) .v2-hww--out,
html[data-v2].no-motion .v2-hww--out,
html[data-v2].v2-static .v2-hww--out {
    background: transparent;
    box-shadow: none;
}


/* ---- 6. Services — compressed rest state --------------------
   The 3×3 lattice reads as a quieter index: shorter cells, so the
   whole section fits closer to two viewports instead of three. */

html[data-v2] .services__headline {
    margin-inline: auto;
    text-align: center;
}
/* 25rem clears the longest blurb + two-row tags with the icon yielded
   (Custom Application Development clipped at 23rem); still 5rem
   tighter than the v1 lattice. */
html[data-v2] .service { min-height: 25rem; }
@media (max-width: 1279px) {
    html[data-v2] .service { min-height: 18rem; }
}
@media (max-width: 767px) {
    html[data-v2] .service { min-height: 0; }
}

/* TEMP launch: hide What We Do "Learn more" pills (the detail drawers
   they open are placeholder copy). Restore: drop this rule, un-hide
   .service__tags-more in index.html, and remove the early return in
   js/modules/service-story.js. */
html[data-v2] .service__tags-more { display: none; }

/* In the compressed cell the lifted blurb needs the icon's zone: the
   icon yields (fades up and away) while its card is open, instead of
   the text colliding with it. No height change — the lattice never
   reflows and the row stays uniform. Desktop only: stacked mobile
   cards lift nothing, so the icon stays. */
@media (min-width: 768px) {
    html[data-v2] .service__icon {
        transition: transform var(--dur-med) var(--ease-out),
            opacity var(--dur-med) var(--ease-out);
    }
    html[data-v2] .service.is-active .service__icon,
    html[data-v2] .service:focus-within .service__icon {
        opacity: 0;
        transform: translateY(-10px) scale(0.94);
    }
}


/* ---- 7. Team cloud — soft ground + wire-language mesh --------
   The halftone image treatment is gone (Jeff note). Instead: a
   barely-there warm ground so the white node discs pop off the
   page, a whisper of ruling (drawn, not an image), and the mesh
   redrawn in the wire spirit's stroke language — solid hairline
   ink with JS depth-fade, the flat dialect of the same instrument. */

html[data-v2] .ecosystem {
    /* Solid, so it also occludes the fixed wire canvas behind #main. */
    background: #f5f4f0;
}
/* The spirit's own mesh as the ground texture: wire-mesh.svg is the
   hero globe's ACTUAL 24-strand geometry (wire-shapes.js) projected
   flat by scripts/gen-wire-mesh.mjs, per-strand depth fade imitating
   the Three fog. A huge cropped portion bleeds off the bottom-left. */
html[data-v2] .ecosystem::before {
    content: '';
    position: absolute;
    width: clamp(60rem, 90vw, 105rem);
    height: clamp(60rem, 90vw, 105rem);
    left: -34rem;
    bottom: -42rem;
    background: url('../assets/img/wire-mesh.svg') center / contain no-repeat;
    opacity: 0.16;
    pointer-events: none;
}
/* Stage content always rides above the texture. */
html[data-v2] .ecosystem__stage {
    position: relative;
    z-index: 1;
}

/* Nodes: 90% white discs so they lift off the ground without going solid. */
html[data-v2] .eco-node__figure {
    background: rgba(255, 255, 255, 0.9);
    box-shadow: 0 10px 30px rgba(13, 15, 20, 0.08);
}

/* Connectors pick up the spirit's ORGANIC stroke: a seamless sine
   tile (one full period, so it loops cleanly along any length)
   replaces the straight rule — every thread in the cloud undulates
   like a wire strand. ecosystem.js still stretches / rotates each
   div in 3D and fades it by depth; only the paint changes.
   The 9px-tall box is recentred on the geometric line (margin-top),
   keeping transform-origin 0 50% on the node centre. */
html[data-v2] .eco-line {
    height: 9px;
    margin-top: -4.5px;
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 9'%3E%3Cpath d='M0 4.5 Q6.5 1.2 13 4.5 T26 4.5' fill='none' stroke='%2316161a' stroke-opacity='0.5' stroke-width='1.1'/%3E%3C/svg%3E") left center / 26px 9px repeat-x;
}
html[data-v2] .eco-line.is-hot {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 9'%3E%3Cpath d='M0 4.5 Q6.5 1.2 13 4.5 T26 4.5' fill='none' stroke='%23f05223' stroke-width='1.8'/%3E%3C/svg%3E");
}

/* ---- Collective + Look at Us share footer --deep --------------
   Invert type (and the ink mesh / sine / rings that would disappear
   on dark). White node discs stay. Orange kicker / active index /
   hot strand unchanged.
   Revert: delete this whole block. Original v2 ground is the
   #f5f4f0 rule above. */
html[data-v2] .who-panel--eco,
html[data-v2] .ecosystem {
    background: var(--deep);
    color: var(--paper);
}
html[data-v2] .ecosystem { min-height: 100%; }
html[data-v2] .ecosystem::before {
    filter: invert(1);
    opacity: 0.22;
}
html[data-v2] .ecosystem__title { color: var(--paper); }
html[data-v2] .ecosystem__sub {
    color: color-mix(in srgb, var(--paper) 82%, transparent);
}
html[data-v2] .ecosystem__legend-item {
    color: color-mix(in srgb, var(--paper) 70%, transparent);
}
html[data-v2] .ecosystem__legend-item:hover,
html[data-v2] .ecosystem__legend-item.is-active {
    color: var(--paper);
}
html[data-v2] .ecosystem__legend-index {
    color: color-mix(in srgb, var(--paper) 40%, transparent);
}
html[data-v2] .eco-node.is-focus .eco-node__label { color: var(--paper-warm); }
html[data-v2] .eco-node__figure {
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
}
html[data-v2] .eco-ring {
    border-color: color-mix(in srgb, var(--paper-warm) 18%, transparent);
}
html[data-v2] .eco-line {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 9'%3E%3Cpath d='M0 4.5 Q6.5 1.2 13 4.5 T26 4.5' fill='none' stroke='%23f6f5f2' stroke-opacity='0.5' stroke-width='1.1'/%3E%3C/svg%3E");
}
html[data-v2] .ecosystem__panel {
    background: var(--deep);
    border-color: color-mix(in srgb, var(--paper-warm) 14%, transparent);
    box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45);
    color: var(--paper-warm);
}
html[data-v2] .ecosystem__panel::before {
    border-top-color: color-mix(in srgb, var(--paper-warm) 45%, transparent);
}
html[data-v2] .ecosystem__index [data-eco-total],
html[data-v2] .ecosystem__index-sep {
    color: color-mix(in srgb, var(--paper) 40%, transparent);
}
html[data-v2] .ecosystem__role-name { color: var(--paper-warm); }
html[data-v2] .ecosystem__role-desc {
    color: color-mix(in srgb, var(--paper-warm) 78%, transparent);
}
html[data-v2] .ecosystem:not(.is-3d) .ecosystem__role {
    border-top-color: color-mix(in srgb, var(--paper-warm) 14%, transparent);
}
html[data-v2] .ecosystem:not(.is-3d) .ecosystem__role h4 {
    color: var(--paper-warm);
}
html[data-v2] .ecosystem:not(.is-3d) .ecosystem__role p {
    color: color-mix(in srgb, var(--paper-warm) 78%, transparent);
}
/* Keep the ground mesh inside the panel on phones — the desktop
   60rem tile otherwise pokes 26px past a 390px viewport. */
html[data-v2] .ecosystem:not(.is-3d)::before {
    width: 100%;
    height: min(40rem, 90%);
    left: 0;
    bottom: -25%;
}


/* ---- 7b. Who panel 3 — full-bleed promo still -----------------
   PROMOTED TO DEFAULT (sections.css): the Arpeggio image treatment
   now ships on v1 too, so the media/scrim rules moved out of this
   v2-scoped file. Nothing v2-specific remains for Panel 3. */

/* ---- 8. Our Work — featured case card ------------------------ */

html[data-v2] .work-feature {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    gap: clamp(1.5rem, 4vw, 4rem);
    align-items: center;
    max-width: var(--container);
    margin: var(--space-lg) auto var(--space-xl);
    text-decoration: none;
    color: inherit;
}
html[data-v2] .work-feature__media {
    position: relative;
    display: block;
    /* Breathing room for the offset browser frame */
    padding-bottom: 9%;
}
html[data-v2] .work-feature__photo {
    aspect-ratio: 16 / 10;
    border-radius: var(--radius);
    transition: transform var(--dur-med) var(--ease-out);
}
html[data-v2] .work-feature:hover .work-feature__photo { transform: scale(1.015); }

/* Reusable device treatment: minimal browser chrome around a raw
   site capture, floated over the duotone location photo. */
html[data-v2] .browser-frame {
    position: absolute;
    right: -4%;
    bottom: 0;
    width: 58%;
    border-radius: 0.45rem;
    overflow: hidden;
    background: var(--paper);
    box-shadow: 0 32px 80px rgba(13, 15, 20, 0.35);
    transition: transform var(--dur-med) var(--ease-out);
}
html[data-v2] .work-feature:hover .browser-frame { transform: translateY(-6px); }
html[data-v2] .browser-frame__bar {
    display: flex;
    gap: 5px;
    padding: 8px 10px;
    background: #eceff3;
}
html[data-v2] .browser-frame__bar i {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #d2d8e0;
}
html[data-v2] .browser-frame > img {
    display: block;
    width: 100%;
    height: auto;
}

html[data-v2] .work-feature__meta { display: block; }
html[data-v2] .work-feature__k {
    display: block;
    font-family: var(--font-body);
    font-size: 0.72rem;
    font-weight: var(--wt-body-bold);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--orange);
}
html[data-v2] .work-feature__title {
    display: block;
    margin-top: 0.8rem;
    font-family: var(--font-display);
    font-size: var(--fs-h3);
    font-weight: var(--wt-display);
    line-height: var(--lh-h3, 1.15);
    letter-spacing: -0.02em;
    color: var(--dark-gray);
    text-wrap: balance;
}
html[data-v2] .work-feature__desc {
    display: block;
    margin-top: 0.9rem;
    font-family: var(--font-body);
    font-size: var(--fs-paragraph);
    line-height: var(--lh-paragraph, 1.6);
    color: var(--muted);
    text-wrap: pretty;
}
html[data-v2] .work-feature__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 1.1rem;
}
html[data-v2] .work-feature__tags span {
    padding: 0.3em 0.85em;
    border: 1px solid var(--line);
    border-radius: 100px;
    font-family: var(--font-body);
    font-size: var(--fs-paragraph-sm);
    font-weight: 700;
    letter-spacing: 0.03em;
    color: var(--muted);
}
html[data-v2] .work-feature__cta {
    display: inline-block;
    margin-top: 1.4rem;
    font-family: var(--font-body);
    font-size: var(--fs-paragraph-sm);
    font-weight: var(--wt-body-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--orange);
}
html[data-v2] .work-feature__cta span {
    display: inline-block;
    transition: transform var(--dur-fast) var(--ease-out);
}
html[data-v2] .work-feature:hover .work-feature__cta span { transform: translateX(0.35em); }

@media (max-width: 1023px) {
    html[data-v2] .work-feature { grid-template-columns: 1fr; }
    html[data-v2] .work-feature__media { padding-bottom: 12%; }
}


/* Wide-desktop container now lives in tokens.css (site-wide:
   --container 75rem → 81.25rem at ≥1600px). */
