/* ═══════════════════════════════════════════════════════════════════════════
   EXPERIENCE SECTION — layout for the homepage "Experience your journey"
   section (#template-gallery): the statement, the door (real template
   posters + browse CTA + industry ambience wall), and the anatomy band.

   DIVISION OF LABOR: this file owns LAYOUT ONLY. All orbit/feed motion
   (keyframes, delay ladders, reduced-motion snapshots) stays in
   experience_card.css — the motion library — whose keyframes are
   mechanically derived. Do not duplicate or hand-edit them here.

   CSP: strict public CSP (style-src 'self'); no inline styles anywhere.
   Motion budget: transform / opacity / filter only.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Section shell + full-bleed aurora ─────────────────────────────────── */
/* The section itself is styled by index_v6.css (.template-gallery-section:
   7rem padding + 100vw hairline). We add a full-bleed ambient light pool
   BEHIND the content — the section must read as a lit stage, not a card. */
#template-gallery { position: relative; overflow: hidden; }
.exps-bg {
    position: absolute; inset: 0; z-index: 0; pointer-events: none;
}
.exps-aurora,
.exps-aurora::before,
.exps-aurora::after {
    content: ''; position: absolute; border-radius: 50%;
    filter: blur(56px); will-change: transform, opacity;
}
.exps-aurora {
    top: 4%; left: 10%; width: 58%; height: 70%;
    background: radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--blurple) 34%, transparent), transparent 66%);
    opacity: .34; animation: exp-aurora-a 26s ease-in-out infinite;
}
.exps-aurora::before {
    top: 18%; right: 0; left: auto; width: 46%; height: 66%;
    background: radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--sector-cyan, #0fa8c0) 30%, transparent), transparent 66%);
    opacity: .22; animation: exp-aurora-b 32s ease-in-out infinite;
}
.exps-aurora::after {
    bottom: -6%; top: auto; left: 30%; width: 50%; height: 55%;
    background: radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--sector-magenta, #9d4edd) 24%, transparent), transparent 64%);
    opacity: .16; animation: exp-aurora-a 30s ease-in-out infinite reverse;
}
#template-gallery .tg-inner { position: relative; z-index: 1; }

/* ── LAYER 1 · the statement ───────────────────────────────────────────── */
.exps-statement {
    text-align: center;
    max-width: 760px;
    margin: 0 auto clamp(2.2rem, 4vw, 3.4rem);
}
.exps-kicker {
    font-size: .7rem; font-weight: 900; letter-spacing: .4em;
    text-transform: uppercase;
    color: var(--blurple);
    margin: 0 0 1rem;
}
/* The headline rides .tg-headline unmodified (index_v6.css): ink color,
   flagship clamp, brand font. The gradient text clip belongs to the DARK
   FPAI section only; on a light section the house tier is ink with the
   kicker carrying the accent (see .meets-kicker / .meets-title). */
.exps-sub {
    font-size: 1.05rem; line-height: 1.55;
    color: color-mix(in srgb, var(--inv-bg-color) 68%, transparent);
    max-width: 62ch; margin: 1.1rem auto 0;
}

/* ── The section's hover language ──────────────────────────────────────── */
/* ONE vocabulary for every interactive thing in here — posters, the CTA, the
   sector filter and its options, result rows, the anatomy band.
   (Owner, 2026-08-04: "the hover style of the panel and the cards does not
   feel premium." It didn't, and every offender was the same two reflexes.)

   The two banned reflexes, and why:
   • NEVER draw a coloured outline on hover. It reads as a focus ring, so the
     pointer and the keyboard stop being distinguishable, and on a card that
     already carries a sector accent it stamps blurple over the card's own
     colour — hovering the Cybersecurity poster drew a blue box beside its
     blue rail, hovering the amber one drew a blue box beside amber.
   • NEVER dim on hover. `opacity: .92` on the gradient CTA is the cheapest
     move in the book and it reads as disabled, not as pressed.

   What replaces them, in this order every time:
   1. the SURFACE warms — a wash of the element's own accent, not a border;
   2. the object LIFTS on a two-layer shadow (tight contact keeps the edge
      crisp; wide diffuse does the elevation — one blurry blob reads as a
      filter, two layers read as an object above a surface);
   3. the element's OWN accent asserts — the rail it already carries goes
      from resting to full. Colour comes from the content, never from us.

   Timing is the house spring, short. Anything over ~220ms on a pointer move
   feels like lag, and linear easing feels mechanical. */
#template-gallery {
    --exp-hov-ms: 200ms;
    --exp-hov-ease: var(--ease-spring, cubic-bezier(0.16, 1, 0.3, 1));
    --exp-hov-lift:
        0 1px 2px -1px color-mix(in srgb, var(--inv-bg-color) 14%, transparent),
        0 14px 28px -18px color-mix(in srgb, var(--inv-bg-color) 45%, transparent);
}
/* Sector → accent, pure CSS (mirrors SECTOR_COLORS in v6_gallery.js). Scoped
   to the section rather than to .exp-poster so that EVERY sector-tagged thing
   in here — poster, result row, filter option — reads the same colour from
   the same map. Adding a surface no longer means copying six lines. */
#template-gallery [data-sector="Technology"] { --exp-accent: var(--sector-blue); }
#template-gallery [data-sector="Financial Services"] { --exp-accent: var(--sector-cyan); }
#template-gallery [data-sector="Health, Education & Government"] { --exp-accent: var(--sector-green); }
#template-gallery [data-sector="Industrial & Manufacturing"] { --exp-accent: var(--sector-amber); }
#template-gallery [data-sector="Consumer"] { --exp-accent: var(--sector-coral); }
#template-gallery [data-sector="Professional Services"] { --exp-accent: var(--sector-magenta); }

/* ── LAYER 2 · the door ────────────────────────────────────────────────── */
/* The glass frame reuses the proven console recipe (theme-aware frosted
   glass + luminous top edge). Static: no pointer tilt, no 3D — the owner
   killed the motion here; hover is border/shadow only. */
.exps-door-frame {
    --exp-ink: var(--inv-bg-color);
    --exp-text: color-mix(in srgb, var(--inv-bg-color) 68%, transparent);
    --exp-muted: color-mix(in srgb, var(--inv-bg-color) 50%, transparent);
    position: relative; z-index: 1; isolation: isolate;
    display: grid; grid-template-columns: minmax(0, 1fr) 300px;
    gap: clamp(1.2rem, 2.5vw, 2rem);
    padding: clamp(1.4rem, 2.6vw, 2.2rem);
    border-radius: 22px; overflow: hidden;
    transition:
        transform 420ms var(--surface-ease, ease),
        box-shadow 420ms var(--surface-ease, ease),
        border-color 420ms var(--surface-ease, ease);
    background:
        radial-gradient(115% 130% at 50% -15%, color-mix(in srgb, var(--blurple) 10%, transparent) 0%, transparent 60%),
        var(--surface-glass-bg);
    -webkit-backdrop-filter: blur(14px) saturate(1.1);
    backdrop-filter: blur(14px) saturate(1.1);
    border: 1px solid color-mix(in srgb, var(--inv-bg-color) 11%, transparent);
    /* THE PARENT PANEL'S ELEVATION.
       This carried `0 24px 48px -28px` — a −28px spread under a 48px blur,
       which keeps almost the entire shadow INSIDE the box. A 1200px sheet was
       sitting on the page with nothing underneath it, and the Browse CTA
       *inside* it cast a visibly stronger shadow than the panel containing it.
       Elevation inverted: the biggest surface on the page read as the flattest.

       Same ramp discipline as the sector panel, scaled to the object: keep the
       house glass token (this frame must stay in the same family as every
       other glass surface), then ramp underneath it — blur doubling, opacity
       halving, spread pinned at 0 so every layer actually clears the edge. A
       sheet this wide grounds on a low broad pool, and that pool carries the
       stage's own indigo; the aurora behind this panel is lit, so neutral-grey
       ink under it reads as dirt rather than as shadow. */
    box-shadow:
        var(--surface-glass-shadow),
        0 4px 8px color-mix(in srgb, var(--inv-bg-color) 3%, transparent),
        0 12px 24px color-mix(in srgb, var(--inv-bg-color) 4%, transparent),
        0 28px 48px color-mix(in srgb, var(--inv-bg-color) 5%, transparent),
        0 48px 88px -20px color-mix(in srgb, var(--indigo, #4f46e5) 15%, transparent),
        inset 0 1px 0 color-mix(in srgb, #fff 14%, transparent);
    color: var(--exp-text);
}
/* THE PANEL'S HOVER: it rises. That is the whole effect.
   Owner call, 2026-08-04: motion, not a colour change. So nothing here tints
   — no wash, no brighter bezel, no blurple border. The panel simply comes up
   2px, and the pool underneath opens the way a real shadow does when its
   object moves away from the surface.

   2px on a 1200px sheet is 0.17% of its width. You do not see it travel; you
   see the whole plane settle a step closer, which is exactly the register a
   surface this size can afford — the same 2px on a 360px card would read as a
   bounce. The shadow doing the work is what makes it legible at all.

   Slow on purpose (420ms). Big objects respond slowly, and that IS the mass
   cue. A 1200px panel that snaps in 150ms feels weightless.

   The border firms a hair, neutrally. That is the edge catching more light at
   the new height, not a colour statement — the rule this replaced tinted the
   entire 1200px border blurple, the outline-on-hover reflex at the largest
   scale available on the page. */
.exps-door-frame:hover {
    transform: translateY(-2px);
    border-color: color-mix(in srgb, var(--inv-bg-color) 14%, transparent);
    box-shadow:
        var(--surface-glass-shadow),
        0 4px 8px color-mix(in srgb, var(--inv-bg-color) 4%, transparent),
        0 16px 30px color-mix(in srgb, var(--inv-bg-color) 5%, transparent),
        0 38px 66px color-mix(in srgb, var(--inv-bg-color) 7%, transparent),
        0 68px 120px -20px color-mix(in srgb, var(--indigo, #4f46e5) 22%, transparent),
        inset 0 1px 0 color-mix(in srgb, #fff 15%, transparent);
}
/* Luminous top-edge signature (the footer-v2 lit bezel). */
.exps-door-frame::before {
    content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px; z-index: 5;
    pointer-events: none;
    background: linear-gradient(90deg,
        rgba(120, 115, 245, 0) 0%,
        rgba(120, 115, 245, 0.55) 24%,
        rgba(96, 165, 250, 0.6) 52%,
        rgba(212, 144, 255, 0.5) 78%,
        rgba(120, 115, 245, 0) 100%);
    box-shadow: 0 0 14px rgba(120, 115, 245, 0.35);
}
.exps-door-main { display: flex; flex-direction: column; min-width: 0; }

/* Poster grid — flat; the reveal system's fade-up is the only entrance. */
.exps-posters {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}
/* One poster = one REAL journey, in the house tg-card anatomy scaled up:
   accent rail / industry icon / body. Whole card is the link. */
a.exp-poster {
    text-decoration: none;
    --exp-accent: var(--blurple);
    position: relative; display: flex; align-items: flex-start; gap: .8rem;
    padding: 1.1rem 1.1rem 1.05rem 1.35rem;
    border-radius: 11px; overflow: hidden;
    /* EXACTLY the feed-card surface (.exp-fcard's recipe): the posters and
       the carousel items beside them are the same object at two sizes, so
       they share one skin — top sheen over main-bg, 15% hairline, the same
       tight shadow. (Owner: anything richer read as "featured cards".) */
    background: linear-gradient(180deg, color-mix(in srgb, var(--inv-bg-color) 5%, transparent), transparent), var(--main-bg-color);
    border: 1px solid color-mix(in srgb, var(--inv-bg-color) 15%, transparent);
    box-shadow: 0 5px 12px -8px rgba(0,0,0,.5), inset 0 1px 0 color-mix(in srgb, #fff 7%, transparent);
    transition:
        transform var(--exp-hov-ms) var(--exp-hov-ease),
        box-shadow var(--exp-hov-ms) var(--exp-hov-ease),
        border-color var(--exp-hov-ms) var(--exp-hov-ease),
        background var(--exp-hov-ms) var(--exp-hov-ease);
}
/* Surface + lift + the card's own rail. The hairline firms NEUTRALLY (22%
   ink) — it is the elevation reading, not a colour statement; the sector
   colour arrives as the wash and the rail. */
/* #template-gallery-SCOPED, and it has to be. The posters carry `.reveal`,
   and the section's grander entrance rule `#template-gallery .reveal.is-visible`
   (1,2,0) sets `transform: translateY(0) scale(1)` — which outranks a plain
   `a.exp-poster:hover` (0,2,1) FOREVER, not just during the entrance. The lift
   below had never once rendered; the border was the only hover feedback that
   ever landed, which is most of why these cards read as flat pictures of
   cards. Verified against the live cascade, not inferred: CDP reported
   `#template-gallery .reveal.is-visible` as the winning rule for `transform`
   on a hovered poster. The ID here buys (1,2,1) and takes it back. */
#template-gallery a.exp-poster:hover,
#template-gallery a.exp-poster:focus-visible {
    text-decoration: none;
    transform: translateY(-2px);
    border-color: color-mix(in srgb, var(--inv-bg-color) 22%, transparent);
    background:
        linear-gradient(180deg, color-mix(in srgb, var(--exp-accent) 8%, transparent), transparent 62%),
        var(--main-bg-color);
    box-shadow:
        0 1px 2px -1px color-mix(in srgb, var(--inv-bg-color) 14%, transparent),
        0 16px 30px -20px color-mix(in srgb, var(--exp-accent) 60%, transparent),
        inset 0 1px 0 color-mix(in srgb, #fff 10%, transparent);
}
.exp-poster:focus-visible { outline: 2px solid var(--exp-accent); outline-offset: -2px; }
.exp-poster-accent {
    position: absolute; top: 0; bottom: 0; left: 0; width: 3px;
    background: var(--exp-accent); opacity: .35;   /* matches .exp-fcard-accent */
    transition: opacity var(--exp-hov-ms) var(--exp-hov-ease),
                width var(--exp-hov-ms) var(--exp-hov-ease);
}
/* The rail is the accent statement hover used to make with a border. It is
   already the card's colour and already in the right place. */
a.exp-poster:hover .exp-poster-accent,
a.exp-poster:focus-visible .exp-poster-accent { opacity: 1; width: 4px; }
/* The tg-card icon tile, one size up for the poster scale. */
/* Sector colour, same as the accent rail beside it — the injected SVGs stroke
   with currentColor, so this is what tints them. */
.exp-poster-icon { width: 34px; height: 34px; flex-shrink: 0; margin-top: .1rem; color: var(--exp-accent); }
.exp-poster-icon svg { width: 100%; height: 100%; }
.exp-poster-body { display: flex; flex-direction: column; gap: .18rem; min-width: 0; }
.exp-poster-industry {
    font-size: .62rem; font-weight: 600; letter-spacing: .12em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--inv-bg-color) 48%, transparent);
}
.exp-poster-name {
    font-family: var(--brand-font, 'Space Grotesk', sans-serif);
    font-size: 1.08rem; font-weight: 650; letter-spacing: -.02em; line-height: 1.18;
    color: var(--exp-ink, var(--inv-bg-color));
}
.exp-poster-sub {
    font-size: .72rem; line-height: 1.4;
    color: color-mix(in srgb, var(--inv-bg-color) 48%, transparent);
}
/* The sector map above sets --exp-accent on [data-sector], and it is the ONLY
   copy: a poster-scoped duplicate of the same six colours used to sit here,
   and two maps for one fact is exactly how they drift. A guard test enforces
   the single map, and it reads this file as text, so do not spell the retired
   selector out here either. */

/* Door foot: the browse-all CTA + the read-only fine print. */
.exps-door-foot {
    display: flex; align-items: center; gap: 1.1rem; flex-wrap: wrap;
    margin-top: 1.15rem;
}
/* The gradient pill CTA (owner call: keep the crown-jewel fill here).
   BOTH states pin color:#fff — the base landing_base a:not(.button):hover
   turns anchors grey-blue (#95A4B4), and with no hover color of our own it
   was winning and flipping the label blue mid-hover. */
a.exps-browse-cta {
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .75rem 1.5rem; border-radius: 12px;
    font-family: var(--font-main, 'Satoshi', sans-serif);
    font-size: .95rem; font-weight: 650; letter-spacing: -.01em;
    text-decoration: none; white-space: nowrap;
    color: #fff;
    background: linear-gradient(135deg, var(--purple), var(--blurple));
    box-shadow: 0 10px 24px -12px color-mix(in srgb, var(--blurple) 55%, transparent);
    transition:
        transform var(--exp-hov-ms) var(--exp-hov-ease),
        box-shadow var(--exp-hov-ms) var(--exp-hov-ease),
        filter var(--exp-hov-ms) ease;
}
/* Brightens and lifts; it does NOT dim. The old `opacity: .92` faded the
   section's only crown-jewel fill on approach, which reads as disabled — the
   one hover in here that has to feel like the primary action was the one that
   felt switched off. The glow deepens instead, and the arrow leads. */
a.exps-browse-cta:hover, a.exps-browse-cta:focus-visible {
    color: #fff;
    text-decoration: none;
    transform: translateY(-2px);
    filter: saturate(1.08) brightness(1.05);
    box-shadow:
        0 2px 4px -2px color-mix(in srgb, var(--blurple) 45%, transparent),
        0 20px 36px -16px color-mix(in srgb, var(--blurple) 65%, transparent);
}
/* Press: the lift collapses. Without this the button never acknowledges the
   click, it just navigates. */
a.exps-browse-cta:active { transform: translateY(0); }
a.exps-browse-cta svg {
    width: 16px; height: 16px; flex-shrink: 0;
    transition: transform var(--exp-hov-ms) var(--exp-hov-ease);
}
a.exps-browse-cta:hover svg,
a.exps-browse-cta:focus-visible svg { transform: translateX(3px); }

/* Ambience wall: the industry feed rides its motion-library classes; only
   the frame geometry changes (fill the column instead of the fixed card
   height). The wall NEVER pauses on poster hover (owner decision
   2026-08-03: the ambience keeps breathing while you read a card).

   THE WALL IS ONE COLUMN — search field, sector filter, then the card stack
   (ambience feed, or live results while searching). Everything in it hangs
   off two vertical rails (the icon rail and the label rail) and shares one
   corner and one control height. Those had drifted apart: 46px vs 43.4px
   tall, an 8px corner over the cards' 11px, and four different left insets
   (search icon 12 / "All Sectors" 16 / feed-card icon 20 / result row 18).
   No single value was wrong enough to name on sight, but together they read
   as a broken column. Derive from the vars below, never retype. Guarded by
   testing/e2e/specs/_guardrails/index_wall_column_rails.spec.ts. */
.exps-door-wall {
    position: relative; min-width: 0; min-height: 340px;
    display: flex; flex-direction: column; gap: .55rem;
    --exps-ctl-h: 2.2rem;       /* both controls, border-box */
    --exps-ctl-radius: 11px;    /* = .exp-fcard / .exp-poster corner */
    --exps-ctl-rail: 20px;      /* = .exp-fcard's icon left edge */
    --exps-ctl-icon: 13px;
    --exps-ctl-gap: .4rem;      /* icon -> label */
    /* Label rail, as a control's padding: -1px because that padding sits
       inside a 1px border, while the search icon is absolutely positioned
       against the border-less label. */
    --exps-ctl-pad-l: calc(var(--exps-ctl-rail) + var(--exps-ctl-icon) + var(--exps-ctl-gap) - 1px);
}
/* The wall's search + sector bar. Compact: the wall is a 300px column. */
.exps-wall-bar { display: flex; flex-direction: column; gap: .55rem; }
.exps-wall-search { position: relative; display: flex; align-items: center; }
.exps-wall-search-icon {
    position: absolute; left: var(--exps-ctl-rail);
    /* Explicit centring: an absolutely-positioned child is out of flow, so it
       must not depend on the parent's align-items for its vertical position. */
    top: 50%; transform: translateY(-50%);
    width: var(--exps-ctl-icon); height: var(--exps-ctl-icon);
    /* The icon sits at the placeholder's LEFT end, so it takes the
       gradient's START hue (--purple); --blurple here read as a mismatched
       endpoint next to the purple-opening text. */
    color: var(--purple);
    pointer-events: none;
}
/* Primary-CTA weight (owner call, restrained): a gradient hairline border
   (double-background technique — border-image can't round corners) and a
   gradient-clipped placeholder, with a solid-blurple placeholder fallback
   where background-clip:text doesn't reach ::placeholder. Typed text stays
   ink; only the invitation is dressed. */
.exps-wall-search input {
    width: 100%; box-sizing: border-box;
    height: var(--exps-ctl-h);
    padding: 0 .6rem 0 var(--exps-ctl-pad-l);
    border-radius: var(--exps-ctl-radius);
    border: 1px solid transparent;
    /* First layer must be an IMAGE (a bare color is only legal in the last
       layer — as a layer it invalidates the whole declaration; that bug
       shipped once as "no border at all"). */
    /* The fcard surface under the gradient border: sheen layer + solid
       main-bg (both padding-box, masking the border gradient), plus the
       fcard's tight shadow — so the field sits in the same family as the
       cards around it instead of reading flat/pasted. */
    background:
        linear-gradient(180deg, color-mix(in srgb, var(--inv-bg-color) 5%, transparent), transparent) padding-box,
        linear-gradient(var(--main-bg-color), var(--main-bg-color)) padding-box,
        /* the frame's luminous-edge run (purple → blue → pink) */
        linear-gradient(135deg, var(--purple), var(--blurple) 55%, var(--pink)) border-box;
    box-shadow: 0 5px 12px -8px rgba(0,0,0,.5), inset 0 1px 0 color-mix(in srgb, #fff 7%, transparent);
    color: color-mix(in srgb, var(--inv-bg-color) 82%, transparent);
    font-family: var(--font-main, 'Satoshi', sans-serif);
    /* .82rem = the .tg-drop__trigger's own size: the two stacked labels are
       one size, and only WEIGHT separates primary from secondary. */
    font-size: .82rem; font-weight: 500;
    transition: box-shadow var(--exp-hov-ms) var(--exp-hov-ease);
}
/* Hover on a text field is an invitation, not a state change: the resting
   shadow warms toward the field's own gradient. No border move — the border
   IS the gradient and touching it makes the field flicker. */
.exps-wall-search input:hover {
    box-shadow:
        0 6px 16px -10px color-mix(in srgb, var(--blurple) 55%, transparent),
        inset 0 1px 0 color-mix(in srgb, #fff 9%, transparent);
}
.exps-wall-search input:focus {
    outline: none;
    box-shadow:
        0 6px 16px -10px color-mix(in srgb, var(--blurple) 55%, transparent),
        inset 0 1px 0 color-mix(in srgb, #fff 9%, transparent),
        0 0 0 3px color-mix(in srgb, var(--blurple) 16%, transparent);
}
.exps-wall-search input::placeholder {
    color: var(--blurple);
    font-weight: 600;
    opacity: 1;
}
@supports (-webkit-background-clip: text) {
    .exps-wall-search input::placeholder {
        background: linear-gradient(135deg, var(--purple), var(--blurple) 55%, var(--pink));
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;
        -webkit-text-fill-color: transparent;
    }
}
/* The sector dropdown rides index_v6's .tg-drop primitives; width goes
   full-column, and the trigger matches the search field's surface (solid
   main-bg + a quiet border — deliberately NOT the primary gradient; the
   search is the primary here). */
.exps-wall-drop { width: 100%; }
/* Twin the trigger to the search field: same height, same corner, same two
   left rails. The trigger carries its own leading glyph for exactly that
   reason — without it the control has no icon rail, so its label sat 21px
   left of the placeholder and the pair read as misaligned rather than
   stacked. index_v6's own padding/radius/font are overridden here only. */
.exps-wall-drop .tg-drop__trigger {
    height: var(--exps-ctl-h);
    padding: 0 .6rem 0 calc(var(--exps-ctl-rail) - 1px);
    gap: var(--exps-ctl-gap);
    border-radius: var(--exps-ctl-radius);
    font-size: .82rem;
    transition:
        background var(--exp-hov-ms) var(--exp-hov-ease),
        border-color var(--exp-hov-ms) var(--exp-hov-ease),
        box-shadow var(--exp-hov-ms) var(--exp-hov-ease),
        color var(--exp-hov-ms) var(--exp-hov-ease);
}
/* A control does NOT lift like a card — it is anchored in a bar. It gets the
   surface half of the language only: fill warms, hairline firms neutrally, a
   contact shadow appears. */
.exps-wall-drop .tg-drop__trigger:hover {
    border-color: color-mix(in srgb, var(--inv-bg-color) 20%, transparent);
    background: color-mix(in srgb, var(--inv-bg-color) 6%, transparent);
    box-shadow: 0 1px 2px -1px color-mix(in srgb, var(--inv-bg-color) 16%, transparent);
}
.exps-wall-drop-icon {
    flex-shrink: 0;
    width: var(--exps-ctl-icon); height: var(--exps-ctl-icon);
    /* Muted, unlike the search's purple magnifier: the search is primary. */
    color: color-mix(in srgb, var(--inv-bg-color) 35%, transparent);
    transition: color 160ms ease;
}
.exps-wall-drop .tg-drop__trigger:hover .exps-wall-drop-icon,
.exps-wall-drop.is-open .exps-wall-drop-icon {
    color: color-mix(in srgb, var(--inv-bg-color) 62%, transparent);
}
/* The panel joins the column's corner family, and swaps index_v6's single
   0 8px 30px blob for the two-layer elevation — a lone wide blur under a
   floating surface reads as a drop-shadow filter someone applied; contact +
   diffuse reads as a sheet lifted off the page. */
.exps-wall-drop .tg-drop__panel {
    /* NO max-height override. This carried `max-height: 240px` against 298px
       of content, so the seventh sector was cut clean off — the exact defect
       index_v6's own base rule documents ("a flat 260px cut the last sector in
       half with no scroll cue, which reads as 'the list is broken'"). Inherit
       the base min(56vh, 302px); the option padding below is sized so all
       seven show whole inside it. */
    border-radius: var(--exps-ctl-radius);
    border-color: color-mix(in srgb, var(--inv-bg-color) 10%, transparent);
    /* AN ELEVATION RAMP, NOT A SHADOW.
       What read as cheap was geometry, not colour. The old pair leaned on
       -22px of spread under a 44px blur, which pulls the shadow 22px INSIDE
       every edge — so almost nothing escaped the panel, the bottom edge butted
       straight into the card behind it, and the panel read as a white
       rectangle pasted on rather than a sheet held above.

       A real shadow is one light source sampled at several distances: blur
       roughly doubles each step while opacity roughly halves, and spread stays
       at 0 so every layer actually reaches past the edge. Four steps is the
       minimum that reads as falloff instead of as a blob.

       The tail carries the section's own violet rather than neutral ink. A
       grey shadow under a warm-white panel on a lavender-lit stage looks like
       soot; light in this section has a colour, so its shadow does too. */
    box-shadow:
        0 2px 4px color-mix(in srgb, var(--inv-bg-color) 4%, transparent),
        0 6px 12px color-mix(in srgb, var(--inv-bg-color) 5%, transparent),
        0 14px 28px color-mix(in srgb, var(--inv-bg-color) 6%, transparent),
        0 28px 56px -10px color-mix(in srgb, var(--purple) 16%, transparent);
}
/* THE OPTION ROW — the one the owner named. index_v6's default is a flat
   7%-ink block behind the label, which is the native-<select> look: a grey
   bar, no colour, no relationship to what the row means.

   Instead the row IS a miniature of the cards below it. Its label sits on the
   column's label rail, its marker sits on the column's ICON rail (the slot a
   glyph occupies on both controls above), and both the marker and the wash
   are the SECTOR'S OWN colour — hovering "Financial Services" shows the same
   cyan its cards carry. The marker also fills a 20px slot that was otherwise
   dead space between the panel edge and the label. */
.exps-wall-drop .tg-drop__option {
    position: relative;
    padding-left: calc(var(--exps-ctl-rail) + var(--exps-ctl-icon) + var(--exps-ctl-gap) - 5px);
    /* .4rem, not more: seven options plus the panel's padding must clear the
       base rule's 302px cap or the list cuts a row again. At .42rem it did. */
    padding-top: .4rem; padding-bottom: .4rem;
    border-radius: 8px;
    transition:
        background var(--exp-hov-ms) var(--exp-hov-ease),
        color var(--exp-hov-ms) var(--exp-hov-ease);
}
/* -5px on left: the panel's own 1px border + 4px padding already inset the
   option box before its padding starts, so the icon rail is 5px nearer. */
.exps-wall-drop .tg-drop__option::before {
    content: ''; position: absolute;
    left: calc(var(--exps-ctl-rail) - 5px); top: 50%;
    width: 5px; height: 5px; margin-top: -2.5px;
    border-radius: 50%;
    background: var(--exp-accent, var(--blurple));
    opacity: 0; transform: scale(.4);
    transition: opacity var(--exp-hov-ms) ease,
                transform var(--exp-hov-ms) var(--exp-hov-ease);
}
.exps-wall-drop .tg-drop__option:hover,
.exps-wall-drop .tg-drop__option:focus-visible {
    outline: none;
    color: var(--inv-bg-color);
    background: color-mix(in srgb, var(--exp-accent, var(--blurple)) 9%, transparent);
}
.exps-wall-drop .tg-drop__option:hover::before,
.exps-wall-drop .tg-drop__option:focus-visible::before {
    opacity: .55; transform: scale(1);
}
/* Selected: the marker stays lit and the label takes the sector's colour, so
   the panel says which sector is active in the same colour the grid will. */
.exps-wall-drop .tg-drop__option.is-active {
    color: var(--exp-accent, var(--blurple));
    font-weight: 600;
}
.exps-wall-drop .tg-drop__option.is-active::before { opacity: 1; transform: scale(1); }

/* Feed / results area: the bar sits in flow; this wrapper owns the rest of
   the column and the media absolute-fills IT (a flow height of 100% resolved
   to auto and once stretched the frame to the feed's ~2000px track). */
.exps-wall-feed { position: relative; flex: 1; min-height: 0; }
.exps-wall-feed .exp-c-media--feed {
    position: absolute; inset: 0;
    height: auto; margin: 0;
}
/* Searching: the marquee yields to live results. */
.exps-door-wall.is-searching .exp-c-media--feed { display: none; }
.exps-wall-results[hidden] { display: none; }
.exps-wall-results {
    position: absolute; inset: 0;
    overflow-y: auto; overscroll-behavior: contain;
    display: flex; flex-direction: column; gap: .5rem;
    padding-right: .1rem;
}
/* Results take the feed cards' exact slot, so they take the feed cards' rail
   and corner: content starts on the 20px icon rail (a hit carries no icon, so
   its name IS its leading element) and the box is the same 11px card. */
a.exps-wall-hit {
    /* overflow:hidden clips the ::before rail to the rounded corner — and it
       ALSO zeroes a flex item's automatic minimum size, so in this scrolling
       flex column every row instantly shrank and clipped its own text.
       flex-shrink:0 is not optional here; the two must ship together. */
    position: relative; overflow: hidden; flex-shrink: 0;
    display: flex; flex-direction: column; gap: .1rem;
    padding: .55rem .75rem .6rem calc(var(--exps-ctl-rail) - 1px);
    border-radius: var(--exps-ctl-radius);
    text-decoration: none;
    border: 1px solid color-mix(in srgb, var(--inv-bg-color) 8%, transparent);
    background: color-mix(in srgb, var(--inv-bg-color) 2%, transparent);
    transition:
        transform var(--exp-hov-ms) var(--exp-hov-ease),
        border-color var(--exp-hov-ms) var(--exp-hov-ease),
        box-shadow var(--exp-hov-ms) var(--exp-hov-ease),
        background var(--exp-hov-ms) var(--exp-hov-ease);
}
/* The result rows were the only cards in this column with no accent rail —
   they replace the feed cards in the same slot, so they now carry the same
   3px sector rail at the same resting .35, and hover brings it to full. */
a.exps-wall-hit::before {
    content: ''; position: absolute; top: 0; bottom: 0; left: 0; width: 3px;
    background: var(--exp-accent, var(--blurple)); opacity: .35;
    transition: opacity var(--exp-hov-ms) var(--exp-hov-ease),
                width var(--exp-hov-ms) var(--exp-hov-ease);
}
/* Was: a 45%-blurple border + translateX(2px) — a coloured outline that read
   as a focus ring and slid the row sideways under the cursor. Now: surface,
   lift, own rail. */
a.exps-wall-hit:hover, a.exps-wall-hit:focus-visible {
    text-decoration: none;
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--inv-bg-color) 15%, transparent);
    background:
        linear-gradient(180deg, color-mix(in srgb, var(--exp-accent, var(--blurple)) 7%, transparent), transparent 70%),
        color-mix(in srgb, var(--inv-bg-color) 3%, transparent);
    box-shadow:
        0 1px 2px -1px color-mix(in srgb, var(--inv-bg-color) 14%, transparent),
        0 12px 22px -16px color-mix(in srgb, var(--exp-accent, var(--blurple)) 60%, transparent);
}
a.exps-wall-hit:hover::before,
a.exps-wall-hit:focus-visible::before { opacity: 1; width: 4px; }
.exps-wall-hit-name {
    font-size: .8rem; font-weight: 600; line-height: 1.25;
    color: color-mix(in srgb, var(--inv-bg-color) 85%, transparent);
    transition: color var(--exp-hov-ms) var(--exp-hov-ease);
}
a.exps-wall-hit:hover .exps-wall-hit-name,
a.exps-wall-hit:focus-visible .exps-wall-hit-name { color: var(--inv-bg-color); }
.exps-wall-hit-ind {
    font-size: .66rem; letter-spacing: .04em;
    color: color-mix(in srgb, var(--inv-bg-color) 48%, transparent);
}
/* Sits under the hits, so it starts on the same rail they do (it has no
   border of its own, hence the raw rail rather than rail - 1px). */
a.exps-wall-more {
    display: inline-flex; align-items: center; gap: .35rem; flex-shrink: 0;
    margin-top: .1rem; padding: .35rem .2rem .35rem var(--exps-ctl-rail);
    font-size: .74rem; font-weight: 700; text-decoration: none;
    color: var(--blurple);
    transition: color var(--exp-hov-ms) var(--exp-hov-ease);
}
/* It had NO hover feedback at all — only a text-decoration reset, so the
   pointer changed and nothing else did. House text-CTA move: label warms,
   arrow leads (same as .exps-anatomy-go). */
a.exps-wall-more:hover, a.exps-wall-more:focus-visible {
    text-decoration: none;
    color: var(--purple);
}
a.exps-wall-more svg {
    width: 12px; height: 12px;
    transition: transform var(--exp-hov-ms) var(--exp-hov-ease);
}
a.exps-wall-more:hover svg,
a.exps-wall-more:focus-visible svg { transform: translateX(3px); }
/* One readable column in the 300px wall — two ellipsis-truncated columns
   read as debris, one full-width column reads as a live index. */
.exps-door-wall .exp-feed { grid-template-columns: 1fr; padding: 0; }
.exps-door-wall .exp-feed-col--b { display: none; }

/* ── LAYER 3 · the anatomy band ────────────────────────────────────────── */
/* Deliberately quiet: no glass box, a hairline and a faint wash. The whole
   band is one link into the modal's stage walk. */
a.exps-anatomy {
    text-decoration: none;
    display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
    align-items: center; gap: clamp(1.2rem, 3vw, 2.6rem);
    margin-top: clamp(2rem, 3.5vw, 3rem);
    padding: clamp(1.2rem, 2.5vw, 1.8rem) clamp(.6rem, 1.5vw, 1.4rem) .6rem;
    border-top: 1px solid color-mix(in srgb, var(--inv-bg-color) 8%, transparent);
    color: color-mix(in srgb, var(--inv-bg-color) 68%, transparent);
}
/* Hover pins BOTH states' inherited color: with no declaration here,
   landing_base's global a:not(.button):hover (#95A4B4 grey-blue) won and
   flipped the kicker + body text to a washed blue (owner-reported). The
   hover FEEDBACK is the house text-CTA move: label warms, arrow glides. */
a.exps-anatomy:hover {
    text-decoration: none;
    color: color-mix(in srgb, var(--inv-bg-color) 68%, transparent);
}
.exps-anatomy-orbit { min-width: 0; }
.exps-anatomy-copy { display: flex; flex-direction: column; gap: .45rem; min-width: 0; }
.exps-anatomy-kicker {
    font-size: .62rem; font-weight: 700; letter-spacing: .18em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--inv-bg-color) 45%, transparent);
}
.exps-anatomy-title {
    font-family: var(--brand-font, 'Space Grotesk', sans-serif);
    font-size: 1.3rem; font-weight: 600; letter-spacing: -.02em; line-height: 1.2;
    color: var(--inv-bg-color); margin: 0;
}
.exps-anatomy-text { font-size: .9rem; line-height: 1.55; margin: 0; max-width: 46ch; }
.exps-anatomy-go {
    display: inline-flex; align-items: center; gap: .4rem;
    margin-top: .3rem;
    font-size: .82rem; font-weight: 700;
    color: var(--blurple);
    transition: color var(--exp-hov-ms) var(--exp-hov-ease);
}
.exps-anatomy-go svg {
    width: 14px; height: 14px;
    transition: transform var(--exp-hov-ms) var(--exp-hov-ease);
}
a.exps-anatomy:hover .exps-anatomy-go,
a.exps-anatomy:focus-visible .exps-anatomy-go { color: var(--purple); }
/* 3px, not 4px: every arrow in the section travels the same distance now
   (browse CTA, "all N matches", here). */
a.exps-anatomy:hover .exps-anatomy-go svg,
a.exps-anatomy:focus-visible .exps-anatomy-go svg { transform: translateX(3px); }

/* ── Tactile: the press beat ───────────────────────────────────────────── */
/* Hover says "you are near it". PRESS is what says "it is a thing." Nothing
   in this section gave under the pointer, so every surface felt like a picture
   of a control rather than a control.

   Two rules make it feel physical rather than animated:

   • TIMING IS ASYMMETRIC. Down in ~70ms, back up on the full 200ms spring. A
     press that eases down as slowly as it releases reads as a fade; real
     objects have no travel time going down, only coming back. This is the
     whole trick — the distances barely matter.
   • TRAVEL IS UNDER 1.5%. You are not meant to SEE this. You are meant to
     feel that the cursor landed on something. Motion you can watch on a
     marketing page is a distraction, and this section's whole argument is
     gravity over grandeur.

   Placed after every :hover rule above (same specificity, later wins) and
   before the responsive block, so the phone's own heavier press still wins. */
#template-gallery { --exp-press-ms: 70ms; }
/* ID-scoped for the same reason the hover lift is — see the note there. */
#template-gallery a.exp-poster:active {
    transform: translateY(-1px) scale(.995);
    transition-duration: var(--exp-press-ms);
}
a.exps-browse-cta:active {
    transform: translateY(0) scale(.985);
    transition-duration: var(--exp-press-ms);
}
a.exps-wall-hit:active {
    transform: translateY(0) scale(.994);
    transition-duration: var(--exp-press-ms);
}
.exps-wall-drop .tg-drop__trigger:active,
.exps-wall-drop .tg-drop__option:active {
    transform: scale(.988);
    transition-duration: var(--exp-press-ms);
}

/* The panel HINGES open from the control instead of fading in place: the
   origin is its top edge — the seam it shares with the trigger — so it unfolds
   downward out of the thing you just clicked. Opacity still resolves fast
   (130ms) while the transform rides the longer spring; that split is what
   stops it reading as a slide. visibility matches the transform's duration or
   the panel disappears mid-close. */
.exps-wall-drop .tg-drop__panel {
    transform-origin: 50% 0;
    transform: translateY(-6px) scale(.97);
    transition: opacity 130ms ease,
                transform 300ms var(--exp-hov-ease),
                visibility 0s linear 300ms;
}
.exps-wall-drop.is-open .tg-drop__panel {
    transform: translateY(0) scale(1);
    transition: opacity 130ms ease,
                transform 300ms var(--exp-hov-ease),
                visibility 0s linear 0s;
}
.exps-wall-drop .tg-drop__chevron {
    transition: transform 300ms var(--exp-hov-ease), opacity 200ms ease;
}

/* Depth by differential: the icon travels 1px less than the card it sits on,
   so the card reads as having thickness rather than as a flat image sliding.
   One pixel — the effect is felt, not seen. */
.exp-poster-icon { transition: transform var(--exp-hov-ms) var(--exp-hov-ease); }
a.exp-poster:hover .exp-poster-icon,
a.exp-poster:focus-visible .exp-poster-icon { transform: translateY(-1px); }

/* The field's own glyph acknowledges focus. :focus-within on the label, not
   :focus on the input — the icon is a PRECEDING sibling and CSS cannot look
   backwards. translateY(-50%) must be restated or the icon drops off centre. */
.exps-wall-search-icon {
    transition: transform var(--exp-hov-ms) var(--exp-hov-ease),
                color var(--exp-hov-ms) ease;
}
.exps-wall-search:focus-within .exps-wall-search-icon {
    transform: translateY(-50%) scale(1.1);
}

/* ── Responsive ────────────────────────────────────────────────────────── */
@media (max-width: 1024px) {
    .exps-door-frame { grid-template-columns: minmax(0, 1fr) 240px; }
}
@media (max-width: 900px) {
    /* The wall does not render on phones: the posters ARE the section. */
    .exps-door-wall { display: none; }
    .exps-door-frame { grid-template-columns: minmax(0, 1fr); }
    .exps-posters { grid-template-columns: minmax(0, 1fr); }
    .exps-door-foot { flex-direction: column; align-items: flex-start; gap: .7rem; }
    /* a.exps-anatomy, NOT .exps-anatomy: the base rule is element+class
       (0,1,1) and a media query adds no specificity — the plain-class form
       lost and the band stayed two-column on phones, crushing the copy into
       a 40% column ("executabl / e."). */
    a.exps-anatomy { grid-template-columns: minmax(0, 1fr); }
    /* Copy above the orbit on phones: the words carry, the motion garnishes. */
    .exps-anatomy-orbit { order: 2; }
    .exps-anatomy-copy { order: 1; }
    /* Phone orbit geometry (from the motion library's retired mobile block). */
    .exps-anatomy .exp-c-media--orbit { height: 156px; }
    .exps-anatomy .exp-orbit { --rx: clamp(88px, 40cqw, 124px); --ry: 54px; --orbit-shift: -26px; }
    /* ID-scoped: a plain .exp-poster:active loses to
       `#template-gallery .reveal.is-visible`, so the phone's tap feedback was
       dead too. Same specificity as the desktop press rule above and later in
       the file, so this is what phones get. */
    #template-gallery a.exp-poster:active { transform: scale(.978); }
}

/* ── SEO index ─────────────────────────────────────────────────────────── */
/* Every journey's landing link, rendered + crawlable, visually hidden via
   the clip recipe (the gx-seo-only precedent) — NEVER display:none, which
   Google discounts to zero. */
.exps-seo-index {
    position: absolute !important;
    width: 1px !important; height: 1px !important;
    overflow: hidden !important;
    clip: rect(0 0 0 0) !important; clip-path: inset(50%) !important;
    white-space: nowrap !important;
    margin: -1px !important; padding: 0 !important; border: 0 !important;
}

/* ── Reduced motion ────────────────────────────────────────────────────── */
/* The hover LANGUAGE survives — surface warms, accent asserts, colour still
   answers the pointer. Only the moving parts stop: no lift, no slide, no
   easing. Reduced motion is not reduced feedback. */
@media (prefers-reduced-motion: reduce) {
    .exps-aurora, .exps-aurora::before, .exps-aurora::after { animation: none; }
    #template-gallery { --exp-hov-ms: 1ms; }
    a.exp-poster:hover, a.exp-poster:focus-visible,
    a.exps-browse-cta:hover, a.exps-browse-cta:focus-visible,
    a.exps-wall-hit:hover, a.exps-wall-hit:focus-visible { transform: none; }
    a.exps-browse-cta:hover svg,
    a.exps-wall-more:hover svg,
    a.exps-anatomy:hover .exps-anatomy-go svg { transform: none; }
    .exps-wall-drop .tg-drop__option::before { transform: scale(1); }
    /* The press beat is motion, so it goes too — but the panel must still
       resolve to its open geometry, not stay stuck at scale(.97). */
    a.exp-poster:active, a.exps-browse-cta:active, a.exps-wall-hit:active,
    .exps-wall-drop .tg-drop__trigger:active,
    .exps-wall-drop .tg-drop__option:active { transform: none; }
    /* The frame's rise goes; its deeper pool stays, so the panel still
       answers the pointer here — reduced motion, not reduced feedback. */
    .exps-door-frame, .exps-door-frame:hover { transform: none; }
    a.exp-poster:hover .exp-poster-icon,
    a.exp-poster:focus-visible .exp-poster-icon { transform: none; }
    .exps-wall-search:focus-within .exps-wall-search-icon { transform: translateY(-50%); }
    .exps-wall-drop .tg-drop__panel { transition: none; }
    .exps-wall-drop.is-open .tg-drop__panel { transform: none; transition: none; }
}
/* Touch: there is no hover, and a sticky :hover left behind after a tap reads
   as a stuck selection. Everything above is gated on a real pointer. */
@media (hover: none) {
    a.exp-poster:hover, a.exps-browse-cta:hover, a.exps-wall-hit:hover,
    .exps-door-frame:hover {
        transform: none;
    }
}
