/**
 * v3 careerweb — detail panel.
 *
 * Two hero modes:
 *   1. No banner (default): flat panel with padding, 80px brand strip
 *      across the top.
 *   2. With banner (.detail-hero--has-banner): banner image fills the
 *      hero, dark gradient overlay for legibility, content sits in a
 *      frosted-glass card. Brand strip is suppressed because the banner
 *      already carries the brand cue.
 *
 * Glass card margin/width math is tuned so the card's left/right
 * edges align with the body's content padding (responsive overrides
 * adjust this at 1100/860 breakpoints — see responsive.css).
 */

.detail {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    position: relative;
    min-height: 400px;
    /* Grid items default to min-width: auto (= min-content), which lets
       wide inner content (apply-bar, banner) push the 1fr column past
       its track. The original styling masked that with overflow:hidden;
       now that the share chip needs to overhang, we drop the clip and
       use min-width: 0 instead to keep the column on its track. */
    min-width: 0;
}

/* Loading state — used both during a filter / sort refetch AND
   while the per-job apply form schema is in flight. Hides the
   underlying content (kept in place so the column height doesn't
   collapse) and paints a single shimmer wave over the panel. One
   loader for the entire transition.
   The back-bar is exempted — on mobile the detail panel is the
   only thing visible, and hiding the back affordance during the
   loading window strands the user with no way to return to the
   list. The wave's ::after pseudo-element sits behind it (z-index
   above the masked content, below the back-bar's own positioning
   context). */
/* Children fade rather than snap during the loading↔loaded swap.
   Was visibility:hidden, which switched abruptly the moment the
   .detail--form-loading class flipped. Opacity transition crossfades
   with the mask (also opacity-transitioned below) so the swap reads
   as a gentle reveal instead of a hard cut. */
.detail > *:not(.detail-back-bar) {
    transition: opacity 200ms ease;
}
.detail--form-loading > *:not(.detail-back-bar) {
    opacity: 0;
}

/* Suppress the legacy form's own spinner inside the v3 detail
   panel — careerwebJobApplyCustomForm_revamped.js toggles the
   .jobApplicationFormLoader element on every getForms() call, which
   stacks visibly on top of (or right next to) our v3 shimmer when a
   context switch fires. v3 owns the loading state via
   .detail--form-loading; the legacy spinner is duplicate UI here. */
.detail .jobApplicationFormLoader,
.detail .cwv3-form-loader {
    display: none !important;
}
/* Mask + shimmer live as pseudo-elements on the base .detail so the
   opacity transition has something to animate. Without the always-
   present rule the pseudos would pop in/out the moment the class is
   added/removed, defeating the fade. The animation keeps running on
   the shimmer pseudo even at opacity 0 — that's fine, it's invisible
   and the browser doesn't repaint hidden layers. */
.detail::before,
.detail::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    opacity: 0;
    pointer-events: none;
    transition: opacity 200ms ease;
}
.detail::before {
    background: var(--surface);
    z-index: 10;
}
.detail::after {
    background: linear-gradient(
        90deg,
        transparent 0%,
        rgba(14, 14, 14, 0.05) 50%,
        transparent 100%
    );
    background-size: 220% 100%;
    z-index: 11;
    /* Animation only runs while loading — leaving it on the always-
       present pseudo would burn paint cycles for an invisible layer. */
}
.detail--form-loading::before,
.detail--form-loading::after {
    opacity: 1;
}
.detail--form-loading::after {
    animation: cwv3-detail-shimmer 1.4s linear infinite;
}
@keyframes cwv3-detail-shimmer {
    0%   { background-position: 110% 0; }
    100% { background-position: -110% 0; }
}
[data-theme="dark"] .detail--form-loading::after {
    background: linear-gradient(
        90deg,
        transparent 0%,
        rgba(255, 255, 255, 0.05) 50%,
        transparent 100%
    );
    background-size: 220% 100%;
}

/* ─── Hero (header band of the detail) ─── */
.detail-hero {
    position: relative;
    border-bottom: 1px solid var(--border);
    overflow: hidden;
    border-top-left-radius: var(--radius-xl);
    border-top-right-radius: var(--radius-xl);
}
.detail-hero::before {
    content: '';
    position: absolute;
    top: 0; left: 0;
    height: 3px;
    width: 80px;
    background: var(--brand);
    z-index: 4;
}
.detail-hero-content {
    position: relative;
    z-index: 3;
    padding: 28px 32px 24px;
}

/* Banner image fills the hero behind the glass card */
.detail-hero-bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    display: block;
    z-index: 0;
}
/* Soft gradient overlay — pushes the top of the banner toward white so
   the action chips + dark ink read cleanly, fades to nearly-transparent
   mid-band so the tenant banner art still shines, finishes with a light
   dark veil at the bottom so the glass card has something to anchor
   against. Re-tuned per VP review 2026-05-28 — the previous all-dark
   gradient (0.18 → 0.32) felt too heavy for dark text. */
.detail-hero-overlay {
    position: absolute;
    inset: 0;
    z-index: 1;
    background: linear-gradient(
        to bottom,
        rgba(255, 255, 255, 0.35) 0%,
        rgba(255, 255, 255, 0.08) 55%,
        rgba(0, 0, 0, 0.18) 100%
    );
    pointer-events: none;
}

/* When the hero has a banner, swap to glass-card layout. The hero
   height scales with the detail panel width via a banner-style
   aspect ratio, but the min-height floor is sized to fit the glass
   card (title + subtitle + 4-cell highlight strip) at narrow
   viewports — without the floor, the hero collapsed shorter than
   the card and the bottom-anchored card pushed its top past the
   hero's clip box, hiding the title (VP review bug 2026-05-28).
   max-height was dropped so the hero can grow when the card needs
   more space rather than getting clipped. */
.detail-hero--has-banner {
    /* aspect-ratio drives banner height from container width above
       ~960px (16/5 of 960 = 300px). Below that, min-height takes over;
       clamp keeps the floor proportional to the viewport instead of
       pinning a flat 300px floor that wastes vertical space on narrow
       desktop sizes (~860-1000px) and feels short on >1400px. */
    aspect-ratio: 16 / 5;
    min-height: clamp(240px, 22vw, 320px);
    display: flex;
    align-items: flex-end;
}
.detail-hero--has-banner::before {
    display: none;  /* banner provides the brand cue, drop the strip */
}
.detail-hero--has-banner .detail-hero-content {
    /* Margin + padding are fluid so the glass card breathes with the
       detail column's actual width. Hard 22/32 values made the card
       feel cramped at ~900-1000px (tablet desktop) and sparsely
       padded at >1400px — clamp() narrows the difference. */
    margin: clamp(16px, 1.8vw, 24px) clamp(20px, 2.2vw, 32px);
    padding: clamp(16px, 1.6vw, 22px) clamp(18px, 1.8vw, 26px);
    /* Tint + text-colour both flow from CSS vars that detail.js sets
       from the sampled banner luminance. Dark banner gets a dark wash
       so white text holds; light banner gets a soft white wash so ink
       text holds. The defaults below cover pre-classification renders
       (light/ink — safe over any white-tinted glass). */
    background: var(--glass-tint, rgba(255, 255, 255, 0.62));
    backdrop-filter: blur(10px) saturate(1);
    -webkit-backdrop-filter: blur(10px) saturate(1);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--glass-shadow);
    /* width is implicit — block element fills hero minus the fluid
       horizontal margin clamps above, so the card breathes proportionally
       with the column width. Older calc(100% - 64px) was tied to a
       fixed 32px margin and broke once margin became fluid. */
}
/* (pay-display block removed — pay now renders as .pay-chip inline in
   the .detail-subtitle row per VP review 2026-05-28). */

/* ─── Title row ─── */
.detail-title-row {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    margin-bottom: 18px;
    padding-right: 150px;  /* clears the absolutely-positioned actions */
}
.detail-hero--has-banner .detail-title-row {
    padding-right: 0;  /* actions float above the card, no reservation */
}
.detail-title-stack { flex: 1; min-width: 0; }

/* Hero-variant phone chip — slightly smaller than the apply-section
   one since it sits inside the glass card next to the title. Top-
   aligned with the title so the brand-coloured icon reads as a peer
   to the title weight. */
.cwv3-phone-affordance--hero {
    flex: 0 0 auto;
    align-self: flex-start;
    margin-top: 2px;
}
.detail-title {
    font-family: 'Archivo', sans-serif;
    font-weight: 700;
    /* Fluid type so the headline scales with the detail column instead
       of staying frozen at 28px from ~900px through 1600px. Floor keeps
       the title readable at the tight tablet-desktop end; ceiling caps
       the very large screens before it starts to feel editorial. Mobile
       has its own clamp in responsive.css that overrides this. */
    font-size: clamp(22px, 1.9vw, 30px);
    line-height: 1.15;
    color: var(--ink);
    letter-spacing: -0.03em;
    margin: 0 0 8px;
    max-width: 580px;
    /* Hard-cap at 2 lines with ellipsis so very long titles don't
       balloon the glass card past the hero's clip box (which would
       hide the top of the title behind .detail-hero{overflow:hidden}
       — the bug VP flagged 2026-05-28: "job titles getting cropped
       out, top of right pane cut off, no ability to scroll up").
       Cards on responsive views inherit; only the no-banner variant
       reverts to natural wrap because it has scrollable body context. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    word-break: break-word;
}
/* The 580px cap above suits the no-banner paragraph layout, but the
   glass-card variant has the title row sitting inside a card that
   spans the full hero width — capping at 580px forces a needless
   2-line wrap (e.g. "CDL A Lease Purchase Dedicated Truck / Drivers")
   that visibly pushes the bottom-anchored card upward. Let the title
   use whatever room the card gives it; the title-stack already has
   `flex: 1; min-width: 0;` so it stops short of the phone chip and
   never overflows. */
.detail-hero--has-banner .detail-title {
    max-width: none;
}
/* The no-banner variant lives inside a scrollable .detail panel with
   no fixed-aspect clip box around it — long titles can wrap freely
   there. Restore natural multi-line rendering by undoing the 2-line
   clamp that the banner variant needs. */
.detail-hero:not(.detail-hero--has-banner) .detail-title {
    display: block;
    -webkit-line-clamp: unset;
    overflow: visible;
    text-overflow: clip;
}
.detail-subtitle {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    color: var(--ink-2);
    font-size: 13.5px;
}
.detail-subtitle .dot { color: var(--ink-3); }
.detail-subtitle strong { color: var(--ink); font-weight: 700; }
.detail-subtitle i { font-size: 14px; vertical-align: -2px; }

/* Banner-luminance-driven text colour. detail.js sets --hero-ink-rgb
   on the hero ("14, 14, 14" for light banner, "255, 255, 255" for
   dark). Every text role derives from that single source via
   rgba(var(...), α). Hierarchy carried by alpha tiers so the
   primary / secondary / tertiary split works in both colourways.
   --hero-ink-rgb defaults to ink so pre-classification renders are
   readable; JS overrides inline once the banner is sampled. */
.detail-hero--has-banner {
    --hero-ink-rgb: 14, 14, 14;
}
.detail-hero--has-banner .detail-title,
.detail-hero--has-banner .detail-subtitle strong,
.detail-hero--has-banner .hero-highlight-val {
    color: rgba(var(--hero-ink-rgb), 1);
}
.detail-hero--has-banner .detail-subtitle {
    color: rgba(var(--hero-ink-rgb), 0.82);
}
.detail-hero--has-banner .detail-subtitle .dot {
    color: rgba(var(--hero-ink-rgb), 0.45);
}
.detail-hero--has-banner .hero-highlight-key {
    /* Eyebrow caps are 10.5px Archivo 700 — at that size, anything
       below ~0.85 alpha dissolves on busy banners. The hierarchy is
       still legible because the value below renders at full alpha
       with a thicker face. */
    color: rgba(var(--hero-ink-rgb), 0.88);
}
.detail-hero--has-banner .hero-highlights {
    border-top-color: rgba(var(--hero-ink-rgb), 0.20);
}
.detail-hero--has-banner .hero-highlight {
    border-left-color: rgba(var(--hero-ink-rgb), 0.10);
}

/* (.pay-chip / .pay-display rules removed — pay is now folded into
   the hero-highlights strip as a synthetic 'Pay' entry and inherits
   the standard .hero-highlight chip treatment.) */

/* ─── Hero key-benefits strip ───
   Sits inside the glass card under the pay display, separated by a
   light divider. Up to 4 highlights on desktop laid out in a flex row
   with vertical dividers; responsive.css narrows the visible count to
   2 below the 860px breakpoint. */
.hero-highlights {
    display: flex;
    align-items: stretch;
    gap: 0;
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
}
.hero-highlight {
    flex: 1 1 0;
    min-width: 0;
    padding: 0 12px;
    display: flex;
    align-items: center;
    gap: 8px;
    border-left: 1px solid var(--border);
}
.hero-highlight:first-child {
    padding-left: 0;
    border-left: none;
}
.hero-highlight:last-child {
    padding-right: 0;
}
/* Solid brand-coloured chip with contrasting stroke. Inverting the
   colour pair (--brand backplate, --brand-on stroke) instead of using
   --brand-tint + --brand keeps the icon readable for light brand
   hues (yellow / lime / cream) where the tinted backplate and the
   stroke would both wash out against the glass card's translucent
   white.
   The thin dark ring (rgba ink) holds the chip's edge against the
   bright translucent banner area — without it a yellow chip can
   dissolve into the glass card on lighter banner regions. */
.hero-highlight-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--brand);
    color: var(--brand-on);
    box-shadow:
        0 0 0 1px rgba(14, 14, 14, 0.12),
        0 1px 3px rgba(20, 20, 20, 0.18);
}
.hero-highlight-icon svg { display: block; }
/* Dark theme: the ring loses contrast on the dark surface — swap to
   a light ring instead. */
[data-theme="dark"] .hero-highlight-icon {
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.12),
        0 1px 3px rgba(0, 0, 0, 0.4);
}
.hero-highlight-body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.hero-highlight-key {
    font-family: 'Archivo', sans-serif;
    font-weight: 700;
    font-size: 10.5px;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    line-height: 1;
}
.hero-highlight-val {
    font-family: 'Archivo', sans-serif;
    font-weight: 700;
    font-size: 13.5px;
    color: var(--ink);
    line-height: 1.3;
    letter-spacing: -0.005em;
    overflow-wrap: anywhere;
}
/* (Banner-variant eyebrow colour is handled higher up in the
   tone-driven block; the old static --ink-2 override was leftover
   from the glass-card era and was beating the var-based rule via
   source-order. Removed 2026-05-29.) */

/* ─── Detail body sections ───
   Editorial pass. The description / requirements blocks ship from
   the DB as raw HTML — bold inline tags doubling as subheadings,
   plain <ul><li> bullets, no surface treatment. The rules below
   lift that markup into a magazine-style read: warm-tinted slab,
   brand-coloured left rule, custom bullet markers, eyebrow
   subheadings for the standalone <strong> idiom. */
.detail-body { padding: 28px 32px 32px; }
.detail-section { margin-bottom: 36px; }
.detail-section:last-child { margin-bottom: 0; }

/* Section eyebrow — short uppercase label flanked by a brand bar
   on the left and a hairline rule on the right. Reads as a
   deliberate editorial break instead of a faint label. */
.section-title {
    font-family: 'Archivo', sans-serif;
    font-weight: 700;
    font-size: 11px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-2);
    margin: 0 0 18px;
    display: flex;
    align-items: center;
    gap: 12px;
}
.section-title::before {
    content: '';
    width: 22px;
    height: 2px;
    background: var(--brand);
    border-radius: 1px;
    flex-shrink: 0;
}
.section-title::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--border);
}

/* Short-summary lead ("About this role"). Treated as a pull-quote
   with a brand left rule — gives the first prose block visual
   weight even before the richtext slab below starts. */
.section-prose {
    position: relative;
    font-family: 'Geist', system-ui, sans-serif;
    font-size: 17.5px;
    line-height: 1.55;
    color: var(--ink);
    letter-spacing: -0.005em;
    margin: 0;
    padding: 6px 0 8px 20px;
}
.section-prose::before {
    content: '';
    position: absolute;
    left: 0;
    top: 8px;
    bottom: 10px;
    width: 3px;
    background: var(--brand);
    border-radius: 2px;
}

/* Richtext rendering for job_description + job_requirements. Both
   ship as DB-supplied HTML; selector-level rules render the
   embedded markup as editorial prose without dragging Bootstrap
   defaults along. The slab itself is a warm tinted card with a
   brand-coloured inset rule on the left edge — picks up the
   runtime brand, so tenants with strong colors get a quiet
   identity cue in this block. */
.section-richtext {
    position: relative;
    background: linear-gradient(180deg, var(--surface-2) 0%, var(--surface) 100%);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: inset 3px 0 0 0 var(--brand), var(--shadow-sm);
    padding: 26px 32px 28px 34px;
    font-size: 15.5px;
    line-height: 1.72;
    color: var(--ink-2);
}
.section-richtext p     { margin: 0 0 14px; color: var(--ink-2); }
.section-richtext p:last-child { margin-bottom: 0; }
.section-richtext strong,
.section-richtext b     { font-weight: 700; color: var(--ink); }
.section-richtext em,
.section-richtext i     { font-style: italic; color: var(--ink); }

/* The DB markup commonly uses a <p><strong>Section name:</strong></p>
   pattern as inline subheadings. Promote that idiom to a real
   editorial subhead — uppercase eyebrow with a brand underline. */
.section-richtext p > strong:only-child {
    display: inline-block;
    font-family: 'Archivo', sans-serif;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink);
    padding: 6px 0 4px;
    margin-top: 8px;
    border-bottom: 2px solid var(--brand);
}
.section-richtext p:first-child > strong:only-child { margin-top: 0; }

/* Custom list markers — small rotated square in brand colour. The
   default disc reads as web-1999; this gives the bullets a quiet
   editorial cadence. */
.section-richtext ul,
.section-richtext ol    { margin: 10px 0 16px; padding-left: 0; list-style: none; }
.section-richtext ol    { counter-reset: rt-ol; }
.section-richtext li    {
    position: relative;
    padding-left: 22px;
    margin: 8px 0;
}
.section-richtext ul li::before {
    content: '';
    position: absolute;
    left: 2px;
    top: 0.62em;
    width: 7px;
    height: 7px;
    border-radius: 1.5px;
    background: var(--brand);
    transform: rotate(45deg);
    opacity: 0.9;
}
.section-richtext ol li {
    counter-increment: rt-ol;
}
.section-richtext ol li::before {
    content: counter(rt-ol, decimal-leading-zero);
    position: absolute;
    left: 0;
    top: 0;
    font-family: 'Archivo', sans-serif;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    color: var(--brand);
}

/* h2/h3/h4 inside the richtext — brand left tick mirrors the
   section eyebrow's bar, so the prose-internal headings read as a
   smaller echo of the outer label. */
.section-richtext h1,
.section-richtext h2,
.section-richtext h3,
.section-richtext h4    {
    position: relative;
    font-family: 'Archivo', sans-serif;
    font-weight: 700;
    letter-spacing: -0.015em;
    color: var(--ink);
    padding-left: 14px;
    margin: 26px 0 10px;
}
.section-richtext h1::before,
.section-richtext h2::before,
.section-richtext h3::before,
.section-richtext h4::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.35em;
    bottom: 0.35em;
    width: 3px;
    background: var(--brand);
    border-radius: 2px;
}
.section-richtext h2 { font-size: 18px; }
.section-richtext h3 { font-size: 16px; }
.section-richtext h4 { font-size: 14.5px; }
.section-richtext a {
    color: var(--brand);
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
    font-weight: 700;
}
.section-richtext a:hover { filter: brightness(0.9); }
.section-richtext hr {
    border: none;
    border-top: 1px solid var(--border);
    margin: 20px 0;
}
.section-richtext blockquote {
    margin: 16px 0;
    padding: 4px 0 4px 16px;
    border-left: 2px solid var(--brand);
    color: var(--ink);
    font-style: italic;
}

/* Brand-light tenants (yellow / pastel hex) — the brand-coloured
   underline under standalone <strong> washes out against the warm
   slab. Switch it to ink so the eyebrow still reads. */
body.brand-light .section-richtext p > strong:only-child {
    border-bottom-color: var(--ink);
}

/* ─── Apply CTAs row (Apply by chat / Apply by phone) ───
   Lives above the inline form. Mirrors v1's button row that sits
   between the summary and the form. Brand-coloured chat button,
   neutral phone button so they read as primary / secondary. */
.cwv3-apply-ctas {
    margin-top: 8px;
}
.cwv3-cta-row {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}
.cwv3-cta-btn {
    flex: 1 1 200px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 48px;
    padding: 0 18px;
    border-radius: var(--radius);
    font-family: 'Archivo', sans-serif;
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
    text-decoration: none;
    border: 1px solid var(--border-2);
    transition: all 120ms ease;
    box-sizing: border-box;
    color: var(--ink);
    background: var(--surface);
}
.cwv3-cta-btn:hover {
    transform: translateY(-1px);
    border-color: var(--ink-3);
    box-shadow: var(--shadow-sm);
}
.cwv3-cta-btn i { font-size: 18px; }
.cwv3-cta-chat {
    background: var(--brand);
    color: var(--brand-on);
    border-color: var(--brand);
}
.cwv3-cta-chat:hover {
    border-color: var(--brand);
    filter: brightness(0.92);
    box-shadow: 0 4px 12px var(--brand-tint-strong);
}

/* ─── Phone affordance ───
   Icon-only chip by default; expands inline on first tap to reveal
   the formatted number, then dials on the next tap (the anchor's
   tel: href fires). The whole affordance is one <a> so right-click
   copy-link and keyboard activation work unchanged.
   Sits to the right of the brand-coloured chat CTA; doesn't compete
   for visual weight since it's secondary action. */
.cwv3-phone-affordance {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    height: 48px;
    padding: 0;
    border-radius: 999px;
    border: 1px solid transparent;
    background: var(--surface);
    color: var(--ink);
    text-decoration: none;
    cursor: pointer;
    transition: all 200ms cubic-bezier(0.16, 1, 0.3, 1);
    overflow: hidden;
    max-width: 48px;  /* collapses to icon-only width by default */
    box-sizing: border-box;
    /* Dark ring + soft shadow — same treatment the highlight chips use,
       keeps the affordance's edge defined against the translucent glass
       card on bright banner regions where a thin border alone would
       dissolve. */
    box-shadow:
        0 0 0 1px rgba(14, 14, 14, 0.16),
        0 1px 3px rgba(20, 20, 20, 0.12);
}
.cwv3-phone-affordance:hover {
    background: var(--surface-2);
    box-shadow:
        0 0 0 1px rgba(14, 14, 14, 0.22),
        0 2px 6px rgba(20, 20, 20, 0.16);
}
.cwv3-phone-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 46px;            /* fills the collapsed pill */
    height: 100%;
    flex-shrink: 0;
    /* Ink (near-black) rather than --brand — yellow / lime / cream brand
       hues blow out a brand-coloured stroke against the chip's white
       backplate. Dark stroke reads on every tenant colour. */
    color: var(--ink);
}
.cwv3-phone-icon i { font-size: 20px; }
[data-theme="dark"] .cwv3-phone-affordance {
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.16),
        0 1px 3px rgba(0, 0, 0, 0.5);
}
.cwv3-phone-number {
    font-family: 'Archivo', sans-serif;
    font-weight: 700;
    font-size: 14.5px;
    color: var(--ink);
    letter-spacing: -0.01em;
    white-space: nowrap;
    opacity: 0;
    max-width: 0;
    padding-right: 0;
    pointer-events: none;
    transition: opacity 180ms ease 60ms,
                max-width 240ms cubic-bezier(0.16, 1, 0.3, 1),
                padding-right 240ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* Revealed state — chip expands width, number fades in.
   max-width target is large enough for any US-format number
   "(555) 555-5555" with the 18px right padding. Keeps the dark ring
   from the default state but stacks a brand-coloured ring underneath
   so the expanded state still reads as the brand action. */
.cwv3-phone-affordance--revealed {
    max-width: 220px;
    background: var(--brand-tint);
    box-shadow:
        0 0 0 1px rgba(14, 14, 14, 0.18),
        0 0 0 3px var(--brand-ring),
        0 2px 8px var(--brand-tint-strong);
}
.cwv3-phone-affordance--revealed .cwv3-phone-icon {
    color: var(--ink);
}
.cwv3-phone-affordance--revealed .cwv3-phone-number {
    opacity: 1;
    max-width: 180px;
    padding-right: 18px;
    pointer-events: auto;
}
.cwv3-phone-affordance--revealed:hover {
    filter: brightness(0.97);
}
[data-theme="dark"] .cwv3-phone-affordance--revealed {
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.22),
        0 0 0 3px var(--brand-ring),
        0 2px 8px rgba(0, 0, 0, 0.5);
}

/* ─── Key details list ─── */
.key-details {
    display: flex;
    flex-direction: column;
    background: linear-gradient(180deg, var(--surface-2) 0%, var(--surface) 100%);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}
.key-detail-row {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 16px 18px;
    border-top: 1px solid var(--border);
}
.key-detail-row:first-child { border-top: none; }

/* Iconed variant — icon chip on the left, stacked key+body on the
   right. Mirrors v1's .jv-hl-card layout. Falls back to the un-iconed
   stacked layout when getHighlightIcon returns '' (key not in map). */
.key-detail-row--iconed {
    flex-direction: row;
    align-items: flex-start;
    gap: 14px;
}
/* Same inversion as the hero chip — solid brand backplate, contrast
   stroke. Sits on the white key-details card here so the chip needs
   to carry its own colour weight; the dark ring keeps it defined for
   any brand color. */
.key-detail-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--brand);
    color: var(--brand-on);
    margin-top: 2px;
    box-shadow:
        0 0 0 1px rgba(14, 14, 14, 0.10),
        0 1px 3px rgba(20, 20, 20, 0.12);
}
.key-detail-icon svg { display: block; }
[data-theme="dark"] .key-detail-icon {
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.12),
        0 1px 3px rgba(0, 0, 0, 0.4);
}
.key-detail-main {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
    flex: 1;
}
.key-detail-key {
    font-family: 'Archivo', sans-serif;
    font-weight: 700;
    font-size: 11px;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
.key-detail-body {
    font-size: 14.5px;
    color: var(--ink);
    line-height: 1.55;
}
.key-detail-value { display: block; }
.key-detail-list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.key-detail-list li {
    position: relative;
    padding-left: 16px;
}
.key-detail-list li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 9px;
    width: 6px;
    height: 6px;
    background: var(--brand);
    border-radius: 50%;
}

/* ─── Empty detail state (no desc, no highlights, no inline form) ─── */
.empty-detail {
    padding: 32px;
    text-align: center;
    color: var(--ink-2);
    background: var(--surface-2);
    border-radius: var(--radius);
}
.empty-detail i {
    font-size: 32px;
    color: var(--ink-3);
    margin-bottom: 12px;
    display: block;
}
.empty-detail p {
    margin: 0;
    font-size: 14px;
    line-height: 1.55;
    max-width: 380px;
    margin: 0 auto;
}
