/*
 * Ultimate -- design pack for the oneclick theme.
 *
 * Loaded dead last in the cascade (functions.php oneclick_assets()), only
 * when oneclick_site('design_template') is 'ultimate'.
 *
 * HISTORY: PR #241 gave this pack its own full visual identity (directional
 * hero scrim, Instrument Serif + Inter type system, its own card language,
 * pill-chip kickers, alternating section bands, a footer accent). The owner
 * reversed that direction the same day (2026-09-01, "restore Home Services
 * look"): this file was reduced to just the Font Pairing mechanism below,
 * and Ultimate fell through to the shared theme CSS -- byte-identical to
 * Lightning. PR #241's full identity is preserved in git history and as an
 * unregistered reference copy at wp-theme/oneclick/templates/ultimate_archive/
 * (see that directory's own README.md).
 *
 * LATER THE SAME DAY, the owner reviewed a hand-built spec (a "Mock 1" home
 * page composition plus a component menu listing every candidate option per
 * part, current-vs-fresh) and picked a specific, named component for each
 * of eleven parts of the individual-site home page:
 *   N1  glass nav bar, condenses on scroll
 *   F1  floating-label request-a-quote form (templates/ultimate/parts/
 *       hero-form.php)
 *   B1  primary button -- pill, arrow, hover glow
 *   B2  secondary button -- outline that fills in on hover
 *   H1  hero stat card -- count-up years-in-business / rating, HONESTY
 *       GATE: renders only stats the brief can prove, absent entirely with
 *       neither
 *   R3  rating pill with stars (restyles the existing #236 honest-badge
 *       markup in place; never invents a count)
 *   S1  photo-top service cards, hover lift + underline sweep
 *   P1  circle-check about bullets
 *   P2  numbered how-we-work steps with a hairline connector
 *   Q1  smooth FAQ accordion, keyboard accessible
 *   T1  dark footer with a soft accent glow
 * This is a DIFFERENT pass from PR #241: it does not touch H1/H2/H3 type
 * scale, does not add chip-kicker eyebrows, does not retint the alternating
 * section bands, and reuses the theme's existing markup/classes wherever
 * one already exists (the FAQ trigger/answer/aria-expanded structure, the
 * about-bullet check-disc pseudo-elements, the commitments numbered-step
 * connector) rather than inventing parallel markup. Every value below is
 * translated into this pack's own idioms: --ocf-primary (never a hardcoded
 * hue -- always the brief's own brand color, bridged from --color-accent in
 * header.php), the existing --card-radius / --radius-* / --duration / --ease
 * tokens, and color-mix() in place of an rgba(accent-rgb, alpha) triple
 * (this codebase has no --accent-rgb variable; color-mix reaches the same
 * soft tints and glows without needing one). Manrope/Source Sans 3 (or a
 * brief's own Font Pairing preset, see the block directly below) are
 * unchanged -- no wording or copy changed anywhere, styling only. All
 * motion respects prefers-reduced-motion (see the block at the very end of
 * this file).
 *
 * The ONE thing kept from PR #241/#234's own pass: the Font Pairing preset
 * mechanism -- a brief can still choose a different heading/body pairing for
 * the ultimate template specifically (platform/public/create.html step 6,
 * tools/provision_brief.py resolves it into brand.font_heading/
 * brand.font_body -> a per-site tokens.css's --font-heading/--font-body,
 * loaded before this file). --ocf-font-heading/--ocf-font-body below read
 * that value first, falling back to Manrope/Source Sans 3 -- this pack's
 * own default, matching templates/lightning's hardcoded default in
 * header.php -- only when tokens.css hasn't set one at all (a render
 * outside the provisioning pipeline, e.g. a hand-built fixture).
 */

:root {
    --ocf-font-heading: var(--font-heading, 'Manrope', sans-serif);
    --ocf-font-body: var(--font-body, 'Source Sans 3', sans-serif);

    /* T1 footer tokens -- header.php's --ocf-footer-* bridge falls back to
       the tenant's light surface tokens by default (assets/tokens.css); this
       pack overrides all three to the fixed dark #141414 family, same fixed
       neutral the hero/CTA dark sections already use (--ocf-dark-bg family
       in header.php's own bridge), never the tenant's brand-derived light
       tokens. */
    --ocf-footer-bg: #141414;
    --ocf-footer-heading: #ffffff;
    --ocf-footer-body: color-mix(in srgb, #ffffff 66%, transparent);
}

/* ============================================================
   N1 -- glass nav bar, condenses on scroll
   (assets/components/header.css .nav-bar; JS: templates/ultimate/assets/
   ultimate.js toggles .is-condensed on scroll. No-JS fallback: the blur +
   translucent bar below renders on its own either way -- only the
   compacting on scroll needs the script.)
   ============================================================ */
.nav-bar {
    background: color-mix(in srgb, var(--ocf-bg) 68%, transparent);
    -webkit-backdrop-filter: blur(10px) saturate(160%);
    backdrop-filter: blur(10px) saturate(160%);
    border-bottom-color: color-mix(in srgb, var(--ocf-heading) 8%, transparent);
    transition: background var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}
.nav-bar.is-condensed {
    background: color-mix(in srgb, var(--ocf-bg) 95%, transparent);
    box-shadow: 0 4px 18px -10px color-mix(in srgb, var(--ocf-heading) 30%, transparent);
}
.nav-inner {
    transition: min-height var(--duration) var(--ease);
}
.nav-bar.is-condensed .nav-inner {
    min-height: 3.75rem;
}
.nav-cta {
    border-radius: 999px;
}

/* ============================================================
   B1 -- primary buttons: pill, hover glow, arrow travel
   (base.css .btn-primary; ocf-global.css .nav-cta already pilled above;
   .mobile-cta; this pack's own .ultimate-b1-btn on the F1 form's submit)
   ============================================================ */
.btn-primary,
.ultimate-b1-btn,
.hero-form-card .form-submit-btn,
.mobile-cta {
    border-radius: 999px !important;
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--ocf-primary) 50%, transparent);
    transition: box-shadow var(--duration) var(--ease), transform var(--duration) var(--ease), background var(--duration) var(--ease);
}
.btn-primary:hover,
.btn-primary:focus-visible,
.ultimate-b1-btn:hover,
.ultimate-b1-btn:focus-visible,
.hero-form-card .form-submit-btn:hover,
.hero-form-card .form-submit-btn:focus-visible {
    box-shadow: 0 0 0 8px color-mix(in srgb, var(--ocf-primary) 16%, transparent), 0 10px 22px -8px color-mix(in srgb, var(--ocf-primary) 55%, transparent);
    transform: translateY(-2px);
}
.btn-primary svg,
.ultimate-b1-arrow {
    transition: transform var(--duration) var(--ease);
}
.btn-primary:hover svg,
.btn-primary:focus-visible svg,
.ultimate-b1-btn:hover .ultimate-b1-arrow,
.ultimate-b1-btn:focus-visible .ultimate-b1-arrow {
    transform: translateX(3px);
}

/* ============================================================
   B2 -- secondary/outline buttons: color sweeps in from the left on hover
   (base.css .btn-outline -- hero secondary CTA)
   ============================================================ */
.btn-outline {
    position: relative;
    z-index: 0;
    overflow: hidden;
    isolation: isolate;
    border-radius: 2px;
    transition: color var(--duration) var(--ease);
}
.btn-outline::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: var(--ocf-primary);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 280ms var(--ease);
}
.btn-outline:hover,
.btn-outline:focus-visible {
    color: #fff;
    border-color: var(--ocf-primary);
}
.btn-outline:hover::before,
.btn-outline:focus-visible::before {
    transform: scaleX(1);
}

/* ============================================================
   Final CTA band -- Hannah's 2026-09-03 correction, ROUND 2 (live review
   of the round-1 fix in PR #303 rejected the flat brand-green band as
   "leprechaun green"). Round 1's problem (band = footer's own fixed
   #141414, the two blurred into one dark block) is still fixed here,
   just with a different resolution: instead of a flat brand-color band,
   this is now a light/white section of its own -- a soft brand-tinted
   radial glow anchored top-right on a white ground, with a thin neutral
   top seam -- reading as its own modern section sitting ABOVE the dark
   footer rather than matching or fighting it.
   Fix, scoped to this file only (loaded solely for design_template ===
   'ultimate', so it never reaches the frozen packs' shared cta.css
   rule):
   - .ocf-cta__shade (always-rendered per cta.css, normally a dark
     photo-dimming scrim) is neutralized to transparent, and the CTA
     image slot is hidden outright -- this band is a clean color
     surface, never a dark-over-photo treatment, regardless of whether
     a site happens to have set a CTA image.
   - .ocf-cta's own background carries the white-ground radial glow.
   - --cta-headline-color/--cta-body-color (the custom props
     .ocf-cta__headline/__body actually read, cta.css's own field-color
     fallback pattern) are repointed from the dark-tone alt tokens
     (--ocf-heading-alt/--ocf-body-alt, white-family -- correct on a
     dark band, wrong on this white one) to the normal light-surface
     tokens (--ocf-heading/--ocf-body) header.php's own bridge already
     defines for the page's default (non-dark) sections.
   - The eyebrow and primary button need NO override at all: cta.css's
     own dark-band eyebrow rule already defaults to var(--ocf-primary),
     and base.css/ocf-global.css's own .btn-primary is already the
     solid-primary-background/white-text pill (B1) -- both rules from
     round 1 existed only to fight the flat-green band, which no longer
     exists.
   - The phone link keeps round 1's no-box plain-link shape but swaps
     white text for the normal dark-surface text tokens.
   ============================================================ */
.ocf-cta > .ocf-cta__shade,
.ocf-cta .ocf-cta__shade {
    background: transparent !important;
    opacity: 0 !important;
}
.ocf-cta > .ocf-cta__image,
.ocf-cta .ocf-cta__image {
    display: none;
}
.ocf-cta {
    --cta-headline-color: var(--ocf-heading);
    --cta-body-color: var(--ocf-body);
    background: radial-gradient(60% 80% at 100% 0%, color-mix(in srgb, var(--ocf-primary) 12%, white), white) !important;
    border-top: 1px solid var(--ocf-border-light);
}
.ocf-cta .ocf-cta__phone {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    min-height: 3rem;
    padding: 0;
    padding-left: 0;
    border: 0;
    border-left: 0;
    color: var(--ocf-body);
    font-family: var(--ocf-font-heading), system-ui, sans-serif;
    font-weight: var(--font-weight-bold);
    text-decoration: none;
}
.ocf-cta .ocf-cta__phone:hover,
.ocf-cta .ocf-cta__phone:focus-visible {
    color: var(--ocf-body);
    text-decoration: underline;
}
.ocf-cta .ocf-cta__phone strong {
    color: var(--ocf-heading);
}

/* ============================================================
   F1 -- floating-label request form
   (this pack's own templates/ultimate/parts/hero-form.php; targets its
   .ultimate-f1-field wrapper -- input, then label, in source order, so a
   plain adjacent-sibling selector is enough)
   ============================================================ */
.ultimate-f1-field {
    position: relative;
}
.ultimate-f1-field input,
.ultimate-f1-field textarea {
    border: none !important;
    border-bottom: 2px solid var(--ocf-border-light) !important;
    border-radius: 0 !important;
    background: transparent !important;
    padding: 1.15rem 0.05rem 0.45rem !important;
    box-shadow: none !important;
}
.ultimate-f1-field input:focus,
.ultimate-f1-field textarea:focus {
    border-bottom-color: var(--ocf-primary) !important;
    box-shadow: none !important;
}
.ultimate-f1-field label {
    position: absolute;
    left: 0.05rem;
    top: 1.15rem;
    color: var(--ocf-body);
    font-size: var(--font-body-size, 1rem);
    pointer-events: none;
    transition: transform 180ms ease, font-size 180ms ease, color 180ms ease;
    transform-origin: left top;
}
.ultimate-f1-field input:focus + label,
.ultimate-f1-field input:not(:placeholder-shown) + label,
.ultimate-f1-field textarea:focus + label,
.ultimate-f1-field textarea:not(:placeholder-shown) + label {
    transform: translateY(-1.1rem);
    color: var(--ocf-primary);
    font-size: 0.72rem;
}

/* ============================================================
   H1 -- hero stat card: overlaps the hero's bottom edge, count-up numbers
   (templates/ultimate/parts/home-hero.php's $ultimate_hero_stats block --
   absolutely positioned, so it never joins .ocf-hero's own CSS-grid layout;
   .ocf-hero gets a matching margin-bottom so the card has room to sit half
   in the hero photo, half over the section below, without covering either
   section's real content. HONESTY GATE lives in the PHP: this CSS only ever
   sees the block when at least one real stat exists.)
   ============================================================ */
.ocf-hero {
    overflow: visible;
    margin-bottom: 2.75rem;
}
.ultimate-hero-stats {
    position: absolute;
    left: 1.25rem;
    right: 1.25rem;
    bottom: -2.75rem;
    z-index: 2;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 2.4rem;
    max-width: 26rem;
    margin: 0 auto;
    padding: 0.9rem 1.25rem 1.5rem;
    background: var(--ocf-bg);
    border-radius: 16px;
    box-shadow: 0 16px 30px -14px color-mix(in srgb, var(--ocf-heading) 35%, transparent);
}
.ultimate-hero-stat {
    text-align: center;
}
.ultimate-hero-stat__num {
    display: block;
    color: var(--ocf-primary);
    font-family: var(--ocf-font-heading), system-ui, sans-serif;
    font-weight: 800;
    font-size: 1.5rem;
}
.ultimate-hero-stat__label {
    display: block;
    margin-top: 0.15rem;
    color: var(--ocf-body);
    font-size: 0.7rem;
}
@media (max-width: 640px) {
    .ultimate-hero-stats { gap: 1.4rem; }
}

/* ============================================================
   R3 -- rating pill (restyles the existing #236 honest-badge markup,
   .ocf-hero__rating, in place -- same real value/label it already
   computes, no new copy)
   ============================================================ */
.ocf-hero__rating {
    display: inline-flex;
    background: color-mix(in srgb, #ffffff 16%, transparent);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    border-radius: 999px;
    padding: 0.5rem 1.1rem;
}
.ocf-hero__rating-value {
    font-family: var(--ocf-font-heading), system-ui, sans-serif;
    font-weight: 800;
}

/* ============================================================
   S1 -- photo-top service cards: hover lift (already the shared default
   via --card-transform-hover) + accent underline sweep under the title
   ============================================================ */
.ocf-svc-card-body h3 {
    position: relative;
    display: inline-block;
    padding-bottom: 0.15rem;
}
.ocf-svc-card-body h3::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: -2px;
    width: 0;
    height: 2px;
    background: var(--ocf-primary);
    transition: width 250ms var(--ease);
}
.ocf-svc-card:hover .ocf-svc-card-body h3::after,
.ocf-svc-card:focus-within .ocf-svc-card-body h3::after {
    width: 100%;
}

/* ============================================================
   P1 -- about bullets: soft accent disc + accent-colored check
   (about.css already draws the disc/check via --about-check-color /
   --about-check-mark-color pseudo-elements -- this pack only retints the
   two tokens, no new markup)
   ============================================================ */
.ocf-about {
    --about-check-color: color-mix(in srgb, var(--ocf-primary) 14%, var(--ocf-bg));
    --about-check-mark-color: var(--ocf-primary);
}

/* ============================================================
   Ultimate about photo: short landscape crop, not full-height portrait
   (2026-09-08, Hannah: "our photo on the left here is very long and
   should be shorter"). The 2026-09-03 rule directly above this comment
   set the media box to the source photo's raw 2:3 portrait ratio, which
   at this column's rendered width stretched the box to ~830-920px tall
   -- nearly the full height of the text column next to it, reading as
   "very long." Measured against the reference product's home About photo
   (Playwright computed styles/bounding box, 1440 viewport,
   /Users/hannahopenclaw/Hermes/work/design-refs/about-photo-review-cards-2026-09-08/measure.py):
   716.0 x 477.3px rendered, aspect-ratio "3 / 2", border-radius 10px,
   object-fit cover, no box-shadow, vertically centered against the copy
   column (.ocf-about__grid's own align-items: center in about.css
   already matches this, unchanged here). This rule now crops the same
   portrait source to that measured 3:2 ratio instead of running it at
   its native 2:3 -- the photo is shorter, matching the reference and
   Hannah's ask, at the cost of cropping the portrait source (accepted
   per this brief: the ask is "shorter," not "uncropped"). This
   design.css file only ever loads for the ultimate pack (see this
   file's own header + functions.php's oneclick_assets()), so no extra
   scoping selector is needed for the frozen packs to stay zero-diff.
   ============================================================ */
.ocf-about__media img {
    aspect-ratio: 3 / 2;
    object-fit: cover;
}

/* ============================================================
   P2 -- numbered how-we-work steps: lighter accent circle, hairline
   connector (commitments.css already draws the numbered circle + the
   connecting line via ::before/::after -- this pack only resizes the
   circle and re-centers the connector on the new size, no new markup)
   ============================================================ */
.ocf-commitment-num {
    inline-size: 2.5rem;
    block-size: 2.5rem;
    font-size: 0.85rem;
}
.ocf-commitments .ocf-commitment:not(:last-child)::before {
    top: calc(2.5rem - 1px);
    left: calc(1.25rem - 1px);
}
.ocf-commitments .ocf-commitment:not(:last-child)::after {
    left: calc(2.5rem + clamp(1rem, 2vw, 1.35rem));
}

/* ============================================================
   Q1 -- smooth FAQ accordion, keyboard accessible
   (faq.css already draws the trigger/chevron/answer structure with
   aria-expanded + .is-open -- this pack swaps display:none/:block for a
   grid-template-rows animation so open/close is smooth; JS:
   templates/ultimate/assets/ultimate.js toggles .is-open on click. Native
   <button> triggers stay keyboard-operable with no extra work.)

   2026-09-03 "skin corrections" (owner screenshot FAQ_Sloppy_Not_premium.png,
   fix/ultimate-faq-cards): the two-column hairline list read as sloppy --
   templates/ultimate/parts/home-faq.php now renders ONE column of FAQ
   items; this block turns each .ocf-faq-item into its own boxed card
   (rounded rectangle, light border, white card surface) instead of the
   shared faq.css's flat hairline-divider list. The two rules below with
   .ocf-faq-column/:first-child in their selector exist only to out-specify
   the equally- or more-specific shared faq.css rules they replace (the
   two-column grid, and the tinted first-child top border) -- nothing in
   assets/components/faq.css itself changes, so every other pack keeps the
   exact hairline look untouched.
   ============================================================ */
.ocf-faq-columns {
    grid-template-columns: 1fr;
    gap: 0.625rem;
    margin-top: 1.75rem;
}
.ocf-faq-column {
    gap: 0.625rem;
}
.ocf-faq-item {
    border: 1px solid var(--ocf-border);
    border-radius: var(--card-radius);
    background: var(--ocf-bg);
    padding: 1rem;
}
.ocf-faq-column .ocf-faq-item:first-child {
    border-top: 1px solid var(--ocf-border);
}
.ocf-faq-trigger {
    padding: 0;
    font-weight: var(--font-weight-medium);
    font-size: 1.0625rem;
}
.ocf-faq-answer {
    display: grid;
    grid-template-rows: 0fr;
    padding: 0;
    transition: grid-template-rows 320ms var(--ease);
}
.ocf-faq-item.is-open .ocf-faq-answer {
    display: grid;
    grid-template-rows: 1fr;
}
.ocf-faq-answer p {
    overflow: hidden;
    margin: 0;
    padding-top: 0.75rem;
}
.ocf-faq-item.is-open {
    border-color: color-mix(in srgb, var(--ocf-primary) 28%, var(--ocf-border));
    background: color-mix(in srgb, var(--ocf-primary) 4%, var(--ocf-bg));
}

/* ============================================================
   T1 -- dark footer with a soft accent glow
   (footer.css .site-footer already consumes --ocf-footer-bg/-heading/-body
   -- set to the dark family at the top of this file; this block adds the
   radial glow + a matching dark hairline, content/links unchanged)
   ============================================================ */
.site-footer {
    position: relative;
    overflow: hidden;
    border-top-color: transparent;
}
.site-footer::before {
    content: "";
    position: absolute;
    top: -45%;
    left: 50%;
    z-index: 0;
    width: 75%;
    height: 85%;
    background: radial-gradient(closest-side, color-mix(in srgb, var(--ocf-primary) 45%, transparent), transparent 70%);
    transform: translateX(-50%);
    pointer-events: none;
}
.footer-grid,
.footer-bottom {
    position: relative;
    z-index: 1;
}
.footer-bottom {
    border-top-color: color-mix(in srgb, #ffffff 15%, transparent);
}
/* Footer links inherit base.css's global `a { color: var(--color-accent) }`,
   which is unreadable on this pack's #141414 footer -- repoint them to the
   dark-footer tokens already set above (icons use stroke="currentColor" in
   footer.php so they follow along automatically). */
.footer-link-list a,
.footer-contact-links a,
.footer-bottom-links a {
    color: var(--ocf-footer-body);
}
.footer-link-list a:hover,
.footer-link-list a:focus-visible,
.footer-contact-links a:hover,
.footer-contact-links a:focus-visible,
.footer-bottom-links a:hover,
.footer-bottom-links a:focus-visible {
    color: var(--ocf-footer-heading);
}

/* ============================================================
   R4 -- reviews marquee: a continuous right-to-left row of review cards
   (owner correction, 2026-09-03, screenshot "Reviews_add_card_animation.
   png": the old two-static-card layout read as unfinished, not premium).
   The scroll mechanism itself -- assets/base.css's .reviews-marquee /
   .marquee-track (two identical flex rows sharing one 40s linear infinite
   translateX keyframe, so as the first tiles fully out of view the second
   is already positioned exactly where it started -- seamless loop, zero
   JS -- plus its own prefers-reduced-motion block that drops the
   animation and hides the duplicate row entirely) is untouched here, only
   read; parts/testimonials.php renders that duplicate second .marquee-
   track (aria-hidden + inert) even under 4 reviews so the track still
   fills the row. Cards reuse .ocf-testimonial-card (testimonials.css --
   existing border/radius/bg/padding); only the fixed marquee width, the
   12px radius and the new avatar/name/meta top row are added below. The
   avatar is a solid --ocf-primary disc with the reviewer's own first
   initial (base.css's own generic .avatar class only supplies size/shape;
   this pack fills it solid instead of a soft tint, per the reference).
   The meta line under the name is the honest per-review star row, or
   "Google review" ONLY when that review's own `source` field really is
   google (testimonials.php's honesty check, same rule parts/rating-
   badge.php already applies) -- never an invented source. Edge fades are
   the brief's own explicitly-optional touch: pure CSS, no JS, no new
   markup.
   ============================================================ */
.reviews-marquee.ocf-reviews-marquee {
    position: relative;
    /* 2026-09-08, Hannah: "these boxes look almost cut off at the shadow
       below." base.css's .reviews-marquee sets a plain `overflow: hidden`
       (both axes) so the track can slide horizontally without showing the
       looped duplicate row -- but the card's own box-shadow (measured
       here: 0 2.88px 8.8px, ~10.7px reach below the card) paints outside
       the card's border box, and since this container's height is exactly
       the card's height (auto, no built-in headroom), that shadow was
       clipped by the same overflow:hidden meant only for the horizontal
       loop. Fix: split the axes -- overflow-x: clip keeps the horizontal
       clip the marquee animation needs, overflow-y: visible (higher
       specificity than base.css's one-class rule, so this wins) lets the
       shadow render in full above/below the row. padding-block reserves
       room for that shadow inside the row's own box instead of relying on
       whatever whitespace happens to be below in the page flow;
       margin-block cancels the added height so the section's outer
       spacing is unchanged. padding-inline/margin-inline give the first
       and last card a small buffer of background before the edge-fade
       masks below start, instead of the fade eating straight into the
       card's own edge (same reason the first card read as "cut off" on
       the left -- flush against the container edge with no buffer). */
    overflow-x: clip;
    overflow-y: visible;
    padding-block: 1rem;
    margin-block: -1rem;
    padding-inline: 0.5rem;
    margin-inline: -0.5rem;
}
.reviews-marquee.ocf-reviews-marquee::before,
.reviews-marquee.ocf-reviews-marquee::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    z-index: 1;
    width: clamp(1.5rem, 6vw, 4rem);
    pointer-events: none;
}
.reviews-marquee.ocf-reviews-marquee::before {
    left: 0;
    background: linear-gradient(90deg, var(--ocf-bg), transparent);
}
.reviews-marquee.ocf-reviews-marquee::after {
    right: 0;
    background: linear-gradient(270deg, var(--ocf-bg), transparent);
}
.ocf-review-marquee-card {
    width: 340px;
    flex: none;
    border-radius: 12px;
    padding: 20px;
}
/* Specificity note: testimonials.css's `.ocf-testimonials .ocf-testimonial-
   card { min-height: clamp(...) }` (two classes) outranks a plain single-
   class override, cascade order or not -- this one matches it so the
   marquee card's height stays content-driven instead of that clamp. */
.ocf-testimonials .ocf-review-marquee-card {
    min-height: auto;
}
.ocf-review-marquee-top {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}
.ocf-review-marquee-avatar.avatar {
    width: 40px;
    height: 40px;
    background: var(--ocf-primary);
    color: #fff;
    font-family: var(--ocf-font-heading), system-ui, sans-serif;
    font-size: 0.95rem;
}
.ocf-review-marquee-who {
    display: grid;
    gap: 0.2rem;
}
.ocf-review-marquee-who strong {
    color: var(--ocf-heading);
    font-weight: 800;
}
.ocf-review-marquee-meta {
    color: var(--ocf-label);
    font-size: var(--font-label-size);
}
.ocf-review-marquee-meta.ocf-testimonial-stars {
    gap: 0.15rem;
    color: var(--ocf-label);
}
.ocf-review-marquee-meta.ocf-testimonial-stars svg {
    width: 0.85rem;
    height: 0.85rem;
}

/* ============================================================
   Hannah's 2026-09-03 correction -- inner-page text: smaller, tighter,
   premium (screenshot "Inner_page_text_sloppy:large_not_premium.png", a
   service-area page). Before this, both prose containers on ultimate's
   inner pages fell all the way through to base.css's raw h1..h4/p
   defaults with zero per-container override: parts/service-detail.php's
   .prose (service + service-area detail pages) and page-about.php's
   .ocf-about-story__content (About's rich-text story) -- so body copy
   read 18px/1.68 (--font-body-size) and section h2 read
   clamp(1.5rem,3.2vw,2.1rem), both oversized and loose at desktop widths,
   and every section printed a plain <hr> divider right above its h2.
   Deliberately literal rem values below, NOT var(--font-body-size) /
   var(--font-h2-size) / var(--font-h3-size) -- those tokens also drive
   the HOME page and every other pack's body copy, which stays untouched
   per the brief ("do NOT change --font-body-size globally"). This file
   only loads for design_template "ultimate" (functions.php's
   oneclick_assets()), so none of this reaches Lightning/Pacific/etc.
   ============================================================ */
.prose,
.ocf-about-story__content {
    max-width: 68ch;
    /* 2026-09-05 (fix/theme-tokens-apply): wrapped in
       var(--oc-owner-font-body-size, ...) so a Text Styles Body-size token
       reaches this container -- falls back to the exact 17px this file
       chose over --font-body-size when no owner token is set. */
    font-size: var(--oc-owner-font-body-size, 1.0625rem); /* 17px, was --font-body-size (18px) */
    line-height: 1.6;     /* was 1.68 (.prose) / base.css's 1.65 (about) */
}
.prose > * + *,
.ocf-about-story__content > * + * {
    margin-top: 1.1em;
}
.prose h2,
.ocf-about-story__content h2 {
    margin: 0 0 0.5em;
    font-size: var(--oc-owner-font-h2-size, 1.75rem); /* 28px, was clamp(1.5rem, 3.2vw, 2.1rem) up to 33.6px */
    line-height: 1.25;
}
/* Same specificity as the ".prose h2" rule above (one class + one type each
   -- the ">" combinator adds no specificity of its own), so source order
   is what makes this one win on margin-top only; every prose h2 is a
   direct child of .prose / .ocf-about-story__content (service-detail.php
   nests nothing between them), so this reaches all of them. */
.prose > h2,
.ocf-about-story__content > h2 {
    margin-top: 2.5rem;
}
.prose h3,
.ocf-about-story__content h3 {
    font-size: var(--oc-owner-font-h3-size, 1.25rem); /* 20px, was base.css's flat 1.2rem -- kept, restated
                            in rem so it never drifts with body's raw h3 rule */
    line-height: 1.3;
}
/* service-detail.php prints a plain <hr> above every section h2 (and above
   the trailing FAQ block's "Common questions" h2) -- Hannah's correction:
   remove it, the 2.5rem top margin above already separates sections. */
.prose hr {
    display: none;
}

/* ============================================================
   2026-09-08 correction -- inner-page "text wall": Hannah's follow-up ask
   ("the inner pages of [the reference] template look much nicer and more
   premium than ours ... match the premium look of the text wall: spacing,
   sizing and format", side card stays put) measured against the reference's
   computed styles at 1440px (brief:
   .superpowers/sdd/alpha-2026-09-08/brief-inner-page-text-wall.md). Scoped
   to service-detail.php's .ocf-detail-content .prose (the ONLY template
   that uses the bare .prose class -- page-about.php's
   .ocf-about-story__content is untouched and still reads the 2026-09-03
   block above; the home page, hero, FAQ block markup, sidebar card
   (.ocf-detail-aside/.ocf-detail-sticky-*) and footer use none of these
   selectors either). Two classes + type beats both the 2026-09-03 block's
   one class + type above AND skin.css's [data-skin='foundry'] h1..h4 rule
   (one attribute + type) on specificity alone, so this wins regardless of
   file load order without an !important anywhere. Colors read the site's
   own tokens (--ocf-heading / --ocf-border-light via header.php's
   --color-heading / --color-border-light) rather than the reference's
   literal hex, so every brand palette keeps working.
   ============================================================ */
.ocf-detail-content .prose,
.ocf-detail__content .prose {
    color: var(--ocf-heading); /* darkest ink token, not the muted --ocf-body this container inherited before */
}
.ocf-detail-content .prose h2,
.ocf-detail__content .prose h2 {
    margin: 48px 0 16px;
    font-size: 30px;
    font-weight: 600;
    line-height: 1.22;
    text-transform: none;
}
.ocf-detail-content .prose > h2,
.ocf-detail__content .prose > h2 {
    /* same child-combinator specificity trick as the 2026-09-03 block above --
       restates margin-top so an intervening bare ".prose h2" rule (any skin
       or future pack) can never win it back on source order. */
    margin-top: 48px;
}
.ocf-detail-content .prose h3,
.ocf-detail__content .prose h3 {
    margin: 36px 0 12px;
    font-size: 23px;
    font-weight: 600;
    line-height: 1.2;
    text-transform: none;
}
.ocf-detail-content .prose p {
    margin: 0 0 18px;
    font-size: 18px;
    font-weight: 400;
    line-height: 1.72;
}
.ocf-detail-content .prose ul,
.ocf-detail-content .prose ol,
.ocf-detail__content .prose ul,
.ocf-detail__content .prose ol {
    margin: 16px 0 22px;
    padding-left: 27px;
}
.ocf-detail-content .prose li,
.ocf-detail__content .prose li {
    margin-bottom: 9px;
    font-size: 18px;
    font-weight: 400;
    line-height: 1.68;
}
.ocf-detail-content .prose li::marker,
.ocf-detail__content .prose li::marker {
    color: var(--ocf-heading);
}
.ocf-detail-content .prose strong,
.ocf-detail__content .prose strong {
    font-weight: 700;
    color: var(--ocf-heading);
}
/* Reference shows a real visible divider above each section h2 (the
   2026-09-03 block's hr display:none above is now overridden here for the
   detail content column only -- About's rich-text story still gets no
   divider, unchanged). */
.ocf-detail-content .prose hr,
.ocf-detail__content .prose hr {
    display: block;
    margin: 34px 0;
    border: 0;
    border-top: 1px solid var(--ocf-border-light);
}

/* Sidebar "book now" card (detail-page.css's .ocf-detail-sticky-*): the
   heading was wrapping awkwardly at --font-h3-size (20px) in a 320px-wide
   card at some sites' brand-token sizes -- restated as an explicit,
   slightly smaller literal so it never inherits a per-site
   --ocf-font-h3-size override. Button + phone row untouched. */
.ocf-detail-sticky-heading {
    font-size: 1.25rem; /* 20px */
    line-height: 1.3;
}
.ocf-detail-sticky-desc {
    font-size: 0.9375rem; /* 15px, was --font-label-size (16px) */
}

/* HTML sitemap page (page-sitemap.php, /sitemap/) -- plain heading + link
   list per page type. No new tokens: reuses --ocf-primary for the link
   color (same accent every other in-body link on this pack uses) and the
   existing card-radius/spacing rhythm via simple margins, nothing novel. */
.ocf-sitemap-page {
    max-width: 48rem;
}
.ocf-sitemap-group + .ocf-sitemap-group {
    margin-top: 2.5rem;
}
.ocf-sitemap-list {
    list-style: none;
    margin: 1rem 0 0;
    padding: 0;
    display: grid;
    gap: 0.625rem;
}
.ocf-sitemap-list a {
    color: var(--ocf-primary);
    text-decoration: none;
}
.ocf-sitemap-list a:hover,
.ocf-sitemap-list a:focus-visible {
    text-decoration: underline;
}

/* ---------- Reduced motion: every effect above still WORKS, it just snaps
   instead of animating (component-menu.html's own ".is-still" idiom) ---------- */
@media (prefers-reduced-motion: reduce) {
    .nav-bar,
    .nav-inner,
    .btn-primary,
    .btn-primary svg,
    .ultimate-b1-btn,
    .ultimate-b1-arrow,
    .hero-form-card .form-submit-btn,
    .btn-outline,
    .btn-outline::before,
    .ocf-cta .ocf-cta__phone,
    .ultimate-f1-field label,
    .ultimate-f1-field input,
    .ultimate-f1-field textarea,
    .ocf-svc-card,
    .ocf-svc-card-body h3::after,
    .ocf-faq-answer {
        transition: none !important;
    }
    .btn-primary:hover,
    .btn-primary:focus-visible,
    .ultimate-b1-btn:hover,
    .ultimate-b1-btn:focus-visible,
    .hero-form-card .form-submit-btn:hover,
    .ocf-svc-card:hover {
        transform: none !important;
    }
}
