/*
 * Single product page - styles.
 *
 * Lifted out of woocommerce/single-product.php on 30 Jul 2026. The block was
 * 58 KB of CSS, byte-identical on all 1,133 product pages and printed inline on
 * every one of them, so no browser could ever cache it. As a file it is fetched
 * once and reused, and the template drops to a size a person can read.
 *
 * Colour lives in tokens.css. Nothing in this file paints a literal colour
 * inside a rule any more - every value is either a semantic token or one of
 * the local properties below, so a dark variant needs to override one block
 * rather than hunt through 2,600 lines.
 *
 * The exceptions are marked where they appear: Klarna's pink and near-black
 * are that company's brand, not ours, and the design system says external
 * brands are not restyled.
 */

/* ==========================================================================
   FIXFACTOR SINGLE PRODUCT TEMPLATE v5.7 - SEO OPTIMIZED
   ========================================================================== */

/*
 * Local properties.
 *
 * Colours that the design system already names point at it, so this page moves
 * with the rest of the site - and, when a dark variant lands in tokens.css,
 * moves with that too for free. Rules keep using var(--ff-*), so pointing the
 * alias is a nine-line change rather than 2,600 lines of find-and-replace.
 *
 * The handful with no counterpart stay literal here, in one block, and are
 * marked. They are candidates for the design system, not for this file - but
 * tokens.css is copied verbatim from the design system and is not edited here.
 */
:root {
  /* --- Aliases onto the design system ----------------------------------- */
  --ff-brand-light: var(--chrome-fill-hover);
  --ff-gray-50: var(--surface-alt);
  --ff-gray-200: var(--border-neutral);
  --ff-gray-300: var(--border-neutral);
  --ff-gray-500: var(--content-secondary);
  --ff-gray-600: var(--content-secondary);
  --ff-gray-900: var(--content-body);
  --ff-placeholder: var(--content-secondary);
  --ff-divider: var(--border-neutral);
  --ff-divider-text: var(--content-secondary);
  --ff-trustpilot-green: var(--trustpilot);
  --ff-brand-light-hover: var(--chrome-fill-faint);
  --ff-tile-border: var(--chrome-border);
  --ff-fill: var(--surface-fill);
  --ff-radius: var(--radius-input);

  /* These three were only ever declared as var() fallbacks, which means the
     fallback always applied and the value could not follow the register.
     Declared properly now; the fallbacks downstream become dead weight. */
  --hair: var(--wash-brand);
  --card-border: var(--border-interactive);
  --tile-border: var(--chrome-border);

  /* --- Local names, system values (v4.6, dark mode Phase 2) --------------
     These five used to be literals with the note "no counterpart in the design
     system yet". Four now have one; the fifth is a pair declared here because
     it is this file's alone. */
  --ff-gray-100: light-dark(#e9ecef, var(--ink-850));   /* one step between surface-alt and border-neutral */
  --ff-accent-light: var(--surface-warm);               /* amber tint */
  --ff-note-fill: var(--surface-warm-deep);             /* amber tint, note boxes */
  --ff-badge-subtitle: light-dark(#3d6b72, var(--teal-300));  /* muted teal, selected badge subtitle */
  --ff-fill-hover: light-dark(#eaeaea, var(--ink-850)); /* modal close button, hover */

  /* --- Black-with-alpha: shadows, scrims, tooltip fills ------------------
     Named rather than inlined because these are the values a dark variant has
     to replace with a different technique, not a different colour: a black
     shadow is invisible on a dark surface. One block to override. */
  --ff-shadow-xs: light-dark(rgba(0, 0, 0, 0.04), rgba(0, 0, 0, 0.4));
  --ff-shadow-sm: var(--shadow-colour);
  --ff-shadow-md: var(--shadow-colour-lg);
  --ff-hairline: var(--overlay-soft);
  --ff-scrim: var(--overlay-scrim);
  --ff-focus-glow: var(--wash-warm);

  /* --- Geometry and scale ------------------------------------------------ */
  --ff-border-width: 1px;
  --ff-border-width-thick: 2px;

  --ff-space-xs: 4px;
  --ff-space-sm: 8px;
  --ff-space-md: 12px;
  --ff-space-lg: 16px;
  --ff-space-xl: 20px;
  --ff-space-2xl: 24px;
  --ff-space-3xl: 30px;
  --ff-space-4xl: 40px;
  --ff-space-5xl: 48px;
  --ff-space-6xl: 60px;

  --ff-font-xs: 11px;
  --ff-font-sm: 12px;
  --ff-font-md: 14px;
  --ff-font-lg: 16px;
  --ff-font-xl: 18px;
  --ff-font-2xl: 20px;
  --ff-font-3xl: 24px;
  --ff-font-4xl: 28px;
  --ff-font-5xl: 32px;
  --ff-font-6xl: 36px;
}

/* Reset and Base Styles - Modified to use grid layout for consistent sidebar positioning */
.fixfactor-product {
    max-width: 1140px;
    margin: 0 auto;
    padding: 25px var(--ff-space-xl) var(--ff-space-5xl) var(--ff-space-xl);
    font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif;
    color: var(--content);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    display: grid;
    grid-template-columns: 2fr 1.2fr;
    gap: 0 var(--ff-space-6xl);
    grid-template-rows: auto 1fr;
}

/* ============================================================================
/* Typography and Content */
.fixfactor-content-area h1,
.fixfactor-content-area h2,
.fixfactor-content-area h3,
.fixfactor-content-area h4,
.fixfactor-content-area h5,
.fixfactor-content-area h6 {
    color: var(--content);
    font-weight: 600;
    margin: 1.5em 0 0.5em 0;
    line-height: 1.3;
    letter-spacing: -0.01em;
}

.fixfactor-content-area h1 { font-size: var(--ff-font-4xl); }
.fixfactor-content-area h2 { font-size: var(--ff-font-3xl); }
.fixfactor-content-area h3 { font-size: var(--ff-font-2xl); }
.fixfactor-content-area h4 { font-size: var(--ff-font-xl); }
.fixfactor-content-area h5 { font-size: var(--ff-font-lg); }
.fixfactor-content-area h6 { font-size: var(--ff-font-md); }

.fixfactor-content-area p {
    margin: 0 0 1.2em 0;
    line-height: 1.7;
    color: var(--content);
}

.fixfactor-content-area ul,
.fixfactor-content-area ol {
    margin: 1em 0;
    padding-left: 1.5em;
    color: var(--content);
}

.fixfactor-content-area li {
    margin-bottom: 0.5em;
    line-height: 1.6;
}

.fixfactor-content-area strong,
.fixfactor-content-area b {
    font-weight: 600;
    color: var(--content);
}

.fixfactor-content-area em,
.fixfactor-content-area i {
    font-style: italic;
}

.fixfactor-content-area a {
    color: var(--action);
    text-decoration: none;
    transition: color 0.2s ease;
}

.fixfactor-content-area a:hover {
    color: var(--action-hover);
    text-decoration: underline;
}

.fixfactor-content-area blockquote {
    background: var(--ff-gray-50);
    border-left: 3px solid var(--content);
    margin: 1.5em 0;
    padding: 1em 1.5em;
    border-radius: 0;
}

.fixfactor-content-area img {
    max-width: 100%;
    height: auto;
    border-radius: var(--ff-radius);
    margin: 1em 0;
}

.fixfactor-content-area pre,
.fixfactor-content-area code {
    background: var(--ff-gray-50);
    border-radius: var(--ff-radius);
    font-family: 'SF Mono', 'Monaco', 'Courier New', monospace;
    padding: 2px 6px;
    font-size: 90%;
}

.fixfactor-content-area pre {
    padding: 1em;
    overflow-x: auto;
    margin: 1em 0;
}

/* Form Styling */
.fixfactor-content-area .wpforms-container,
.fixfactor-content-area .wpforms-form {
    margin: 0;
}

.fixfactor-content-area .wpforms-field {
    margin-bottom: 6px;
}

/* WPForms Styling - Combined selectors for specificity against both Avada and WPForms defaults */
.fixfactor-content-area .wpforms-field input,
.fixfactor-content-area .wpforms-field select,
.fixfactor-content-area .wpforms-field input[type="text"],
.fixfactor-content-area .wpforms-field input[type="email"],
.fixfactor-content-area .wpforms-field input[type="tel"],
.fixfactor-content-area .wpforms-field input[type="number"],
div.wpforms-container-full .wpforms-form input[type="text"],
div.wpforms-container-full .wpforms-form input[type="email"],
div.wpforms-container-full .wpforms-form input[type="tel"],
div.wpforms-container-full .wpforms-form input[type="number"],
div.wpforms-container-full .wpforms-form select {
    width: 100% !important;
    padding: 14px var(--ff-space-md) !important;
    min-height: 47px !important;
    border: 1.5px solid var(--content-secondary) !important;
    border-radius: 9px !important;
    background: var(--surface) !important;
    font-size: 14px !important;
    color: var(--content) !important;
    line-height: 1.4 !important;
    transition: border-color 0.2s ease !important;
    font-family: inherit !important;
    -webkit-appearance: none !important;
    -moz-appearance: none !important;
    appearance: none !important;
}

.fixfactor-content-area .wpforms-field textarea,
div.wpforms-container-full .wpforms-form textarea {
    width: 100% !important;
    padding: 14px var(--ff-space-md) !important;
    border: 1.5px solid var(--content-secondary) !important;
    border-radius: 9px !important;
    background: var(--surface) !important;
    font-size: 14px !important;
    color: var(--content) !important;
    line-height: 1.4 !important;
    transition: border-color 0.2s ease, border-width 0.2s ease !important;
    font-family: inherit !important;
    -webkit-appearance: none !important;
    -moz-appearance: none !important;
    appearance: none !important;
}

.fixfactor-content-area .wpforms-field input::placeholder,
.fixfactor-content-area .wpforms-field textarea::placeholder,
div.wpforms-container-full .wpforms-form input::placeholder,
div.wpforms-container-full .wpforms-form textarea::placeholder {
    color: var(--content-secondary) !important;
    opacity: 1 !important;
}

.fixfactor-content-area .wpforms-field input:focus,
.fixfactor-content-area .wpforms-field select:focus,
.fixfactor-content-area .wpforms-field textarea:focus,
div.wpforms-container-full .wpforms-form input:focus,
div.wpforms-container-full .wpforms-form select:focus,
div.wpforms-container-full .wpforms-form textarea:focus {
    outline: none !important;
    border: 2px solid var(--accent) !important;
    box-shadow: none !important;
}

.fixfactor-content-area .wpforms-field label {
    font-weight: 600;
    color: var(--content);
    margin-bottom: 6px;
    display: block;
    font-size: 13px;
}

.fixfactor-content-area .wpforms-submit-container {
    margin-top: var(--ff-space-md);
    text-align: center;
    padding-top: 10px;
    padding-bottom: 10px;
}

.fixfactor-content-area .wpforms-submit {
    background: var(--action) !important; /* WCAG AA - white text on var(--accent) fails contrast */
    color: var(--on-action) !important;
    border: none !important;
    padding: 18px 24px !important;
    border-radius: var(--ff-radius) !important;
    font-size: 15px !important;
    font-weight: 700 !important;
    cursor: pointer !important;
    transition: all 0.2s ease !important;
    font-family: inherit !important;
    min-height: 52px !important;
    width: 100% !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    box-shadow: none !important;
}

.fixfactor-content-area .wpforms-submit:hover {
    background: var(--action-hover) !important;
    transform: scale(1.015) !important;
}

/* Layout - Grid wrapper uses display: contents to flatten into parent grid */
.fixfactor-product-grid {
    display: contents;
}

/* Left Column - Basic styles */
.fixfactor-left-column {
    display: block;
    grid-column: 1;
    grid-row: 2;
    margin-top: var(--ff-space-md);
}

/* Product Header */
.fixfactor-product-header {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 0;
    grid-column: 1;
    grid-row: 1;
}

/* Product title container - allow full width of left column */
.fixfactor-product-title {
    max-width: 100%; /* Use full width available in grid column */
}

/* Service Title with Icon (Variant A - Simple Inline) */
.fixfactor-title-with-icon {
    display: flex;
    align-items: flex-start;
    gap: 18px;
}

.fixfactor-service-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--accent);
    line-height: 1;
    margin-top: 6px;
    /* Circle outline frame */
    width: 78px;
    height: 78px;
    border-radius: 50%;
    background: var(--surface);
    border: 3px solid var(--accent);
}

/* 56, not 67: the redrawn icon set (8 Aug 2026) sits inside 2..22 of a 24
   grid, where the drawings it replaces filled about 60% of their box. Same
   declared circle, same optical size for the drawing inside it. */
.fixfactor-service-icon svg {
    width: 56px;
    height: 56px;
    display: block;
}

.fixfactor-title-content {
    flex: 1;
    min-width: 0;
    padding-top: 4px;
}

.fixfactor-title-content h1 {
    margin: 0;
    line-height: 1.15;
}

.fixfactor-title-content .fixfactor-hero-ratings {
    margin-top: 10px;
}


/* Hero Ratings - Review Badges */
.fixfactor-hero-ratings {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    margin-top: var(--ff-space-sm);
    margin-bottom: 0;
    padding: 0;
    margin-left: -2px;
    padding-right: 0; /* Remove padding - grid handles spacing from sidebar */
}

.fixfactor-rating-badge {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    text-decoration: none;
    transition: opacity 0.2s ease;
}

.fixfactor-rating-badge:hover {
    opacity: 0.8;
}

.fixfactor-rating-logo {
    width: 13px;
    height: 13px;
    flex-shrink: 0;
}

.fixfactor-rating-stars {
    display: flex;
    gap: 0;
}

.fixfactor-rating-stars-trustpilot {
    display: flex;
    gap: 2px;
}

.fixfactor-rating-star {
    width: 15px;
    height: 15px;
    fill: var(--accent-warm);
}

.fixfactor-rating-star-box {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 12px;
    height: 12px;
    background: var(--ff-trustpilot-green);
    border-radius: 2px;
}

.fixfactor-rating-star-box .fixfactor-rating-star {
    width: 8px;
    height: 8px;
    fill: white;
}

.fixfactor-rating-number {
    font-size: 0.8125rem;
    font-weight: 700;
    color: var(--content);
    line-height: 1;
    margin-left: 0.25rem;
}

.fixfactor-rating-text {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--content);
    line-height: 1;
}

.fixfactor-rating-divider {
    display: none;
}


.fixfactor-product-title h1 {
    font-family: var(--font-stack);
    font-size: 34px;
    font-weight: 700;
    margin: 0;
    color: var(--content);
    letter-spacing: -0.02em;
    margin-left: -4px;
    line-height: 1.2;
}

/* Title Separator - Removed, replaced by service icons */

/* Short Description - Desktop */
.fixfactor-short-description {
    background: var(--surface);
    padding: 0 var(--ff-space-2xl) 10px 0;
    border-radius: var(--ff-radius);
    margin-top: calc(var(--ff-space-lg) + 5px); /* 16px + 5px extra spacing from reviews */
    margin-bottom: var(--ff-space-sm);
    border: none;
}

#ff-sp .fixfactor-short-description p {
    color: var(--content);
}

/* Trust Badges - Outlined Cards */
.fixfactor-badges {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 8px;
    margin-top: var(--ff-space-lg);
    margin-bottom: var(--ff-space-3xl);
}

.fixfactor-badge {
    background: var(--surface);
    border: 1.5px solid var(--ff-tile-border);
    border-radius: var(--ff-radius);
    padding: 10px 8px 10px 12px;
    text-align: left;
}

.fixfactor-badge-title {
    font-size: 14px;
    font-weight: 700;
    color: var(--action);
    display: block;
    margin: 0 0 2px 0;
    letter-spacing: -0.01em;
    line-height: 1.1;
}

.fixfactor-badge-subtitle {
    font-size: 11px;
    color: var(--content-secondary);
    display: block;
    font-weight: 500;
    line-height: 1.2;
}

.fixfactor-badge a {
    color: var(--action);
    text-decoration: none;
}

.fixfactor-badge a:hover {
    color: var(--action-hover);
    text-decoration: underline;
}

/* Sticky Sidebar - Spans both grid rows with fixed top offset for consistent alignment */
#ff-sp.fixfactor-no-price .fixfactor-sticky-sidebar {
    position: sticky;
    /* 5px of gap, below the 44px the sticky trail now occupies. */
    top: 49px;
    background: var(--surface);
    border-radius: 11px;
    padding: 0 5px;
    border: 5px solid var(--accent-warm);
    height: fit-content;
    grid-column: 2;
    grid-row: 1 / 3;
    align-self: start;
    margin-top: 8px; /* Aligned with title (no SERVICE badge) */
}

#ff-sp .fixfactor-sticky-sidebar {
    position: sticky;
    top: 49px;
    background: var(--surface);
    border-radius: 11px;
    padding: 0 5px;
    border: 2.5px solid var(--accent);
    height: fit-content;
    grid-column: 2;
    grid-row: 1 / 3;
    align-self: start;
    margin-top: 8px; /* Aligned with title (no SERVICE badge) */
}

/* Price Section */
#ff-sp .fixfactor-price-section {
    text-align: left;
    margin-bottom: 0;
    padding: 24px;
    position: relative;
    border: none;
    background: var(--surface);
}

.fixfactor-price-container {
    position: relative;
    margin-top: 0;
}

.fixfactor-price-row {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: var(--ff-space-md);
    margin-bottom: 0;
}

.fixfactor-price {
    font-family: var(--font-stack);
    font-size: 32px;
    font-weight: 700;
    color: var(--content);
    letter-spacing: -0.02em;
    transition: all 0.2s ease;
}

.fixfactor-price.range {
    font-size: var(--ff-font-4xl);
}

/* Negotiate Button - Inline with price */
.fixfactor-negotiate-btn {
    background: var(--surface);
    color: var(--content);
    /* 2px of yellow made the tag the loudest thing under the price. */
    border: 1.5px solid var(--accent-warm);
    padding: 5px 13px;
    border-radius: var(--ff-radius);
    font-size: var(--ff-font-xs);
    font-weight: 600;
    cursor: pointer;
    /* Named properties rather than `all`: `all` also animates the border and
       forces a layout pass on every hover. */
    transition: background-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
    text-transform: none;
    letter-spacing: 0;
    white-space: nowrap;
    flex-shrink: 0;
}

/* Fills rather than grows. Scaling nudged the icons beside it and read as a
   jump; a fill plus a 1px rise stays inside the tag's own box. */
.fixfactor-negotiate-btn:hover {
    background: var(--accent-warm);
    transform: translateY(-1px);
    box-shadow: 0 3px 10px var(--wash-warm-strong);
}

.fixfactor-negotiate-btn:active {
    transform: translateY(0);
    box-shadow: none;
}

/* Enhanced focus management for accessibility */
.fixfactor-negotiate-btn:focus-visible,
.fixfactor-variation-item:focus-visible,
.fixfactor-service-option:focus-visible,
.mobile-service-option:focus-visible,
.fixfactor-main-cta:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Price Animation */
@keyframes priceUpdate {
    0% { opacity: 0.7; }
    50% { opacity: 1; }
    100% { opacity: 1; }
}

.fixfactor-price.animate {
    animation: priceUpdate 0.3s ease-in-out;
}

/* Payment Methods */
.fixfactor-payment-methods {
    margin: 4px -24px 0 -24px;
    padding: 0 24px var(--ff-space-lg) 27px;
    border-bottom: 2.5px solid var(--accent);
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

/* Negotiate Button - moves to payment row */
.fixfactor-payment-methods .fixfactor-negotiate-btn {
    margin-left: auto;
}

.payment-card-icon {
    /* Width follows the viewBox ratio, so one number keeps the set aligned. */
    height: 20px;
    width: auto;
    display: block;
    flex: 0 0 auto;
}

/*
 * Klarna's own pink and near-black. The design system lists external brands as
 * do-not-restyle, so these two stay literal - the one pair of colours in this
 * file that must not follow our palette, in light mode or dark.
 */
.payment-badge.klarna {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Same height and radius as the cards, so the four read as one set
       rather than three cards and a sticker. Klarna's wordmark is lowercase;
       the old rule shouted it in uppercase at 900 weight. */
    height: 20px;
    padding: 0 7px;
    background: #FFA8CD;
    color: #0B051D;
    font-size: 9px;
    font-weight: 700;
    text-transform: none;
    letter-spacing: 0;
    border-radius: 2.5px;
    flex: 0 0 auto;
}

/* Variations - Unified Service Style */
#ff-sp .fixfactor-variations {
    margin-bottom: 0;
    padding: 10px 24px 0 24px;
    border: none;
    background: var(--surface);
}

.fixfactor-variation-group {
    margin-bottom: var(--ff-space-xl);
    text-align: left;
}

.fixfactor-variation-group .fixfactor-variation-group-label {
    font-size: 14px;
    font-weight: 600;
    margin-top: 0;
    margin-bottom: 12px;
    color: var(--content);
    opacity: 0.7;
    text-align: left;
}

/*
 * Variation badges.
 *
 * auto-fill, not auto-fit. auto-fit collapses the empty tracks on the last
 * row, so a group with an odd number of options ended with one badge stretched
 * across the full width - the ragged item at the bottom of every other group.
 * auto-fill keeps the track, so the last badge is the same width as the rest.
 */
.fixfactor-variation-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: var(--ff-space-sm);
    padding-left: 0;
    text-align: left;
}

.fixfactor-variation-item {
    background: var(--surface);
    border: 1px solid var(--ff-tile-border);
    border-radius: var(--ff-radius);
    padding: 10px 14px;
    cursor: pointer;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.fixfactor-variation-item:hover {
    border-color: var(--accent);
}

.fixfactor-variation-item.selected {
    border-color: var(--accent);
    box-shadow: inset 0 0 0 1px var(--accent);
    background: transparent;
}

.fixfactor-variation-item input[type="radio"] {
    display: none;
}

.fixfactor-variation-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--content);
    line-height: 1.3;
    text-align: left;
}

.fixfactor-variation-item.selected .fixfactor-variation-title {
    color: var(--action);
}

.fixfactor-variation-info-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    border: 1.5px solid var(--border-interactive);
    border-radius: 50%;
    background: transparent;
    color: var(--accent);
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
    flex-shrink: 0;
    font-style: normal;
    font-family: inherit;
}

.fixfactor-variation-info-trigger::after {
    content: "?";
}

.fixfactor-variation-info-trigger svg {
    display: none;
}

/* Gentle Reminder Pulsing */
@keyframes gentleReminder {
    0%, 100% { 
        background: transparent;
    }
    50% { 
        background: var(--ff-brand-light);
    }
}

.fixfactor-service-option {
    background: var(--surface);
    border: 1px solid var(--ff-tile-border);
    border-radius: var(--ff-radius);
    padding: 12px 16px;
    cursor: pointer;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--ff-space-md);
}

.fixfactor-service-option:hover {
    border-color: var(--accent);
}

.fixfactor-service-option.selected {
    border-color: var(--accent);
    box-shadow: inset 0 0 0 1px var(--accent);
    background: transparent;
}

.fixfactor-service-option input[type="radio"] {
    display: none;
}

.fixfactor-info-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    border: 1.5px solid var(--border-interactive);
    border-radius: 50%;
    background: transparent;
    color: var(--accent);
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
    flex-shrink: 0;
    font-style: normal;
    font-family: inherit;
}

.fixfactor-info-trigger::after {
    content: "?";
}

.fixfactor-info-trigger svg {
    display: none;
}

/* Shared floating tooltip (appended to body) */
.fixfactor-floating-tooltip {
    position: fixed;
    background: var(--content);
    color: var(--surface);
    font-size: 12px;
    font-weight: 400;
    line-height: 1.4;
    padding: 8px 12px;
    border-radius: 6px;
    max-width: 220px;
    white-space: normal;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.15s ease, visibility 0.15s ease;
    z-index: 999999;
    pointer-events: none;
    box-shadow: 0 4px 12px var(--ff-shadow-md);
}

/* Mobile service info trigger */
.mobile-service-desc {
    display: none;
}

.mobile-service-title-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
}

.mobile-info-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 13px;
    height: 13px;
    border: 1px solid var(--accent);
    border-radius: 50%;
    color: var(--accent);
    font-size: 9px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    flex-shrink: 0;
    font-style: italic;
    font-family: Georgia, 'Times New Roman', serif;
}

.mobile-info-trigger::after {
    content: "i";
}

.mobile-info-trigger svg {
    display: none;
}

/* CTA Buttons */
#ff-sp .fixfactor-cta-section {
    margin-bottom: 0;
    padding: 24px;
    border: none;
    background: var(--surface);
}

.fixfactor-main-cta {
    width: 100%;
    background: var(--action); /* WCAG AA - white text on var(--accent) fails contrast */
    color: var(--on-action);
    border: none;
    padding: var(--ff-space-xl) var(--ff-space-2xl);
    border-radius: var(--ff-radius);
    font-size: var(--ff-font-lg);
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s ease;
    margin-bottom: var(--ff-space-md);
    opacity: 1;
    pointer-events: auto;
    box-shadow: none;
}

.fixfactor-main-cta.active:hover {
    background: var(--action-hover);
    transform: scale(1.015);
}

.fixfactor-main-cta.disabled {
    opacity: 0.4;
    cursor: not-allowed;
    background: var(--ff-gray-300);
    box-shadow: none;
}

.fixfactor-main-cta.disabled:hover {
    transform: none;
    box-shadow: none;
}

/* Conditional Info Bar - 20px SVG icons, transparent bg, updates on service change */
.fixfactor-conditional-info {
    background: transparent;
    border: none;
    padding: var(--ff-space-md) 0;
    border-radius: 0;
    font-size: var(--ff-font-sm);
    font-weight: 400;
    color: var(--ff-gray-600);
    text-align: left;
    display: flex;
    align-items: center;
    gap: var(--ff-space-sm);
    transition: all 0.3s ease;
}

.fixfactor-conditional-info .status-icon {
    color: var(--accent);
    flex-shrink: 0;
    opacity: 0.7;
}

.fixfactor-conditional-info-content {
    flex: 1;
    line-height: 1.4;
}

.fixfactor-conditional-info.show {
    display: flex;
}

/* The block sets display:flex from a class, which beats the browser's own rule
   for [hidden], so hiding it from script needs saying here. It has to be
   hideable: diagnostics and water damage carry their note in the product's
   short description instead, and without this the line would stay on screen as
   an icon with nothing beside it. */
.fixfactor-conditional-info[hidden] {
    display: none;
}

/* Micro-copy animation */
@keyframes fadeInUp {
    from {
        opacity: 0;
        transform: translateY(5px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.fixfactor-conditional-info.animate {
    animation: fadeInUp 0.3s ease-out;
}

/* Product Description - Variant #1 Style */
#ff-sp section.fixfactor-description {
    margin-top: var(--ff-space-3xl);
    position: relative;
}

/* Sibling repairs - "Other iPhone 15 repairs". Same row idiom as the service
   list on the model page, so the two lists read as one system. Positioned so
   it sits above the PCB decoration that bleeds out of the section above. */
#ff-sp section.fixfactor-related {
    margin-top: var(--ff-space-3xl);
    position: relative;
    z-index: 1;
}

#ff-sp .ffrr-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 10px;
}

#ff-sp .ffrr-link {
    /* Single compact row: name left, price right. Equal-width grid cards and
       tabular figures keep the price column visually aligned; the row form
       keeps each card one line tall. */
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    border: 1px solid var(--ff-tile-border);
    border-radius: var(--radius, 12px);
    background: var(--surface);
    color: var(--content);
    text-decoration: none;
    transition: border-color 0.18s ease, background 0.18s ease;
}

#ff-sp .ffrr-link:hover,
#ff-sp .ffrr-link:focus-visible {
    border-color: var(--accent);
    background: var(--surface-alt);
}

#ff-sp .ffrr-name {
    font-weight: 600;
    font-size: 0.95rem;
    line-height: 1.35;
}

#ff-sp .ffrr-price {
    font-weight: 700;
    font-size: 0.85rem;
    color: var(--action);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

#ff-sp .ffrr-from {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--content-secondary);
}

#ff-sp .ffrr-quote {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--content-secondary);
    white-space: nowrap;
}

/* Guides from our workshop — same row idiom as the sibling-repairs list.
   Thumbnail plus title; the whole card is the link, so no separate read
   affordance. Second heading inside the shared .fixfactor-related section
   gets its own breathing room. */
#ff-sp .ffrg-heading {
    margin-top: 40px;
}

#ff-sp .ffrg-link {
    /* Guides keep the horizontal arrangement: thumbnail beside title. */
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: 12px;
}

#ff-sp img.ffrg-thumb {
    width: 52px;
    height: 52px;
    border-radius: 8px;
    object-fit: cover;
    flex: none;
}

/* PCB board decoration - brand signature, same idiom as Homepage (#ff-pcb-board).
   Background layer only: low opacity, no pointer events, never over interactive UI */
#ff-sp .fixfactor-pcb-decoration {
    position: absolute;
    bottom: -24px;
    right: -20px;
    width: 340px;
    height: auto;
    opacity: 0.08;
    pointer-events: none;
    z-index: 0;
}

#ff-sp .fixfactor-description-content {
    position: relative;
    z-index: 1;
}

#ff-sp .fixfactor-description-header {
    font-size: 20px;
    font-weight: 700;
    margin-bottom: 15px;
    padding-bottom: 0;
    padding-left: 12px;
    border-bottom: none;
    border-left: 3px solid var(--accent);
    color: var(--content);
    text-transform: none;
    letter-spacing: -0.3px;
}

#ff-sp .fixfactor-description-content {
    background: transparent;
    padding: 0;
    border: none;
    border-radius: 0;
}

/* ---------------------------------------------------------------------------
   MEASURE, 24.08.2026.

   The column is 752px and the prose had no cap, so a paragraph in Service
   Details ran to 94 characters a line - measured, at 1440. Comfortable is
   45-75. Past about 80 the eye starts losing the return to the next line, and
   the page reads as "too wide" even though the shell (1140px) is already the
   narrowest on the site: the header is 1290, the funnel pages 1320.

   First attempt capped the paragraphs, the lists and the callouts one by one,
   and it looked worse than the problem: paragraphs at 544, callouts at 546,
   the photograph at 500 and the headings still at 752, so the section had four
   different right edges and read as broken rather than as set. A text column
   only looks deliberate when EVERYTHING in it shares one edge.

   So the constraint sits on the section instead, and every child inherits it.
   620px is 77 characters at 16px - the top of the comfortable band rather than
   the middle, chosen because the alternative starves a column that also has to
   hold photographs and callouts. Measured alternatives: 752 = 94ch (as was),
   700 = 87ch, 660 = 82ch, 620 = 77ch.

   The fulfilment block is a sibling section, so it keeps the full 752px. Cards
   earn their width; running prose does not.

   Value in px, not ch: the CSS ch unit is the width of the "0" glyph, and in
   this font a zero is about a quarter wider than the average character in
   running text - 68ch measured out at 86 real characters, not 68.

   REVERSED FOR SERVICE DETAILS, 4.09.2026 (owner's call).

   The reasoning above is about one edge inside the section, and it got that.
   What it did not weigh is the edge BETWEEN sections: Service Details stopped
   at 790px while Other Repairs and Guides From Our Workshop, its siblings in
   the same column, ran to 922px. Measured at 1440. So the fix that made one
   section look set made the column look ragged, which is the more visible of
   the two faults because the sections sit one under another.

   Service Details takes the column again. The token stays because the short
   description in the ffc layout still uses it, and the line length that
   prompted this is a real cost: back to about 94 characters at 1440, against a
   comfortable 45-75.
   --------------------------------------------------------------------------- */
#ff-sp { --ff-measure: 620px; }

/* Below 768 the body drops to 14px (a pre-existing decision, not this one),
   which puts 87 characters back on the same 620px line - worse than the
   desktop it was meant to fix. So the measure follows the type down. It cannot
   be expressed in em: the 14px rule targets the paragraphs, while the cap sits
   on the section, and em there would resolve against the section's own 16px.
   Below about 600 the column is already narrower than this, so it stops
   applying on its own. */
@media (max-width: 768px) {
    #ff-sp { --ff-measure: 540px; }
}

.fixfactor-info-buttons {
    display: flex;
    gap: var(--ff-space-md);
    margin-top: var(--ff-space-xl);
}

#ff-sp .fixfactor-info-button {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 12px 20px;
    background: var(--surface);
    color: var(--action);
    text-decoration: none;
    border-radius: 8px;
    border: 2px solid var(--accent);
    font-weight: 600;
    font-size: var(--ff-font-md);
    transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

/*
 * Fills on hover, the same way .fixfactor-negotiate-btn does.
 *
 * This used to be transform: scale(1.02). The button is flex:1 and already
 * fills the row, so the 2% had nowhere to go: it put the box at x 166.81 with
 * width 325.38, and Chromium dropped the left border and both left corners
 * when rasterising that fractional geometry against a 2px border and an 8px
 * radius. Confirmed at 4x - nothing was clipping it, every ancestor is
 * overflow: visible.
 *
 * White on --action, not --accent: white on --accent fails contrast, as the
 * comment on the CTA in this file already records.
 */
#ff-sp .fixfactor-info-button:hover {
    background: var(--action);
    color: var(--on-action);
    border-color: var(--action);
    text-decoration: none;
}

/* Service Details fallback - shown when a product has no long description */
#ff-sp .ff-sd {
    padding: var(--ff-space-xl) 0 0;
}

#ff-sp .ff-sd p {
    margin: 0 0 var(--ff-space-md);
    font-size: var(--ff-font-md);
    line-height: 1.7;
    color: var(--content-body);
}

#ff-sp .ff-sd p.ff-sd-lead {
    font-size: var(--ff-font-lg);
    font-weight: 600;
    line-height: 1.55;
    color: var(--content);
    margin-bottom: var(--ff-space-lg);
}

#ff-sp .ff-sd p.ff-sd-close {
    margin-bottom: 0;
}

/* Prose links only. Scoped to p on purpose: an unscoped .ff-sd a rule has the
   same specificity as .fixfactor-info-button:hover and, sitting later in the
   file, was winning - the hovered button rendered dark teal text on a dark
   teal fill, 1.46:1. */
#ff-sp .ff-sd p a {
    color: var(--action);
    font-weight: 600;
    text-decoration: none;
}

#ff-sp .ff-sd p a:hover {
    color: var(--action-hover);
    text-decoration: underline;
}

/* Other repairs for the same device. This is the part of the block that is
   unique to the page - of 40 such pages sampled, none had an internal link
   pointing at them from any published post. */
#ff-sp .ff-sd-siblings {
    margin: var(--ff-space-xl) 0;
    padding: var(--ff-space-lg) var(--ff-space-xl);
    background: var(--surface-alt);
    border: 1px solid var(--chrome-border);
    border-radius: var(--ff-radius);
}

#ff-sp .ff-sd-siblings h3 {
    margin: 0 0 var(--ff-space-md);
    font-size: var(--ff-font-md);
    font-weight: 700;
    color: var(--content);
    letter-spacing: -0.1px;
}

#ff-sp .ff-sd-siblings ul {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ff-space-sm);
    margin: 0;
    padding: 0;
    list-style: none;
}

#ff-sp .ff-sd-siblings li {
    margin: 0;
    padding: 0;
}

#ff-sp .ff-sd-siblings a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 24px;
    padding: 7px 13px;
    background: var(--surface);
    border: 1px solid var(--chrome-border);
    border-radius: var(--radius-tag);
    font-size: 13px;
    font-weight: 600;
    color: var(--action);
    text-decoration: none;
    transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

#ff-sp .ff-sd-siblings a:hover {
    background: var(--action);
    border-color: var(--action);
    color: var(--on-action);
    text-decoration: none;
}

#ff-sp .ff-sd-siblings .ff-sd-price {
    font-weight: 400;
    opacity: 0.75;
}

@media (max-width: 768px) {
    #ff-sp .ff-sd-siblings {
        padding: var(--ff-space-md) var(--ff-space-lg);
    }

    #ff-sp .ff-sd p.ff-sd-lead {
        font-size: var(--ff-font-md);
    }
}

/*
 * On a phone no two chips fit on a line, so inline-flex produced a ragged
 * one-per-row column of mismatched widths. Full-width rows with the price
 * pushed right read as a price list instead - and a price list is the more
 * useful thing to hand someone comparing repairs on a phone.
 */
@media (max-width: 575px) {
    #ff-sp .ff-sd-siblings ul {
        display: grid;
        grid-template-columns: 1fr;
        gap: 6px;
    }

    #ff-sp .ff-sd-siblings a {
        justify-content: space-between;
        width: 100%;
        min-height: 44px;
        padding: 10px 14px;
    }

    #ff-sp .ff-sd-siblings .ff-sd-price {
        flex-shrink: 0;
        margin-left: var(--ff-space-md);
    }
}

/* Contact Form - Comic-Inspired Bold Design (Variant #7 Adapted) */
#ff-sp section.fixfactor-contact-form-wide {
    margin-top: 0;
    background: var(--surface);
    padding: 0;
    border-radius: 6px;
    position: relative;
    border: none;
}

#ff-sp .fixfactor-form-content {
    padding: 0 24px 24px 24px;
    background: var(--surface);
    border: none;
    border-radius: 0;
}

/* Modal */
.fixfactor-modal {
    display: none;
    position: fixed;
    z-index: 999999 !important; /* Avada override */
    left: 0;
    top: 0;
    width: 100vw;
    height: 100vh;
    background-color: var(--ff-scrim) !important;
    padding: 0;
    box-sizing: border-box;
    overflow-y: auto;
    align-items: center;
    justify-content: center;
}

.fixfactor-modal.show {
    display: flex !important;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    animation: ffModalFadeIn 0.25s ease;
}

@keyframes ffModalFadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes ffModalScaleIn {
    from { transform: scale(0.97); opacity: 0.6; }
    to { transform: scale(1); opacity: 1; }
}

.fixfactor-modal-wrapper {
    margin: auto;
    position: relative;
    width: 90%;
    max-width: 600px;
}

/* Unified close button - 32px circle inside the card, same on all breakpoints */
.fixfactor-modal-close {
    position: absolute;
    top: 14px;
    right: 14px;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    font-weight: 400;
    line-height: 1;
    color: var(--content);
    background: var(--ff-fill);
    border: 1px solid var(--border-neutral);
    border-radius: 50%;
    cursor: pointer;
    transition: background 0.2s ease;
    z-index: 1001;
}

.fixfactor-modal-close:hover {
    background: var(--ff-fill-hover);
}

.fixfactor-modal h3 {
    margin: 0;
    padding: 0;
    font-size: 28px;
    color: var(--content);
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.02em;
}

/* MOBILE OPTIMIZATIONS */
@media (max-width: 768px) {
    #ff-sp {
        padding: 18px 20px 25px 20px;
        display: block; /* Block layout for natural flow on mobile */
    }

    #ff-sp .fixfactor-product-grid {
        display: flex;
        flex-direction: column;
        gap: 0;
    }

    #ff-sp .fixfactor-product-header {
        gap: 12px;
        margin-bottom: var(--ff-space-sm);
        padding: 0;
        grid-column: unset;
        grid-row: unset;
    }

    #ff-sp .fixfactor-left-column {
        grid-column: unset;
        grid-row: unset;
        margin-top: 0;
    }

    #ff-sp .fixfactor-sticky-sidebar {
        grid-column: unset;
        grid-row: unset;
        margin-top: var(--ff-space-lg);
    }

    /* Service icon adjustments for mobile */
    .fixfactor-title-with-icon {
        gap: 14px;
    }

    .fixfactor-title-content {
        padding-top: 2px;
    }

    .fixfactor-service-icon svg {
        width: 48px;
        height: 48px;
    }

    .fixfactor-service-icon {
        width: 66px;
        height: 66px;
        border-radius: 50%;
    }

    /* Title container uses full width on mobile */
    #ff-sp .fixfactor-product-title {
        max-width: 100%;
        padding-left: 0;
    }

    /* Title displays normally on mobile */
    #ff-sp .fixfactor-product-title h1 {
        font-size: 26px;
        line-height: 1.2;
        font-weight: 700;
        padding-right: 0;
        padding-left: 0;
        margin-left: 0;
    }

    /* Hero Ratings - Mobile */
    .fixfactor-hero-ratings {
        gap: 1rem;
        margin-top: var(--ff-space-xs);
        margin-bottom: 0;
        padding: 0 0 5px 0; /* Reduced from 10px - tighter spacing before short description */
        flex-wrap: wrap;
    }

    .fixfactor-rating-logo {
        width: 12px;
        height: 12px;
    }

    .fixfactor-rating-star {
        width: 13px;
        height: 13px;
    }

    .fixfactor-rating-star-box {
        width: 11px;
        height: 11px;
    }

    .fixfactor-rating-star-box .fixfactor-rating-star {
        width: 7px;
        height: 7px;
    }

    .fixfactor-rating-number {
        font-size: 0.75rem;
    }

    .fixfactor-rating-text {
        font-size: 0.75rem;
    }

    .fixfactor-rating-divider {
        display: none;
    }

    #ff-sp .fixfactor-sticky-sidebar {
        position: relative;
        top: 0;
        order: 1;
        margin-top: 0;
        margin-bottom: var(--ff-space-lg);
        padding: 20px;
        display: flex;
        flex-direction: column;
        background: var(--surface);
        border-radius: 11px;
        border: 2.5px solid var(--accent);
    }

    #ff-sp.fixfactor-no-price .fixfactor-sticky-sidebar {
        position: relative;
        top: 0;
        background: var(--surface);
        border: 3px solid var(--accent-warm);
        border-radius: 11px;
    }

    /* Quote Form - Mobile border-radius adjustment */
    #ff-sp section.fixfactor-contact-form-wide {
        border-radius: 8px;
    }

    #ff-sp .fixfactor-form-content {
        border-radius: 0 0 8px 8px;
    }

    #ff-sp .fixfactor-price-section {
        margin-bottom: 0;
        padding: 0;
        order: 3;
        border: none;
    }
    
    .fixfactor-price-container {
        margin-top: var(--ff-space-xl);
    }
    
    .fixfactor-price-row {
        justify-content: flex-start;
        align-items: center;
        gap: var(--ff-space-md);
    }

    #ff-sp .fixfactor-price {
        font-size: var(--ff-font-4xl);
        font-weight: 700;
    }

    #ff-sp .fixfactor-price.range {
        font-size: var(--ff-font-3xl);
    }

    #ff-sp .fixfactor-payment-methods {
        margin: 4px -20px var(--ff-space-sm) -20px;
        padding: 0 20px var(--ff-space-lg) 20px;
        gap: 6px;
        border-bottom: none;
        flex-wrap: wrap;
    }

    .fixfactor-payment-methods .fixfactor-negotiate-btn {
        margin-left: auto;
    }

    .payment-card-icon {
        height: 17px;
    }

    .payment-badge.klarna {
        height: 17px;
        font-size: 8px;
        padding: 0 6px;
    }

    .fixfactor-negotiate-btn {
        font-size: 11px;
        padding: 4px 10px;
    }

    /* Short description visible on mobile */
    #ff-sp .fixfactor-short-description {
        display: block;
        opacity: 1;
        visibility: visible;
        margin-bottom: var(--ff-space-lg);
        background: transparent;
        padding: 0;
        border-radius: 0;
        order: -1;
        width: 100%;
        box-sizing: border-box;
        font-size: 14px;
    }

    #ff-sp .fixfactor-short-description p {
        font-size: 14px;
        line-height: 1.4;
    }
    
    #ff-sp.fixfactor-no-price .fixfactor-contact-form-wide {
        order: 4;
        margin-bottom: 0;
        padding: 0;
        padding-top: var(--ff-space-xl);
        margin-top: var(--ff-space-lg);
    }

    #ff-sp .fixfactor-variations {
        margin-bottom: 0;
        padding: 10px 0 0 0;
        order: 1;
        border: none;
    }

    /* Option 8: Mobile - Auto-responsive (badges side-by-side if they fit) */
    .fixfactor-variation-list {
        grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
        gap: 6px;
    }

    #ff-sp .fixfactor-cta-section {
        margin-bottom: 0;
        padding: 0;
        order: 4;
        border: none;
    }
    
    .fixfactor-main-cta {
        padding: var(--ff-space-xl) var(--ff-space-2xl);
        font-size: var(--ff-font-lg);
        font-weight: 600;
    }
    
    .fixfactor-conditional-info {
        padding: var(--ff-space-md);
        font-size: var(--ff-font-sm);
        gap: var(--ff-space-sm);
    }
    
    .fixfactor-conditional-info-content {
        font-size: var(--ff-font-sm);
    }
    
    /* Trust badges on mobile - 2x2 grid */
    #ff-sp .fixfactor-badges {
        grid-template-columns: 1fr 1fr;
        gap: 8px;
        margin-bottom: var(--ff-space-xl);
        order: 10;
        display: grid;
        width: 100%;
    }

    #ff-sp .fixfactor-badge {
        padding: 10px;
        width: 100%;
        box-sizing: border-box;
    }

    #ff-sp .fixfactor-badge-title {
        font-size: 13px;
        line-height: 1.1;
    }

    #ff-sp .fixfactor-badge-subtitle {
        font-size: 10px;
        line-height: 1.2;
    }

    #ff-sp .fixfactor-left-column {
        order: 2;
        display: contents;
        width: 100%;
        min-height: auto;
        height: auto;
    }
    
    #ff-sp section.fixfactor-description {
        margin-top: var(--ff-space-xl);
        order: 11;
    }

    /* Left column is display:contents on mobile, so this needs its own order
       to stay directly below Service Details. */
    #ff-sp section.fixfactor-related {
        order: 12;
        margin-top: var(--ff-space-xl);
    }

    #ff-sp .ffrr-list {
        grid-template-columns: 1fr;
    }

    /* PCB decoration hidden on mobile - same as Homepage */
    #ff-sp .fixfactor-pcb-decoration {
        display: none;
    }

    #ff-sp .fixfactor-description-header {
        font-size: 20px;
        font-weight: 700;
        margin-bottom: 12px;
        padding-bottom: 0;
        padding-left: 12px;
        border-bottom: none;
        border-left: 3px solid var(--accent);
        color: var(--content);
        text-transform: none;
        letter-spacing: -0.3px;
    }

    #ff-sp .fixfactor-description-content {
        padding: 0;
        font-size: var(--ff-font-md);
        background: transparent;
        border: none;
    }

    #ff-sp .fixfactor-description-content p {
        font-size: var(--ff-font-md);
        line-height: 1.6;
    }

    #ff-sp .fixfactor-info-button {
        padding: 12px 16px;
        font-size: var(--ff-font-sm);
    }

    .fixfactor-modal h3 {
        font-size: 24px;
    }

    /* Modal form fields on tablet */
    .fixfactor-content-area .wpforms-field {
        margin-bottom: 6px;
    }

    .fixfactor-content-area .wpforms-field input,
    .fixfactor-content-area .wpforms-field select,
    .fixfactor-content-area .wpforms-field input[type="text"],
    .fixfactor-content-area .wpforms-field input[type="email"],
    .fixfactor-content-area .wpforms-field input[type="tel"],
    .fixfactor-content-area .wpforms-field input[type="number"] {
        padding: 10px 14px !important;
        min-height: 41px !important;
        font-size: 16px !important;
    }

    .fixfactor-content-area .wpforms-field textarea {
        padding: 10px 14px !important;
        font-size: 16px !important;
        min-height: 90px !important;
    }

    .fixfactor-modal {
        padding: 0 !important;
        justify-content: flex-start !important;
        align-items: flex-start !important;
    }

    .fixfactor-modal-wrapper {
        width: 100% !important;
        max-width: 100% !important;
        margin: 0 !important;
        min-height: 100vh;
        min-height: 100dvh; /* iOS address bar safe */
    }

    .fixfactor-modal h3 {
        font-size: 24px;
    }
    
    /* Mobile Service Options Container - after variations, before price */
    #ff-sp #mobile-service-options-container {
        order: 2;
    }

    /* Mobile Service Options - JS rendered <768px */
    #ff-sp .mobile-service-options {
        margin-bottom: 0;
        padding: 0;
        margin-top: 6px;
    }

    #ff-sp .mobile-service-options .mobile-service-options-label {
        font-size: 14px;
        font-weight: 600;
        margin-bottom: 12px;
        color: var(--content);
        opacity: 0.7;
    }

    .mobile-service-grid {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 11px;
    }

    .mobile-service-option {
        background: var(--surface);
        border: 1px solid var(--ff-tile-border);
        border-radius: var(--ff-radius);
        padding: 12px 16px;
        cursor: pointer;
        transition: border-color 0.2s ease, box-shadow 0.2s ease;
        display: flex;
        align-items: center;
        gap: 12px;
    }

    .mobile-service-option:hover {
        border-color: var(--accent);
    }

    .mobile-service-option.selected {
        border-color: var(--accent);
        box-shadow: inset 0 0 0 1px var(--accent);
        background: transparent;
    }

    .mobile-service-option.selected .mobile-service-title {
        color: var(--action);
    }

    .mobile-service-icon {
        display: none;
    }

    .mobile-service-option.selected .mobile-service-icon {
        display: none;
    }

    .mobile-service-content {
        flex: 1;
    }

    .mobile-service-title {
        font-size: 14px;
        font-weight: 600;
        color: var(--content);
    }

    .mobile-service-desc {
        display: none;
    }

    /* Quote Form - Mobile */
    #ff-sp section.fixfactor-contact-form-wide {
        border-width: 2px;
    }

    #ff-sp .fixfactor-form-content {
        padding: 0 20px 20px 20px;
    }

    /* Submit button - mobile override */
    .fixfactor-content-area .wpforms-submit,
    section.fixfactor-contact-form-wide .wpforms-submit,
    .wpforms-container .wpforms-submit {
        padding: 18px 24px !important;
        min-height: 52px !important;
    }

}

@media (max-width: 576px) {
    #ff-sp {
        padding: 16px 10px 20px 10px;
    }

    #ff-sp .fixfactor-product-header {
        padding: 0 2px;
        margin-bottom: var(--ff-space-xs);
    }

    /* Service icon on very small screens */
    .fixfactor-title-with-icon {
        gap: 12px;
    }

    .fixfactor-service-icon svg {
        width: 44px;
        height: 44px;
    }

    .fixfactor-service-icon {
        width: 52px;
        height: 52px;
        border-radius: 50%;
    }

    /* Hero ratings - very small screens */
    .fixfactor-hero-ratings {
        gap: 0.75rem;
    }

    .fixfactor-rating-badge {
        gap: 0.25rem;
    }

    .fixfactor-rating-logo {
        width: 11px;
        height: 11px;
    }

    .fixfactor-rating-star {
        width: 11px;
        height: 11px;
    }

    .fixfactor-rating-star-box {
        width: 10px;
        height: 10px;
    }

    .fixfactor-rating-star-box .fixfactor-rating-star {
        width: 6px;
        height: 6px;
    }

    .fixfactor-rating-number {
        font-size: 0.65rem;
    }

    .fixfactor-rating-text {
        font-size: 0.7rem;
    }

    /* Badges - 2 columns on very small screens */
    #ff-sp .fixfactor-badges {
        grid-template-columns: 1fr 1fr;
        gap: 6px;
    }

    #ff-sp .fixfactor-badge {
        padding: 8px;
    }

    #ff-sp .fixfactor-badge-title {
        font-size: 12px;
    }

    #ff-sp .fixfactor-badge-subtitle {
        font-size: 9px;
    }

    #ff-sp .fixfactor-sticky-sidebar {
        padding: var(--ff-space-lg);
    }

    .fixfactor-modal {
        padding: 0 !important;
        justify-content: flex-start !important;
        align-items: flex-start !important;
    }

    .fixfactor-modal-wrapper {
        width: 100% !important;
        max-width: 100% !important;
        margin: 0 !important;
        min-height: 100vh;
        min-height: 100dvh; /* iOS address bar safe */
    }

    .fixfactor-modal h3 {
        font-size: 22px;
    }

    /* Modal form fields on mobile */
    .fixfactor-content-area .wpforms-field {
        margin-bottom: 5px;
    }

    .fixfactor-content-area .wpforms-field input,
    .fixfactor-content-area .wpforms-field select,
    .fixfactor-content-area .wpforms-field input[type="text"],
    .fixfactor-content-area .wpforms-field input[type="email"],
    .fixfactor-content-area .wpforms-field input[type="tel"],
    .fixfactor-content-area .wpforms-field input[type="number"] {
        padding: 8px 12px !important;
        min-height: 37px !important;
        font-size: 16px !important;
    }

    .fixfactor-content-area .wpforms-field textarea {
        padding: 8px 12px !important;
        font-size: 16px !important;
        min-height: 80px !important;
    }

    #ff-sp .fixfactor-payment-methods {
        gap: 5px;
        margin: 2px 0 var(--ff-space-xs) 0;
        padding-bottom: var(--ff-space-xs);
        flex-wrap: wrap;
        border-bottom: none;
    }

    .payment-card-icon {
        height: 15px;
    }

    .payment-badge.klarna {
        height: 15px;
        padding: 0 5px;
        font-size: 7px;
    }

    .fixfactor-negotiate-btn {
        font-size: 11px;
        padding: 4px 8px;
    }
    
    .mobile-service-grid {
        grid-template-columns: 1fr 1fr;
    }

    .mobile-service-option {
        padding: 12px 16px;
        gap: 12px;
    }

    .mobile-service-title {
        font-size: 14px;
    }

    #ff-sp .fixfactor-form-content {
        padding: 16px;
    }
}

/* Core Web Vitals Optimizations */
@supports (content-visibility: auto) {
    .fixfactor-product img {
        content-visibility: auto;
        contain-intrinsic-size: 80px 80px;
    }

    /* Skip rendering of below-fold sections until near viewport */
    section.fixfactor-description {
        content-visibility: auto;
        contain-intrinsic-size: auto 400px;
    }

    section.fixfactor-contact-form-wide {
        content-visibility: auto;
        contain-intrinsic-size: auto 500px;
    }

    .fixfactor-modal {
        content-visibility: auto;
        contain-intrinsic-size: auto 0px;
    }
}

.fixfactor-sticky-sidebar {
    contain: layout style paint;
}

.fixfactor-variation-item,
.fixfactor-service-option {
    contain: layout style;
}

/* Accessibility Improvements */
@media (prefers-reduced-motion: reduce) {
    * {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* .sr-only now lives in base.css, which is inlined on every page. */

/* Service notes carry two different things under one marker: a caution the
   customer has to accept, and a condition in their favour. Painting both amber
   spends the accent on good news and softens the real risk. Rule colour, glyph
   and a visually hidden word all change with the kind - never colour alone.
   No fill: the design language has no amber "warning" panel, and a tint would
   be a second surface. The glyph is a CSS mask rather than markup, because
   wp_kses_post strips <svg> out of filtered content and generated content
   cannot be dragged into the clipboard with the text. */
.fixfactor-note {
    display: flex;
    align-items: flex-start;
    gap: 0.65rem;
    background: none;
    border: 0;
    border-left: 3px solid var(--note-rule-caution);
    border-radius: 0;
    padding: 0.25rem 0 0.25rem 1rem;
    margin: var(--ff-space-lg) 0;
    font-size: var(--ff-font-md);
    line-height: 1.6;
    color: var(--content-body);
    box-shadow: none;
}
.fixfactor-note + .fixfactor-note {
    margin-top: 0.6rem;
}
.fixfactor-note.is-condition {
    border-left-color: var(--note-rule-condition);
}
.fixfactor-note::before {
    content: "";
    flex: 0 0 16px;
    height: 16px;
    margin-top: 0.16rem;
    background-color: var(--note-mark-caution);
    -webkit-mask: var(--note-glyph-caution) center / 16px 16px no-repeat;
    mask: var(--note-glyph-caution) center / 16px 16px no-repeat;
}
.fixfactor-note.is-condition::before {
    background-color: var(--note-mark-condition);
    -webkit-mask-image: var(--note-glyph-condition);
    mask-image: var(--note-glyph-condition);
}
.fixfactor-note-content {
    flex: 1;
    min-width: 0;
}
.fixfactor-note strong {
    font-weight: 700;
    color: var(--content);
}
@media (max-width: 768px) {
    /* Only the type gets smaller. The indent and the rule are the component. */
    .fixfactor-note {
        font-size: 13px;
        gap: 0.55rem;
        padding-left: 0.8rem;
    }
}

/*
 * Service option: the second line (added 30 Jul 2026).
 *
 * "2-5 day turnaround, insured delivery" versus "bring it in, possibly same
 * day" is the whole basis on which someone picks between the two options, and
 * it used to be behind a 14px "?" that opened a hover tooltip. That failed
 * three ways at once: the target was well under the 24px minimum, hover does
 * not exist on the phones most of this traffic arrives on, and although the
 * trigger carried role="button" and tabindex="0" it had no keyboard handler -
 * a span does not fire click on Enter or Space, so a keyboard user could focus
 * it and nothing would happen. Nor was the text tied to the option with
 * aria-describedby, so screen readers never received it either.
 *
 * The grid was already designed for two lines (see .fixfactor-variation-
 * description). These two options simply were not using it.
 */
#ff-sp .fixfactor-service-description,
#ff-sp .mobile-service-description {
    margin: 2px 0 0;
    font-size: var(--ff-font-sm);
    line-height: 1.35;
    color: var(--ff-gray-500);
}

#ff-sp .fixfactor-service-option.selected .fixfactor-service-description,
#ff-sp .mobile-service-option.selected .mobile-service-description {
    color: var(--ff-badge-subtitle);
}

/* Two short buttons fit side by side down to about 500px of column, so they
   stack only in mobile portrait. They used to stack from 768px, where the
   column is still 728px wide and two full-width buttons cost a screen of
   height for nothing. */
@media (max-width: 575px) {
    #ff-sp .fixfactor-info-buttons {
        flex-direction: column;
        gap: var(--ff-space-sm);
    }

    #ff-sp .fixfactor-info-button {
        width: 100%;
    }
}


/* ==========================================================================
 * Why This Price modal (.ffwp)
 *
 * Replaces the old Negotiate Price dialog. Reuses the .fixfactor-modal shell
 * for the overlay, scrim and scroll behaviour; everything inside is new.
 *
 * Two things worth knowing before editing:
 *  - Section separation is surface + spacing. No one-sided decorative rules,
 *    per the design rules.
 *  - The two chart colours are chart-only values, validated against the
 *    #f8fafb surface (chroma >= 0.1, normal-vision dE 20.6, CVD dE 16+, both
 *    >= 3:1). The brand --accent measures 2.66:1 there and cannot be used.
 * ========================================================================== */

#ff-sp .ffwp,
.ffwp {
    --ffwp-cost: var(--action);
    --ffwp-margin: var(--accent-warm-text);
    /* No token for this: VAT is neither a cost of doing the job nor money we
       keep, so it gets neither of their colours. Grey reads as "passes
       through". */
    --ffwp-tax: light-dark(#6f7d82, rgba(255, 255, 255, 0.5));
    --ffwp-gap: var(--surface-alt);
}

.ffwp .ffwp-panel {
    width: 100%;
    max-width: 660px;
    /* Auto on all four sides, deliberately. The overlay centres with
       align-items and scrolls; a centred flex item taller than its scroll
       container puts its own top out of reach. Auto margins outrank
       align-items and collapse to zero when there is no free space, so a
       short panel is centred and a tall one starts at the overlay's padding
       and scrolls from the top. The gutter is the overlay's padding. */
    margin: auto;
    padding: 0;
    background: var(--surface);
    border-radius: 14px;
    box-shadow: 0 1px 2px var(--ff-shadow-xs), 0 24px 64px var(--shadow-colour-lg);
    /* The overlay scrolls. Boxing the panel as well put the form in a 660px
       column with its own scrollbar and cut it in half on a laptop. */
    overflow: hidden;
}

/* The gutter lives on the overlay, not the panel, so the panel's auto margins
   are free to collapse. The tablet block earlier in this file zeroes
   .fixfactor-modal padding and forces flex-start with !important; this is the
   one place that has to outrank it, and only above the full-bleed breakpoint. */
@media (min-width: 769px) {
    #negotiate-modal {
        padding: 24px 20px;
    }
}

.ffwp.show .ffwp-panel {
    animation: ffModalScaleIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

/* --- head --- */
.ffwp .ffwp-head {
    position: relative;
    /* Bottom padding was tuned for a paragraph sitting under the title. With
       the title alone it only has to clear the descenders. */
    padding: 22px 30px 18px;
    background: linear-gradient(180deg, var(--chrome-fill-faint) 0%, var(--surface) 100%);
}

.ffwp .ffwp-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding-right: 44px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    line-height: 1.4;
    color: var(--action);
}

.ffwp .ffwp-eyebrow svg {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
}

/* The question is the whole head now. The sentence that used to explain it
   sat between the title and the figure that actually answers it, so it read
   as a delay rather than an introduction. Larger type wants tighter tracking:
   -0.7px was right at 26px, not at 34px. */
.ffwp .ffwp-head h2 {
    margin: 10px 0 0;
    font-size: 34px;
    font-weight: 700;
    letter-spacing: -1px;
    line-height: 1.12;
    color: var(--content);
}

.ffwp .fixfactor-modal-close {
    position: absolute;
    top: 20px;
    right: 20px;
    z-index: 2;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid var(--border-neutral);
    background: var(--surface);
    border-radius: 50%;
    font-size: 19px;
    line-height: 1;
    color: var(--content-secondary);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.ffwp .fixfactor-modal-close:hover {
    color: var(--content);
    border-color: var(--content-secondary);
}

/* Description headings: promoted from bold paragraphs, styled to match them.
   Measured on the page before the migration - paragraph 16px/27.2px weight 600
   margin 0 0 19.2px desktop, 14px/22.4px margin-bottom 16.8px on a phone, both
   1.2em. An unstyled h3 here would have been 20px/26px margin 30px 0 10px, so
   without this the markup change would have been a visible change too.

   Inherit rather than restate: the container already sets the size and leading
   per breakpoint, so one rule covers both. */
#ff-sp .fixfactor-description-content h3 {
    font-size: inherit;
    /* inherit is 1.6, which is what a paragraph uses on a phone. Paragraphs
       take 1.7 from .fixfactor-content-area p above 768px, so the heading
       follows them there and nowhere else. */
    line-height: inherit;
    font-weight: 600;
    letter-spacing: normal;
    color: inherit;
    margin: 0 0 1.2em;
}

@media (min-width: 769px) {
    #ff-sp .fixfactor-description-content h3 { line-height: 1.7; }
}

/* --- the figure --- */
.ffwp .ffwp-fig { padding: 18px 30px 20px; }

.ffwp .ffwp-fig-top {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 20px;
    margin-bottom: 15px;
}

.ffwp .ffwp-fig-what {
    font-size: 14px;
    font-weight: 600;
    color: var(--content-body);
}

.ffwp .ffwp-hero {
    font-size: 44px;
    font-weight: 700;
    letter-spacing: -1.5px;
    line-height: 1;
    color: var(--content);
    white-space: nowrap;
}

/* One row per line of the price: what it is, how much, and how much of the
   whole it is. The stacked bar it replaces could only answer the third of
   those, and only to a mouse - its narrowest segment was 24px wide in the
   rail, which is not a hover target. Each track is the full width, so the
   fills are directly comparable without adding anything up. */
.ffwp .ffwp-lines {
    display: flex;
    flex-direction: column;
    gap: 11px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.ffwp .ffwp-line {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: baseline;
    gap: 2px 12px;
}

.ffwp .ffwp-line-name {
    font-size: 13.5px;
    line-height: 1.3;
    color: var(--content-body);
}

.ffwp .ffwp-line .ffwp-amount {
    font-size: 14px;
    font-weight: 700;
    line-height: 1.3;
    color: var(--content);
    font-variant-numeric: tabular-nums;
}

.ffwp .ffwp-line-track {
    grid-column: 1 / -1;
    height: 7px;
    border-radius: 4px;
    background: var(--surface-fill);
    overflow: hidden;
}

.ffwp .ffwp-line-fill {
    display: block;
    height: 100%;
    border-radius: 4px;
    background: var(--ffwp-cost);
}

.ffwp .ffwp-line-fill.is-margin { background: var(--ffwp-margin); }
.ffwp .ffwp-line-fill.is-tax { background: var(--ffwp-tax); }

/* The last line is the answer to the question the dialogue asks, so it is the
   one that is allowed to be heavier than the rest. */
.ffwp .ffwp-line.is-margin .ffwp-line-name,
.ffwp .ffwp-line.is-margin .ffwp-amount {
    color: var(--content);
    font-weight: 700;
}

/* Small, and last, because it qualifies the figures rather than adding to
   them: it says these are a model, before anyone points out they found the
   part cheaper somewhere. */
.ffwp .ffwp-fineprint {
    margin: 14px 0 0;
    font-size: 11.5px;
    line-height: 1.5;
    color: var(--content-secondary);
}

.ffwp .ffwp-legend {
    display: flex;
    flex-direction: column;
    gap: 9px;
    margin: 14px 0 0;
    padding: 0;
    list-style: none;
}

/* The bar and the sentence beneath it make the argument; the four line items
   are the evidence for it. A native <details> keeps the evidence one click
   away with no JavaScript, and reclaims 113px on desktop, 287px on a phone. */
.ffwp .ffwp-more {
    margin-top: 14px;
}

.ffwp .ffwp-more-toggle {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 2px 0;
    cursor: pointer;
    list-style: none;
    font-size: 13px;
    font-weight: 600;
    color: var(--action);
    -webkit-user-select: none;
    user-select: none;
}

.ffwp .ffwp-more-toggle::-webkit-details-marker {
    display: none;
}

/* Chevron drawn from two borders on a rotated square: no icon file, no extra
   element, and it inherits the link colour. */
.ffwp .ffwp-more-toggle::after {
    content: "";
    width: 6px;
    height: 6px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform 0.18s ease;
}

.ffwp .ffwp-more[open] .ffwp-more-toggle::after {
    transform: rotate(225deg) translate(-1px, -1px);
}

.ffwp .ffwp-more-toggle:hover {
    text-decoration: underline;
    text-underline-offset: 3px;
}

.ffwp .ffwp-more-toggle:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
    border-radius: 3px;
}

.ffwp .ffwp-more-shut { display: none; }
.ffwp .ffwp-more[open] .ffwp-more-open { display: none; }
.ffwp .ffwp-more[open] .ffwp-more-shut { display: inline; }

/* Inside the disclosure the list only needs clearance from the toggle. */
.ffwp .ffwp-more .ffwp-legend {
    margin-top: 12px;
}

.ffwp .ffwp-legend li {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
}

.ffwp .ffwp-key {
    flex-shrink: 0;
    width: 10px;
    height: 10px;
    border-radius: 3px;
    background: var(--ffwp-cost);
    transform: translateY(1px);
}

.ffwp .ffwp-key.is-margin { background: var(--ffwp-margin); }
.ffwp .ffwp-key.is-tax { background: var(--ffwp-tax); }


.ffwp .ffwp-lt {
    flex: 1 1 200px;
    min-width: 0;
    font-size: 13.5px;
    line-height: 1.5;
    color: var(--content-body);
}

.ffwp .ffwp-lt b { font-weight: 600; color: var(--content); }

/* --- two columns, once there is room for them ---------------------------
   Measured at 660px wide: head 120 + figure 251 + Klarna 132 + the ask 645 =
   1148px against a 1000px laptop viewport, so the panel always scrolls.
   Widening on its own buys almost nothing - the height is four blocks stacked,
   not text that would reflow into fewer lines. Two columns turn that sum into
   a max: 120 + max(251 + 132, 645). Same content, roughly 380px shorter, and
   the form is above the fold instead of below it.

   Below this width the single column is still right: the modal reads as an
   argument that ends in a question, and columns would break that order. */
@media (min-width: 1060px) {
    .ffwp .ffwp-panel {
        max-width: 980px;
        display: grid;
        grid-template-columns: 420px minmax(0, 1fr);
        grid-template-rows: auto 1fr auto;
        align-content: start;
    }

    .ffwp .ffwp-head {
        grid-column: 1 / -1;
    }

    .ffwp .ffwp-fig {
        grid-column: 1;
        grid-row: 2;
    }

    .ffwp .ffwp-sec.is-tinted {
        grid-column: 1;
        grid-row: 3;
    }

    /* The whole argument column becomes the tinted rail this site already uses
       for supporting content. Without it the leftover height under Klarna reads
       as a gap; with it, it reads as the rail running to the bottom. */
    .ffwp .ffwp-fig,
    .ffwp .ffwp-sec.is-tinted {
        background: var(--surface-alt);
    }

    .ffwp .ffwp-sec.is-tinted {
        border-top: 1px solid var(--chrome-border);
    }

    /* A hairline rather than a change of surface: the form is a different job,
       not a different kind of content. */
    .ffwp .ffwp-sec:not(.is-tinted) {
        grid-column: 2;
        grid-row: 2 / span 2;
        border-left: 1px solid var(--chrome-border);
    }
}

/* --- sections, separated by surface not by rules --- */
.ffwp .ffwp-sec { padding: 22px 30px; }
/* Klarna earns its place, but it states a single fact - same total, three
   payments - and was using 181px to say it. */
.ffwp .ffwp-sec.is-tinted {
    background: var(--surface-alt);
    padding-top: 16px;
    padding-bottom: 16px;
}

.ffwp .ffwp-sec.is-tinted .ffwp-sec-body {
    margin-top: 10px;
}

.ffwp .ffwp-sec h3 {
    margin: 0 0 3px;
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -0.2px;
    color: var(--content);
}

/* The badge is sized for the payment row under the price, where it stands
   beside 20px card marks. Next to a 16px heading it was too tall, and being
   inline-flex it takes its baseline from its own text rather than from the
   box - so it hung low. Centring it on the heading's x-height fixes both. */
.ffwp .ffwp-sec h3 .payment-badge.klarna {
    height: 17px;
    padding: 0 6px;
    font-size: 9px;
    border-radius: 3px;
    vertical-align: middle;
    position: relative;
    top: -1px;
}

.ffwp .ffwp-sec-sub {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--content-secondary);
}

/* No indent under the icon: it put the form 76px from the left edge and 30
   from the right, out of line with the bar and legend above. */
.ffwp .ffwp-sec-body {
    margin-top: 14px;
}

.ffwp .ffwp-split { display: flex; gap: 8px; }

/* Each card was 64px to hold two short lines. Most of that was inherited:
   the panel's 1.6 line-height put 9px of dead space around a single number.
   Both lines now set their own leading, which is what a card this small
   needs. 64px -> 46px, on three cards and on every breakpoint. */
.ffwp .ffwp-split-part {
    flex: 1;
    padding: 6px 10px;
    text-align: center;
    background: var(--surface);
    border: 1px solid var(--chrome-border);
    border-radius: var(--radius-input);
}

.ffwp .ffwp-split-part .amt {
    display: block;
    font-size: 15px;
    line-height: 1.15;
    font-weight: 700;
    color: var(--content);
}

.ffwp .ffwp-split-part .when {
    display: block;
    margin-top: 1px;
    font-size: 11px;
    line-height: 1.25;
    color: var(--content-secondary);
}

/* --- the WPForms body, dressed to match --- */
.ffwp .ffwp-form .wpforms-container { margin: 0; }
.ffwp .ffwp-form .wpforms-head-container { display: none; }

.ffwp .ffwp-form .wpforms-field-container {
    display: grid;
    grid-template-columns: 132px 1fr;
    gap: 0 10px;
}

.ffwp .ffwp-form .wpforms-field {
    grid-column: 1 / -1;
    padding: 0 0 11px;
}

.ffwp .ffwp-form .wpforms-field-label {
    display: block;
    margin: 0 0 5px;
    font-size: 12px;
    font-weight: 600;
    color: var(--content-secondary);
}

.ffwp .ffwp-form .wpforms-required-label { display: none; }

/* Inputs, textareas and their focus state are styled by the theme's own
   .fixfactor-content-area rules, which carry !important. Nothing here tries to
   restate them - it would be dead CSS. */

/* Checkbox list as chips: the box goes, the label becomes the control. */
.ffwp .ffwp-form .ff-chips ul {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.ffwp .ffwp-form .ff-chips li { margin: 0; padding: 0; }

/* Covers its own chip, so the whole chip is the hit target. Sized against the
   li, which is why the li below has position: relative - without it all seven
   stack in one place and swallow each other's clicks. */
.ffwp .ffwp-form .ff-chips input[type="checkbox"] {
    position: absolute;
    inset: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    opacity: 0;
    cursor: pointer;
}

.ffwp .ffwp-form .ff-chips label {
    display: inline-block;
    margin: 0;
    padding: 8px 13px;
    min-height: 24px;
    background: var(--surface);
    border: 1px solid var(--border-neutral);
    border-radius: 999px;
    font-size: 13px;
    font-weight: 400;
    color: var(--content-body);
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

/* On the li, because the input now sits above the label. */
.ffwp .ffwp-form .ff-chips li:hover label { border-color: var(--accent); }

.ffwp .ffwp-form .ff-chips input:checked + label {
    background: var(--action);
    border-color: var(--action);
    color: var(--surface);
    font-weight: 600;
}

.ffwp .ffwp-form .ff-chips input:focus-visible + label {
    outline: 2px solid var(--action);
    outline-offset: 2px;
}

/*
 * WPForms lays choice lists out as a grid of full-width rows. Scoped to the
 * dialog's id so it wins on specificity rather than on !important.
 */
#negotiate-modal .ff-chips ul {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    grid-template-columns: none;
}

/* Chrome draws the number spinner from its own pseudo-element, which the
   theme's appearance: none does not reach. */
#negotiate-modal input[type="number"]::-webkit-outer-spin-button,
#negotiate-modal input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

#negotiate-modal input[type="number"] {
    -moz-appearance: textfield;
}

#negotiate-modal .ff-chips li {
    position: relative;
    display: block;
    width: auto;
    margin: 0;
    padding: 0;
}


.ffwp .ffwp-form .wpforms-submit-container { padding: 0; margin-top: 3px; }

/* --- live preview of what lands in the inbox --- */
.ffwp .ffwp-preview {
    margin: 13px 0 0;
    padding: 14px 16px;
    background: var(--chrome-fill-faint);
    border: 1px solid var(--chrome-border);
    border-radius: var(--radius-input);
}

.ffwp .ffwp-preview[hidden] { display: none; }

.ffwp .ffwp-preview-label {
    display: block;
    margin-bottom: 6px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--content-secondary);
}

.ffwp .ffwp-preview p {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.65;
    color: var(--content-body);
}

.ffwp .ffwp-send-note {
    margin: 10px 0 0;
    font-size: 12px;
    line-height: 1.5;
    text-align: center;
    color: var(--content-secondary);
}

/* --- phone --- */
@media (max-width: 768px) {
    .ffwp .ffwp-panel {
        max-width: none;
        max-height: none;
        min-height: 100%;
        margin: 0;
        border-radius: 0;
    }

    .ffwp .ffwp-head,
    .ffwp .ffwp-fig,
    .ffwp .ffwp-sec {
        padding-left: 18px;
        padding-right: 18px;
    }

    /* The sheet runs to about 1,950px and the overlay is what scrolls, so a
       close button in the flow disappears at the first swipe. */
    .ffwp .fixfactor-modal-close {
        position: fixed;
        top: 12px;
        right: 12px;
        box-shadow: 0 2px 10px var(--shadow-colour-lg);
    }

    .ffwp .ffwp-head h2 { font-size: 28px; }

    .ffwp .ffwp-fig-top {
        flex-direction: column;
        align-items: flex-start;
        gap: 6px;
    }

    .ffwp .ffwp-hero { font-size: 36px; }


    /* Three amounts side by side, not stacked: 354px of row is enough for
       114px a card once the padding and caption come down a step. */
    .ffwp .ffwp-split { gap: 6px; }
    .ffwp .ffwp-split-part {
        min-width: 0;
        padding: 6px 4px;
    }
    .ffwp .ffwp-split-part .amt { font-size: 15px; }
    .ffwp .ffwp-split-part .when {
        font-size: 10.5px;
        line-height: 1.3;
    }

    .ffwp .ffwp-form .wpforms-field-container { grid-template-columns: 1fr; }
}

@media (max-width: 420px) {
    /* The swatch used to wrap onto its own line to make room for a value
       column on the right. That column is gone, so it sits on the text's
       line where it belongs. */
    .ffwp .ffwp-legend li { gap: 8px; }
}

/* ==========================================================================
 * Funnel steps bar (.ffp-steps)
 *
 * Same component as the model page's .ffd-steps, so hub -> model -> service
 * reads as one trail. Full width above the page, real names as the anchors.
 * ========================================================================== */
.ffp-steps-band {
    /* The trail is the only thing telling you where you are in a four-step
       journey, and it left the screen after 115px of scrolling. The band is a
       direct child of <body> - measured: nothing above it clips, transforms or
       contains - so sticky works with an offset and nothing else.

       Desktop: the header is relative and scrolls off, so the band takes the
       top of the viewport. Phone (<=767px): the header is fixed at 70px, so
       the band sits under it. Both measured on the page, not assumed. */
    position: sticky;
    top: 0;
    z-index: var(--z-sticky, 900);
    border-bottom: 1px solid var(--wash-brand-med);
    background: var(--surface, #fff);
}

@media (max-width: 767px) {
    .ffp-steps-band { top: 70px; }
}

/* Same column as #ff-sp, not the model page's 60rem: measured at 1440 the
   trail started at L240 and the product content at L150, so the bar read as
   belonging to a different page. Width and gutter are the product column's. */
.ffp-steps {
    max-width: 1140px;
    margin: 0 auto;
    padding: 0.65rem 20px;
    display: flex;
    align-items: center;
    font-size: 0.86rem;
}

.ffp-step {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    text-decoration: none;
    color: var(--action, #007a92);
    font-weight: 600;
    white-space: nowrap;
}

a.ffp-step:hover .ffp-step-label {
    text-decoration: underline;
    text-underline-offset: 2px;
}

.ffp-step-dot {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    background: var(--wash-brand-soft);
    color: var(--action, #007a92);
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
}

.ffp-step.is-current {
    color: var(--content, #000);
    font-weight: 800;
}

/* The warm accent, matching the same bar on the device pages: the step you are
   on is the one place on the page allowed to use it. Black on yellow rather
   than white on teal, because yellow cannot carry white text. */
.ffp-step.is-current .ffp-step-dot {
    background: var(--accent-warm);
    /* --content turns white on ink and gives 1.46:1 here; the comment above
       already said black, --on-warm is the token that keeps it black. */
    color: var(--on-warm);
}

/* The last step is the page you are on, so it may be long. Everything before
   it holds its width; only this one is allowed to shrink and ellipsis. */
.ffp-step.is-current .ffp-step-label {
    overflow: hidden;
    text-overflow: ellipsis;
}

.ffp-step.is-current {
    min-width: 0;
}

.ffp-step-sep {
    flex: 0 1 44px;
    min-width: 12px;
    height: 1px;
    background: var(--wash-brand-strong);
    margin: 0 0.7rem;
}

@media (max-width: 640px) {
    /*
     * Four labels do not fit 390px. Scrolling them sideways hid the step you
     * are on behind the edge and ellipsised it to "S…" — measured on the
     * iPhone 14 Pro page — which is the worst thing a "where am I" bar can do.
     *
     * So: name the step you are on and the one immediately before it, the way
     * back, which on a product page is the model. Everything earlier keeps its
     * dot and stays tappable. Nothing overflows, so nothing scrolls.
     *
     * The current step is always last, which makes the step before it
     * :nth-last-child(3) — step, separator, step.
     */
    .ffp-steps {
        flex-wrap: nowrap;
        overflow: visible;
        padding: 0.6rem 12px;
        font-size: 0.78rem;
    }

    .ffp-step { gap: 0.3rem; padding: 0.2rem 0; }

    .ffp-step .ffp-step-label { display: none; }

    .ffp-steps .ffp-step:last-child .ffp-step-label,
    .ffp-steps .ffp-step:nth-last-child(3) .ffp-step-label {
        display: inline;
    }

    .ffp-steps .ffp-step:nth-last-child(3) .ffp-step-label {
        max-width: 38vw;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* With the label gone the dot is the whole control, so it stays visible
       and gains a little size to be worth aiming at. */
    .ffp-step.is-done .ffp-step-dot {
        width: 20px;
        height: 20px;
    }

    .ffp-step.is-current .ffp-step-dot {
        width: 17px;
        height: 17px;
        font-size: 10px;
    }

    .ffp-step-sep { flex: 0 1 20px; margin: 0 0.4rem; }
}

/* Right corners only: the left edge stays flat because the accent bar runs
   down it. Two populations render the same callout — the ones the description
   filter classes, and the ones authored in content with the colours inline and
   no class at all. The attribute pair matches the second without touching any
   other div. Radius is the system default so these agree with cards and
   buttons. Scoped by id to outrank a plain class rule earlier in this file. */
#ff-sp div[style*="background-color"][style*="border-left"] {
    border-radius: 0 var(--radius, 12px) var(--radius, 12px) 0;
}


/* =============================================================================
   CONFIGURATOR (proposal C, stage 1)

   Two steps, one idiom. The variation rows and the fulfilment cards are drawn
   the way the model pages draw them (.ffd-variant / .ffd-fcard), because the
   same customer sees both and a control should not change shape between them.

   Appended rather than woven in: the rules above still describe the old grid of
   small variation tiles, and this block overrides only what the new inner
   markup needs. Dead rules from the two-option service switch are left alone in
   this pass — they belong to a clean-up run with its own before/after.
   ========================================================================== */

/*
 * The band bleeds to the viewport edge, so the clip that stops any resulting
 * horizontal scroll has to sit on a full-width ancestor. On #ff-sp itself —
 * capped at 1140 and centred — it cut the bleed off at the container edge,
 * which is exactly what it looked like.
 */
.ffc-shell { overflow-x: clip; }

#ff-sp .fixfactor-vis-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* --- step one: which option ------------------------------------------------ */

#ff-sp .fixfactor-variation-list {
    display: block;
    grid-template-columns: none;
}

#ff-sp .fixfactor-variation-item {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 12px;
    padding: 16px;
    margin-bottom: 8px;
    border: 1px solid var(--border-neutral);
    border-radius: var(--radius-input, 10px);
    background: var(--surface);
}

#ff-sp .fixfactor-variation-item:last-child {
    margin-bottom: 0;
}

/* --surface here is the page white, so the selected row changed border only and
   the fill never moved. Same faint chrome tint the fulfilment cards use, so a
   chosen variation and a chosen route read alike. */
#ff-sp .fixfactor-variation-item.selected {
    border-color: var(--action);
    background: var(--chrome-fill-faint);
    box-shadow: inset 0 0 0 1px var(--action);
}

#ff-sp .fixfactor-variation-item {
    transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}

#ff-sp .fixfactor-variation-item:hover {
    border-color: var(--border-active);
    background: var(--chrome-fill-faint);
}

#ff-sp .fixfactor-variation-item.selected:hover {
    border-color: var(--action);
    background: var(--chrome-fill-faint);
}

/* The dot carries the "this one is chosen" signal, so the label does not have
   to change colour to say it — colour alone is not a state. */
#ff-sp .fixfactor-variation-dot {
    width: 19px;
    height: 19px;
    flex: 0 0 auto;
    border: 1.5px solid var(--border-neutral);
    border-radius: 50%;
    background: var(--surface);
    position: relative;
}

#ff-sp .fixfactor-variation-item.selected .fixfactor-variation-dot {
    border-color: var(--action);
}

#ff-sp .fixfactor-variation-item.selected .fixfactor-variation-dot::after {
    content: "";
    position: absolute;
    inset: 4px;
    border-radius: 50%;
    background: var(--action);
}

#ff-sp .fixfactor-variation-body {
    flex: 1;
    min-width: 0;
}

#ff-sp .fixfactor-variation-title {
    display: block;
    font-size: 15px;
    font-weight: 700;
    line-height: 1.3;
    color: var(--content);
}

#ff-sp .fixfactor-variation-item.selected .fixfactor-variation-title {
    color: var(--content);
}

#ff-sp .fixfactor-variation-sub {
    display: block;
    margin-top: 4px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--content-secondary);
}

#ff-sp .fixfactor-variation-price {
    margin-left: auto;
    font-size: 17px;
    font-weight: 800;
    color: var(--action);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* An add-on row carries the difference it makes, not a total. A quiet chip in
   the brand tint reads as "extra" at a glance and does not compete with the
   figure above the button. */
#ff-sp .fixfactor-variation-price.is-extra {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .01em;
    color: var(--action);
    background: color-mix(in srgb, var(--accent) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
    border-radius: 999px;
    padding: 4px 10px;
    line-height: 1.25;
}

/* The cheapest option in an add-on group adds nothing, so it says nothing —
   and an empty chip is still a chip. */
#ff-sp .fixfactor-variation-price.is-extra:empty {
    display: none;
}

#ff-sp .fixfactor-variation-item.selected .fixfactor-variation-price.is-extra {
    background: color-mix(in srgb, var(--accent) 18%, transparent);
    border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}

/* An option we cannot price is still worth showing — the customer may want to
   ask about it. It just must not look buyable. */
#ff-sp .fixfactor-variation-ask {
    font-size: 13px;
    font-weight: 600;
    color: var(--content-secondary);
}

/* --- step two: how it gets done -------------------------------------------- */

/* Quiet outbound link under the fulfilment cards, pointing at
   /mail-in-repair/. Same visual language as the "Full details" links on the
   device templates: secondary colour, underline and arrow nudge on hover, so
   it reads as help rather than as a second call to action. */
#ff-sp .ffc-mailin-more[hidden] { display: none; }
#ff-sp .ffc-mailin-more { display: flex; align-items: center; gap: 6px; margin: 16px 0 0; font-size: 0.82rem; line-height: 1.5; }
#ff-sp .ffc-mailin-more svg { flex: 0 0 auto; width: 16px; height: 16px; stroke: var(--accent-art, #006e82); stroke-width: 1.8; fill: none; stroke-linecap: round; stroke-linejoin: round; }
#ff-sp .ffc-mailin-more a { color: var(--content-secondary, #505050); font-weight: 500; text-decoration: none; border-bottom: 1px solid transparent; transition: color 0.2s ease, border-color 0.2s ease; }
#ff-sp .ffc-mailin-more a:hover, #ff-sp .ffc-mailin-more a:focus-visible { color: var(--action, #007a92); border-bottom-color: currentColor; }

#ff-sp .ffc-fulfil {
    padding: 0 24px;
    margin-top: 20px;
}

#ff-sp .ffc-fulfil-legend,
#ff-sp.ffc-layout .fixfactor-variation-group .fixfactor-variation-group-label {
    font-size: 15px;
    font-weight: 700;
    letter-spacing: normal;
    text-transform: none;
    color: var(--content);
    opacity: 1;
    margin: 0 0 12px;
}

/* The FASTEST tab overhangs the card by 9px, so the legend needs the clearance
   or the two touch. */
#ff-sp .ffc-fulfil-legend { margin-bottom: 18px; }

#ff-sp .ffc-cards {
    display: grid;
    /* Three routes are a comparison, and a comparison has to be readable in one
       glance. Stacked, they read as three unrelated paragraphs. */
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 12px;
}

#ff-sp .ffc-card {
    position: relative;
    display: block;
    padding: 16px;
    border: 1px solid var(--border-neutral);
    border-radius: var(--radius, 12px);
    background: var(--surface);
    cursor: pointer;
    transition: border-color 0.18s ease, background 0.18s ease;
}

#ff-sp .ffc-card:hover {
    border-color: var(--accent);
    background: var(--chrome-fill-faint);
}

/* --surface here was the page white: the fill never changed and selection read
   from the border alone. The faint wash is deliberately the quieter of the two
   chrome tints - the accent border and inset ring carry "chosen", the fill only
   has to separate the card from the page. */
#ff-sp .ffc-card.is-on {
    border-color: var(--action);
    background: var(--chrome-fill-faint);
    box-shadow: inset 0 0 0 1px var(--action);
}

#ff-sp .ffc-card.is-on:hover {
    background: var(--chrome-fill-faint);
}

/* Sits on the border, not inside it: as a block in the flow it stole a line
   from the card and pushed "Repaired While You Wait" onto two. */
#ff-sp .ffc-rec {
    position: absolute;
    top: -9px;
    left: 14px;
    z-index: 1;
    padding: 3px 8px;
    border-radius: 4px;
    background: var(--accent-warm);
    /* Same amber, same rule: the badge ink cannot follow the register. */
    color: var(--on-warm);
    font-size: 9.5px;
    font-weight: 800;
    line-height: 1.2;
    letter-spacing: 0.06em;
}

#ff-sp .ffc-card-head {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

#ff-sp .ffc-card-name {
    font-size: 14.5px;
    font-weight: 700;
    line-height: 1.3;
    color: var(--content);
}

#ff-sp .ffc-ico {
    width: 19px;
    height: 19px;
    flex: 0 0 auto;
    margin-top: 1px;
    color: var(--action);
}

#ff-sp .ffc-card-specs {
    display: block;
    margin-top: 8px;
}

/* The two rows repeat across every card — payment then timing — so the cards
   line up and scan like a comparison table rather than three paragraphs. */
#ff-sp .ffc-spec {
    display: block;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--content-secondary);
}

#ff-sp .ffc-spec + .ffc-spec {
    margin-top: 5px;
}

#ff-sp .ffc-spec.is-fast {
    color: var(--status-success);
}

#ff-sp .ffc-spec.is-slow {
    color: var(--accent-warm-text);
}

@media (max-width: 768px) {
    #ff-sp .ffc-fulfil {
        padding: 0;
        margin-top: 16px;
    }

    #ff-sp .fixfactor-variation-item {
        padding: 14px;
    }
}


/* =============================================================================
   LAYOUT C (stage 2)

   Hero band, a full-width configurator strip, then content with a sticky column
   of facts. Built entirely with grid-template-areas on #ff-sp, because
   .fixfactor-product-grid was already display:contents — so every section is
   already a child of the grid container and nothing had to be moved in the
   document to reach this picture. Four elements were added: the hero backdrop,
   the device photo, the tag row and the buy bar.

   Everything below is scoped to .ffc-layout. Remove that one class from the
   wrapper and the page renders exactly as it did before.
   ========================================================================== */

#ff-sp.ffc-layout {
    /* Stated outright, both here and in the phone block below: an older rule
       flips .fixfactor-product to display:block under 768px, which silently
       threw the areas away and left the page in document order. */
    display: grid;
    grid-template-columns: minmax(0, 1fr) 300px;
    grid-template-rows: auto;
    grid-template-areas:
        "head media"
        "lead media"
        "conf conf"
        "body facts"
        "rel  facts";
    gap: 0 var(--ff-space-4xl, 40px);
    column-gap: 48px;
    padding-top: 0;
    position: relative;
}

/* Both wrappers stop being boxes and become pass-throughs, so their sections
   can be placed individually. The grid wrapper is restated here because an
   older phone rule turns it into a flex column, which collapsed the whole
   layout into one 34px-wide track. */
#ff-sp.ffc-layout .fixfactor-product-grid { display: contents; }
#ff-sp.ffc-layout .fixfactor-left-column { display: contents; }

/* Default for anything not given an area: full width, never its own column.
   A stray script tag or container must not be able to invent a track. */
#ff-sp.ffc-layout > * { grid-column: 1 / -1; }

#ff-sp.ffc-layout .fixfactor-product-header { grid-area: head; align-items: flex-start; padding: 36px 0 0; }
#ff-sp.ffc-layout .fixfactor-short-description {
    grid-area: lead;
    /* Bottom padding sets the air between the last line of the hero and the
       configurator card that crosses the band's edge. Raising it alone is not
       enough: the photograph stretches to the row, so the row growing meant a
       bigger device. The figure's own bottom margin below absorbs the same
       24px, which keeps the image exactly the size it was. Top padding is
       deliberately untouched. */
    padding: 16px 0 84px;
    margin: 0;
    /* It carried its own white fill, which cut a pale rectangle out of the
       tinted hero band. On the band it has to be transparent. */
    background: transparent;
}
#ff-sp.ffc-layout .ffc-media { grid-area: media; }
#ff-sp.ffc-layout .fixfactor-sticky-sidebar { grid-area: conf; }
/* Both columns start on the same line under the configurator. The heading
   carried a user-agent top margin, so the facts card's border sat 16px above
   the words next to it and the two read as unaligned. */
#ff-sp.ffc-layout section.fixfactor-description { grid-area: body; margin-top: 32px; }
#ff-sp.ffc-layout section.fixfactor-description > .fixfactor-description-header { margin-top: 0; }
#ff-sp.ffc-layout .fixfactor-related { grid-area: rel; margin-top: 40px; padding-bottom: 64px; }
#ff-sp.ffc-layout .fixfactor-badges { grid-area: facts; }
#ff-sp.ffc-layout .fixfactor-contact-form-wide {
    grid-area: conf;
    /* It was 500px wide inside a 390px phone. Nothing in a grid cell may set
       its own width larger than the track. */
    width: auto;
    max-width: 100%;
    min-width: 0;
}

/* Hero backdrop. A grid item rather than a pseudo-element: it has to bleed past
   the page padding on both sides, and an item can be told exactly which rows to
   cover without hard-coding a height. */
#ff-sp.ffc-layout .ffc-hero-bg {
    grid-column: 1 / -1;
    grid-row: 1 / 3;
    /* Edge to edge, whatever the viewport. The container is capped at 1140 and
       a band that stops at the same line reads as a box, not a band. */
    margin-inline: calc(50% - 50vw);
    /* White, like the rest of the page. The tint was doing the separating; a
       single hairline does it more quietly, and the configurator card crossing
       that line still reads as the next step. */
    background: var(--surface);
    border-bottom: 1px solid var(--chrome-border);
    z-index: 0;
}

/*
 * The backdrop is a grid item with an explicit z-index, so it paints in the
 * z-index layer — above plain in-flow content. Lifting the sections above it
 * cannot be done with `> *`: the two wrappers between them and #ff-sp are
 * display:contents, which generates no box, so position and z-index on those
 * wrappers do nothing at all. Each section that shares rows with the backdrop
 * has to say it itself.
 */
#ff-sp.ffc-layout .fixfactor-product-header,
#ff-sp.ffc-layout .fixfactor-short-description,
#ff-sp.ffc-layout .ffc-media,
#ff-sp.ffc-layout .fixfactor-sticky-sidebar,
#ff-sp.ffc-layout .fixfactor-contact-form-wide,
#ff-sp.ffc-layout section.fixfactor-description,
#ff-sp.ffc-layout .fixfactor-related,
#ff-sp.ffc-layout .fixfactor-badges {
    position: relative;
    z-index: 1;
}

/* The circled outline icon goes: the device now has a photograph. */
#ff-sp.ffc-layout .fixfactor-service-icon { display: none; }

#ff-sp.ffc-layout .fixfactor-product-header h1 {
    font-size: 38px;
    line-height: 1.15;
    letter-spacing: -1.1px;
    font-weight: 800;
}

#ff-sp.ffc-layout .fixfactor-hero-ratings { margin-top: 12px; }

/* The header was built as a flex row around an icon that no longer renders.
   With the icon gone the row still constrained the title to its content width,
   so the H1 wrapped after two words and the tag list floated up beside it.
   Force the whole block back to a single column at full measure. */
#ff-sp.ffc-layout .fixfactor-product-header,
#ff-sp.ffc-layout .fixfactor-product-title,
#ff-sp.ffc-layout .fixfactor-title-with-icon,
#ff-sp.ffc-layout .fixfactor-title-content {
    display: block;
    width: 100%;
    max-width: 100%;
}

/* No character cap. 20ch broke "iPhone 15 Battery Replacement" over two lines
   inside a column with 240px to spare; the measure the column already gives is
   the right one. */
#ff-sp.ffc-layout .fixfactor-product-header h1 { max-width: 26ch; }
/* Routed through the same variable so the lead and the body share one
   measure - at 62ch it was still running to 78 real characters. */
#ff-sp.ffc-layout .fixfactor-short-description { max-width: var(--ff-measure); }
#ff-sp.ffc-layout .fixfactor-hero-ratings { display: flex; }

/* Not just p: a trailing warning note is a div and carried its own 16px, which
   stacked on top of the tag row's 16 and opened a 32px hole in the hero. */
#ff-sp.ffc-layout .fixfactor-short-description > *:last-child { margin-bottom: 0; }

/* Notes stay part of the description rather than becoming a second card or a
   headed sub-section. The hidden "Please note" text already gives each row an
   accessible label; visually, a calm information mark and a divider are enough. */
#ff-sp.ffc-layout .fixfactor-short-description > p:empty { display: none; }

#ff-sp.ffc-layout .fixfactor-note {
    gap: 14px;
    margin: 0;
    padding: 14px 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    font-size: 14px;
    line-height: 1.55;
    color: var(--content-body);
}

#ff-sp.ffc-layout .fixfactor-short-description > p + .fixfactor-note { margin-top: 16px; }

#ff-sp.ffc-layout .fixfactor-note + .fixfactor-note {
    margin-top: 0;
    border-top: 1px solid var(--chrome-border);
}

/* Outlined mark: ring and letter carry the brand amber, background stays empty
   (owner decision, 20 Aug 2026). --accent-warm-icon is the line-work weight
   (#b38600, 3.3:1) — lighter than the text amber but still legible; brand
   #FFD100 sits at 1.46:1 and reads as a smudge at this size. In dark mode the
   token flips back to #FFD100 on its own. */
#ff-sp.ffc-layout .fixfactor-note::before,
#ff-sp.ffc-layout .fixfactor-note.is-condition::before {
    content: "i";
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 20px;
    width: 20px;
    height: 20px;
    margin-top: 1px;
    border: 1.5px solid var(--accent-warm-icon, #b38600);
    border-radius: 50%;
    background: transparent;
    color: var(--accent-warm-icon, #b38600);
    /* The earlier .fixfactor-note::before block still applies a mask; without
       this reset it clips the amber disc into the glyph shape. */
    -webkit-mask: none;
    mask: none;
    font-family: inherit;
    font-size: 12px;
    font-style: normal;
    font-weight: 700;
    line-height: 1;
}

/*
 * Two limits, not one. Width scales with the viewport and stops at 280 — the
 * source is 700px, so that is still sharp at 2x and it never dominates the
 * column. Height is bounded by the hero itself: the figure stretches across
 * the title and lead rows, min-height:0 keeps it out of the row sizing, and
 * the image contains itself inside whatever that leaves. Short copy no longer
 * pushes the device down behind the configurator card.
 */
#ff-sp.ffc-layout .ffc-media {
    align-self: stretch;
    /* Split the 16px safety reserve evenly above and below the photograph.
       The image keeps its established height while neither edge can touch the
       breadcrumb boundary or the configurator crossing the hero.
       The figure stretches to the hero rows and the image is height:100% of
       it, so this margin is what decouples the device's size from the band's
       height: it carries the same 24px the lead's bottom padding gained, and
       the photograph does not grow with the extra air below it. */
    margin-bottom: 64px;
    justify-self: end;
    display: flex;
    align-items: flex-start;
    justify-content: flex-end;
    width: clamp(190px, 20vw, 280px);
    max-width: 100%;
    /*
     * Size containment: the figure contributes nothing to how tall the hero
     * rows are, it only fills what the copy beside it has already decided.
     * Without it a 400px-tall device stretched the title row and opened a
     * 130px hole between the ratings and the first paragraph.
     */
    contain: size;
}

/* The media wrapper sizes to the actual cut-out, so the service badge overlaps
   the device rather than an arbitrary 280px figure track. */
#ff-sp.ffc-layout .ffc-media-visual {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    height: calc(100% - 16px);
    margin-top: 12px;
    max-width: 100%;
}

/* No frame, no plate. The phone has its own edge; a box around it only fights
   the white page. */
/* Scales by height, so the box is always exactly the device — no letterboxing
   and nothing to align around. Width is the cap: the source is 700px, so 280
   CSS px is still sharp at 2x and it never takes over the column. */
#ff-sp.ffc-layout .ffc-media-img {
    display: block;
    height: 100%;
    width: auto;
    max-width: 100%;
    object-fit: contain;
    border-radius: 0;
}

/* Service identity without another teal button-like surface. The existing
   mapped service SVG is enlarged in ink; only the small warm dot carries the
   brand accent. The keyline belongs to the outside of the white separation
   disc, so it never reduces the icon's field or reads as an inset ring. */
#ff-sp.ffc-layout .ffc-service-swatch {
    --ffc-swatch-edge-offset: 4px;
    position: absolute;
    left: 16%;
    bottom: 7%;
    z-index: 2;
    display: grid;
    place-items: center;
    width: 92px;
    height: 92px;
    box-sizing: border-box;
    border: 0;
    border-radius: 50%;
    outline: 0;
    background: var(--surface);
    color: var(--content);
    box-shadow: none;
    transform: translateX(-44%);
    isolation: isolate;
    pointer-events: none;
}

#ff-sp.ffc-layout .ffc-service-swatch::before {
    content: "";
    position: absolute;
    inset: calc(-1 * var(--ffc-swatch-edge-offset));
    z-index: 0;
    border: 1px solid var(--border-interactive);
    border-radius: inherit;
    background: var(--surface);
}

#ff-sp.ffc-layout .ffc-service-swatch svg {
    position: relative;
    z-index: 1;
    display: block;
    width: 68px;
    height: 68px;
    fill: none;
    color: inherit;
}

#ff-sp.ffc-layout .ffc-service-swatch-mark {
    position: absolute;
    right: -1px;
    bottom: -1px;
    z-index: 2;
    width: 13px;
    height: 13px;
    border: 2px solid var(--surface);
    border-radius: 50%;
    background: var(--accent-warm);
}

/* The generic laptop shot is a wide landscape device where the clamp above
   was tuned for upright phones - a fifth more width keeps its on-page
   presence comparable to the packshots. */
#ff-sp.ffc-layout .ffc-media.is-laptop {
    width: clamp(228px, 24vw, 336px);
}

/* Landscape packshots need a width-led cap. Using the phone track made a
   Surface image carry only 256px at desktop even though its source is 500px
   wide. The class is derived from attachment dimensions, not model names. */
#ff-sp.ffc-layout .ffc-media.is-landscape:not(.is-laptop) {
    width: clamp(300px, 28vw, 360px);
    max-width: none;
}

/* Generic services keep the device category without pretending to be a
   specific model. These are source silhouettes supplied for this purpose;
   the same service badge used on model packshots carries the repair type. */
#ff-sp.ffc-layout .ffc-media.is-generic-device .ffc-media-visual {
    width: 100%;
}

#ff-sp.ffc-layout .ffc-media.is-generic-device .ffc-generic-device-img {
    width: 100%;
    height: auto;
    max-height: 100%;
}

#ff-sp.ffc-layout .ffc-media.is-generic-laptop {
    width: clamp(260px, 27vw, 336px);
    max-width: none;
}

#ff-sp.ffc-layout .ffc-media.is-generic-phone {
    width: clamp(142px, 14vw, 176px);
    container-name: ffc-generic-phone;
    container-type: size;
}

#ff-sp.ffc-layout .ffc-media.is-generic-phone .ffc-media-visual {
    height: 166px;
    margin-top: 20px;
}

/* The grid determines the media track from the real hero copy. Container
   thresholds let the silhouette use that space without product-name rules:
   compact services stay quiet, diagnostics grow, and neither can run away. */
@container ffc-generic-phone (min-height: 240px) {
    #ff-sp.ffc-layout .ffc-media.is-generic-phone .ffc-media-visual {
        height: 220px;
        margin-top: 32px;
    }
}

@container ffc-generic-phone (min-height: 360px) {
    #ff-sp.ffc-layout .ffc-media.is-generic-phone .ffc-media-visual {
        height: 300px;
        margin-top: 36px;
    }
}

#ff-sp.ffc-layout .ffc-media.is-generic-laptop .ffc-service-swatch {
    left: 15%;
    bottom: 2%;
}

#ff-sp.ffc-layout .ffc-media.is-generic-phone .ffc-service-swatch {
    left: 5%;
    bottom: 7%;
}

/* --- the configurator strip ------------------------------------------------ */

/* The 2px outline made the sidebar the only element on the site drawn that way.
   One hairline, one radius, same as every card on the model pages. */
#ff-sp.ffc-layout .fixfactor-sticky-sidebar {
    position: static;
    top: auto;
    /* Overlaps the band by 32px so the card is clearly the next step out of the
       hero, not a separate slab that happens to follow it. */
    margin-top: -32px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 336px;
    grid-template-areas:
        "vars  buy"
        "ful   buy";
    border: 1px solid var(--border-neutral);
    border-radius: var(--radius, 12px);
    padding: 0;
    margin-bottom: 8px;
    overflow: hidden;
    background: var(--surface);
}

/* No variants, no empty row above the options. */
#ff-sp.ffc-layout.ffc-novars .fixfactor-sticky-sidebar {
    grid-template-areas: "ful buy";
}

/* Top-aligned. Centring it made the panel look like it was trying to hide the
   fact that the buy column is taller; reading order beats symmetry here. */
#ff-sp.ffc-layout.ffc-novars .ffc-fulfil { align-content: start; }

#ff-sp.ffc-layout .fixfactor-variations { grid-area: vars; padding: 32px 32px 0; margin: 0; }
#ff-sp.ffc-layout .ffc-fulfil { grid-area: ful; padding: 32px; margin: 0; }

/* One column, not two stacked cells. Price and action used to sit in separate
   grid rows whose heights were set by the options and the routes beside them,
   which parked the button up to 115px below the figure it acts on. */
#ff-sp.ffc-layout .ffc-buy { grid-area: buy; }
#ff-sp.ffc-layout .fixfactor-price-section,
#ff-sp.ffc-layout .fixfactor-cta-section { grid-area: auto; }

/* The tint and the hairline belong to the column now, not to each section.
   Both sections carry background:white from the old sidebar, which painted a
   seam across the column wherever a section ended. */
#ff-sp.ffc-layout .ffc-buy {
    /* Variant A: a flat tonal step brings the transactional column forward
       without relying on shadow, lift or a decorative accent edge. */
    background: color-mix(in srgb, var(--surface-alt) 42%, var(--surface-fill) 58%);
    border-left: 1px solid var(--border-neutral);
}

#ff-sp.ffc-layout .ffc-buy .fixfactor-price-section,
#ff-sp.ffc-layout .ffc-buy .fixfactor-cta-section {
    background: transparent;
}

#ff-sp.ffc-layout .fixfactor-price-section { padding: 32px 32px 0; }
#ff-sp.ffc-layout .fixfactor-cta-section { padding: 20px 32px 32px; border-left: 0; }

/* Negotiate Price stops floating beside the card logos and becomes a quiet
   chip under the price, in the warm accent it already used. */
#ff-sp.ffc-layout .fixfactor-payment-methods {
    margin: 16px 0 0;
    padding: 0;
    border-bottom: 0;
    flex-wrap: wrap;
}

#ff-sp.ffc-layout .fixfactor-payment-methods { align-items: flex-start; }

#ff-sp.ffc-layout .fixfactor-no-price .fixfactor-sticky-sidebar,
#ff-sp.ffc-layout.fixfactor-no-price .fixfactor-sticky-sidebar {
    display: block;
    border: 0;
    background: transparent;
}

/* --- facts column ---------------------------------------------------------- */

/* Not sticky. It is a card of standing facts, not a control the reader needs
   in view while they scroll the description. */
#ff-sp.ffc-layout .fixfactor-badges {
    display: block;
    align-self: start;
    position: static;
    margin: 32px 0 0;
    border: 1px solid var(--ff-tile-border);
    border-radius: var(--radius, 12px);
    padding: 4px 20px;
    background: var(--surface);
}

#ff-sp.ffc-layout .fixfactor-badge {
    border: 0;
    border-radius: 0;
    padding: 14px 0;
    display: block;
}

#ff-sp.ffc-layout .fixfactor-badge + .fixfactor-badge {
    border-top: 1px solid var(--hair, rgba(0, 170, 196, 0.16));
}

#ff-sp.ffc-layout .fixfactor-badge-title { font-size: 15px; font-weight: 800; letter-spacing: -0.2px; }
#ff-sp.ffc-layout .fixfactor-badge-subtitle { font-size: 12px; margin-top: 4px; line-height: 1.4; }

/* --- the buy bar ----------------------------------------------------------- */

#ff-sp .ffc-buybar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: var(--z-sticky, 900);
    background: color-mix(in srgb, var(--surface) 97%, transparent);
    backdrop-filter: blur(10px);
    border-top: 1px solid var(--hair, rgba(0, 170, 196, 0.16));
    box-shadow: 0 -6px 22px var(--shadow-colour);
    transform: translateY(102%);
    transition: transform 0.22s ease;
}

#ff-sp .ffc-buybar[hidden] { display: block; }
#ff-sp .ffc-buybar.is-visible { transform: translateY(0); }

#ff-sp .ffc-buybar-inner {
    max-width: 1140px;
    margin: 0 auto;
    padding: 12px var(--ff-space-xl);
    display: flex;
    align-items: center;
    gap: 16px;
}

/* The whole device, small — not a crop. The image is proportional (medium
   size); the cap is the bar's inner height, width follows the aspect ratio. */
#ff-sp .ffc-buybar-thumb {
    width: auto;
    height: 32px;
    max-width: 44px;
    object-fit: contain;
    flex: 0 0 auto;
}

#ff-sp .ffc-buybar-text { min-width: 0; }

#ff-sp .ffc-buybar-text b {
    display: block;
    font-size: 14px;
    font-weight: 700;
    line-height: 1.25;
    color: var(--content);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

#ff-sp .ffc-buybar-text span {
    display: block;
    font-size: 12px;
    color: var(--content-secondary);
    margin-top: 2px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

#ff-sp .ffc-buybar-price {
    margin-left: auto;
    font-size: 20px;
    font-weight: 800;
    letter-spacing: -0.5px;
    white-space: nowrap;
}

#ff-sp .ffc-buybar-price .woocommerce-Price-amount { font-size: inherit; font-weight: inherit; color: inherit; }

#ff-sp .ffc-buybar-cta {
    flex: 0 0 auto;
    height: 46px;
    padding: 0 24px;
    border: 0;
    border-radius: var(--radius, 12px);
    background: var(--action);
    color: var(--on-action);
    font-family: inherit;
    font-size: 15px;
    font-weight: 700;
    cursor: pointer;
}

#ff-sp .ffc-buybar-cta:hover { background: var(--action-hover, #00697e); }

/*
 * Nothing here moves the chat bubble any more.
 *
 * This file used to lift it 88px while the buy bar was up, because the bubble
 * sits bottom-right and landed on the checkout button. Removed 15 Aug 2026 on
 * the owner's call: the widget keeps whatever position Chaty's own settings
 * give it, on every device. If the overlap becomes a problem again, the fix
 * belongs in Chaty's settings - not in a stylesheet fighting them.
 */

/* --- phone ----------------------------------------------------------------- */

@media (max-width: 900px) {
    #ff-sp.ffc-layout,
    #ff-sp.ffc-layout.ffc-no-media {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-areas:
            "head media"
            "lead lead"
            "conf conf"
            "body body"
            "facts facts"
            "rel  rel";
        column-gap: 16px;
    }

    #ff-sp.ffc-layout .fixfactor-product-grid { display: contents; }
    #ff-sp.ffc-layout .fixfactor-product-header { padding-top: 20px; }
    #ff-sp.ffc-layout .fixfactor-product-header h1 { font-size: 26px; letter-spacing: -0.6px; }
    /* Match the media's top edge to the padded title rather than the grid row.
       The previous 4px margin left device images almost touching the breadcrumb
       while the heading itself started 20px lower. The 24px lower reserve keeps
       the device distinct from the description when that row becomes white. */
    #ff-sp.ffc-layout .ffc-media {
        contain: none;
        align-self: center;
        width: 92px;
        margin: 22px 0 24px;
    }
    #ff-sp.ffc-layout .ffc-media-visual {
        width: 100%;
        height: auto;
        margin-top: 0;
    }
    #ff-sp.ffc-layout .ffc-media-img,
    #ff-sp .ffc-art { width: 100%; height: auto; }
    #ff-sp.ffc-layout .ffc-service-swatch {
        --ffc-swatch-edge-offset: 3px;
        left: 16%;
        bottom: 3%;
        width: 56px;
        height: 56px;
        transform: translateX(-40%);
    }
    #ff-sp.ffc-layout .ffc-service-swatch svg { width: 40px; height: 40px; }
    #ff-sp.ffc-layout .ffc-service-swatch-mark {
        right: -1px;
        bottom: -1px;
        width: 10px;
        height: 10px;
    }
    /* The laptop shot: a fifth larger, and flush with the left edge of the
       copy - the phone layout centred it, which read as misaligned against
       left-set text. */
    #ff-sp.ffc-layout .ffc-media.is-laptop {
        width: 110px;
        align-self: start;
        justify-self: start;
        justify-content: flex-start;
    }
    #ff-sp.ffc-layout .ffc-media.is-landscape:not(.is-laptop) { width: 132px; max-width: 132px; }
    /* Keep the title on two lines at 390px; the desktop silhouette carries the
       requested size increase without costing the mobile heading its measure. */
    #ff-sp.ffc-layout .ffc-media.is-generic-laptop { width: 148px; }
    #ff-sp.ffc-layout .ffc-media.is-generic-phone {
        width: 96px;
        height: 160px;
    }
    #ff-sp.ffc-layout .ffc-media.is-generic-phone .ffc-media-visual {
        height: 150px;
        margin-top: 5px;
    }
    #ff-sp.ffc-layout .ffc-media.is-generic-phone .ffc-generic-device-img {
        height: 100%;
    }
    #ff-sp.ffc-layout .ffc-media.is-generic-laptop .ffc-service-swatch {
        left: 16%;
        bottom: 1%;
    }
    #ff-sp.ffc-layout .ffc-media.is-generic-phone .ffc-service-swatch {
        left: 5%;
        bottom: 5%;
    }
    #ff-sp.ffc-layout .fixfactor-product-header { min-width: 0; }
    #ff-sp.ffc-layout .fixfactor-hero-ratings { flex-wrap: wrap; gap: 10px 14px; margin-top: 10px; }
    #ff-sp.ffc-layout .fixfactor-short-description { padding-bottom: 16px; }
    /* On a phone the tinted band stops at the title. The short description is
       several paragraphs of prose here, and 800px of it on a coloured field
       before the customer reaches a price is a wall, not a hero. */
    #ff-sp.ffc-layout .ffc-hero-bg { margin-inline: calc(50% - 50vw); grid-row: 1 / 2; }

    /* One column, in the order the decision is made: what, how, then pay. */
    /* Specificity, not order, decides here: the .ffc-novars rule above carries
       one class more, so the phone case has to be stated for both. */
    #ff-sp.ffc-layout .fixfactor-sticky-sidebar,
    #ff-sp.ffc-layout.ffc-novars .fixfactor-sticky-sidebar {
        grid-template-columns: 1fr;
        grid-template-rows: none;
        margin-top: 20px;
    }

    #ff-sp.ffc-layout .fixfactor-sticky-sidebar { grid-template-areas: "vars" "ful" "buy"; }
    #ff-sp.ffc-layout.ffc-novars .fixfactor-sticky-sidebar { grid-template-areas: "ful" "buy"; }

    #ff-sp.ffc-layout .fixfactor-variations { padding: 20px 16px 0; }
    #ff-sp.ffc-layout .ffc-fulfil { padding: 20px 16px; }
    #ff-sp.ffc-layout .ffc-buy { border-left: 0; border-top: 1px solid var(--border-neutral); }
    #ff-sp.ffc-layout .fixfactor-price-section { padding: 20px 16px 0; }
    #ff-sp.ffc-layout .fixfactor-cta-section { padding: 16px 16px 20px; }
    #ff-sp.ffc-layout .fixfactor-badges { position: static; margin: 28px 0 0; }
    #ff-sp.ffc-layout section.fixfactor-description { margin-top: 28px; }
    #ff-sp.ffc-layout .fixfactor-related { margin-top: 32px; padding-bottom: 40px; }
    #ff-sp.ffc-layout .fixfactor-short-description { padding: 12px 0 28px; }
    #ff-sp.ffc-layout .ffc-media.is-art { width: 152px; }

    #ff-sp .ffc-buybar-inner { padding: 8px var(--ff-space-lg); gap: 12px; }
    #ff-sp .ffc-buybar-text { display: none; }
    #ff-sp .ffc-buybar-thumb { display: none; }
    #ff-sp .ffc-buybar-price { margin-left: 0; font-size: 19px; }
    #ff-sp .ffc-buybar-cta { margin-left: auto; padding: 0 16px; font-size: 14px; height: 44px; }
}


/* --- stage 3: the last three gaps against proposal C ----------------------- */

/* Two-tone heading, as on the model pages. */
#ff-sp.ffc-layout .ffc-h1-svc { color: var(--action); }

/* Negotiate Price: the yellow-outlined pill floated beside the card marks and
   read as a second CTA. It is an invitation, not an action — warm chip, under
   the price, out of the way of the button that matters. */
#ff-sp.ffc-layout .fixfactor-negotiate-btn {
    display: inline-flex;
    align-items: center;
    height: auto;
    min-height: 0;
    padding: 7px 13px;
    border: 0;
    border-radius: 6px;
    background: var(--wash-warm);
    color: var(--accent-warm-text, #996f00);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: normal;
    text-transform: none;
    box-shadow: none;
    cursor: pointer;
}

#ff-sp.ffc-layout .fixfactor-negotiate-btn:hover {
    background: var(--wash-warm-strong);
    color: var(--accent-warm-text, #996f00);
    box-shadow: none;
    transform: none;
}

/* --- the no-price branch, laid out like the priced one --------------------- */

/*
 * Two columns, not two stacked slabs. The form is the transaction here, so it
 * takes a column of its own — 420px, the width a name/email/phone/message set
 * actually wants — while the left column explains why there is no figure. The
 * old shape put a "Request a Quote" button above a full-width form whose only
 * job was to scroll down to it: two calls to action, one of them a no-op.
 */
#ff-sp.ffc-layout.fixfactor-no-price .fixfactor-sticky-sidebar {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 460px;
    grid-template-areas: "steps form";
    border: 1px solid var(--card-border, rgba(0, 170, 196, 0.4));
    border-radius: var(--radius, 12px);
    background: var(--surface);
    overflow: hidden;
}

#ff-sp.ffc-layout .ffc-quote-steps { grid-area: steps; padding: 32px; }

#ff-sp.ffc-layout .ffc-quote-form {
    grid-area: form;
    padding: 32px;
    margin: 0;
    background: var(--surface-alt);
    border-left: 1px solid var(--hair, rgba(0, 170, 196, 0.16));
    border-top: 0;
}

/* The steps sit under a rule, so the two halves of the left column read as
   "why there is no price" then "what happens next". */
#ff-sp.ffc-layout .ffc-steps-legend {
    margin-top: 20px;
    padding-top: 20px;
    border-top: 1px solid var(--hair, rgba(0, 170, 196, 0.16));
}

#ff-sp.ffc-layout .ffc-steps { list-style: none; margin: 0; padding: 0; }

#ff-sp.ffc-layout .ffc-steps li {
    display: flex;
    gap: 12px;
    padding: 12px 0;
    font-size: 14.5px;
    line-height: 1.6;
}

#ff-sp.ffc-layout .ffc-steps li + li { border-top: 1px solid var(--hair, rgba(0, 170, 196, 0.16)); }
#ff-sp.ffc-layout .ffc-steps b { display: block; font-size: 15px; color: var(--content); }
#ff-sp.ffc-layout .ffc-steps span span { display: block; font-size: 13.5px; color: var(--content-secondary); }

#ff-sp.ffc-layout .ffc-step-n {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    margin-top: 2px;
    border-radius: 50%;
    background: var(--wash-brand-soft);
    color: var(--action);
    font-size: 12px;
    font-weight: 800;
}

#ff-sp.ffc-layout .ffc-noprice {
    margin: 0;
    font-size: 22px;
    font-weight: 800;
    letter-spacing: -0.5px;
    line-height: 1.25;
    color: var(--content);
}

#ff-sp.ffc-layout .ffc-noprice-why {
    margin: 8px 0 0;
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--content-secondary);
}


/* --- stage 5: card badge, one icon per card, the line under the button ----- */

/*
 * The reassurance line was 14px grey with a filled 20px teal cube — the icon
 * read louder than the sentence. Proposal C gives it a 16px stroked shield in
 * the same ink as the text, so the mark supports the sentence instead of
 * competing with the button above it.
 */
#ff-sp.ffc-layout .fixfactor-conditional-info {
    align-items: flex-start;
    gap: 8px;
    padding: 0;
    margin-top: 12px;
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--content-secondary);
}

#ff-sp.ffc-layout .fixfactor-conditional-info .status-icon {
    width: 16px;
    height: 16px;
    margin-top: 2px;
    color: inherit;
    opacity: 1;
}

#ff-sp.ffc-layout .fixfactor-conditional-info-content { line-height: inherit; }

/* Bigger, lighter, and keyed to the service. The old plate was 300px of dark
   rectangle on a pale band; this one is a rendered object over a measurement
   field, so it can carry detail without weighing the hero down. */
/*
 * The artwork is wide, not tall, and it is drawn rather than photographed —
 * it can carry a bigger box than a device cut-out without crowding the copy,
 * and it has no height to be clamped by, so it sizes on width like a picture.
 */
#ff-sp.ffc-layout .ffc-media.is-art {
    contain: none;
    align-self: center;
    width: clamp(240px, 26vw, 384px);
    max-width: 384px;
}

#ff-sp.ffc-layout .ffc-media.is-art .ffc-art { width: 100%; height: auto; }

/* Same rule as the photograph: scale by height, cap on width. The figure then
   holds nothing but the drawing, with no letterboxing to align around. */
#ff-sp .ffc-art {
    display: block;
    height: 100%;
    width: auto;
    max-width: 100%;
}


/* The artwork is a wide composition, the device photographs are tall cut-outs.
   A 300px track that suits one starves the other, so the column widens only on
   the pages that carry artwork. */
#ff-sp.ffc-layout:has(.ffc-media.is-art) { grid-template-columns: minmax(0, 1fr) 384px; }


/* --- stage 6: white hero, one facts card, buy column on a 20px rhythm ------ */

/*
 * The column is one flow, so the padding belongs to the column and the two
 * sections inside it only carry rhythm. Price, payment marks, chip, button and
 * the reassurance line then sit on the proposal's 32 / 16 / 20 / 20 / 12 —
 * before this the chip was a flex child of the payment row and landed wherever
 * the card marks left it.
 */
#ff-sp.ffc-layout .ffc-buy { padding: 32px; }

#ff-sp.ffc-layout .ffc-buy .fixfactor-price-section,
#ff-sp.ffc-layout .ffc-buy .fixfactor-cta-section {
    padding: 0;
    margin: 0;
    background: transparent;
    border: 0;
}

#ff-sp.ffc-layout .ffc-buy .fixfactor-price { font-size: 40px; letter-spacing: -1.2px; line-height: 1; }
#ff-sp.ffc-layout .ffc-buy .fixfactor-price.range { font-size: 28px; }
#ff-sp.ffc-layout .ffc-buy .fixfactor-price-row { margin: 0; }

#ff-sp.ffc-layout .ffc-buy .fixfactor-payment-methods {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 16px 0 0;
    padding: 0;
    border: 0;
}

#ff-sp.ffc-layout .ffc-buy .fixfactor-negotiate-btn {
    display: inline-flex;
    width: auto;
    margin: 20px 0 0;
}

#ff-sp.ffc-layout .ffc-buy .fixfactor-cta-section { margin-top: 20px; }

#ff-sp.ffc-layout .ffc-buy .fixfactor-main-cta {
    height: 56px;
    padding: 0 20px;
    margin: 0;
    font-size: 16.5px;
    font-weight: 700;
    border-radius: var(--radius, 12px);
}

#ff-sp.ffc-layout .ffc-buy .fixfactor-main-cta.active:hover {
    background: var(--action-hover);
    transform: none;
}

@media (max-width: 900px) {
    #ff-sp.ffc-layout .ffc-buy { padding: 20px 16px; }
    #ff-sp.ffc-layout .ffc-buy .fixfactor-main-cta { height: 52px; font-size: 16px; }
}


/* --- stage 7: the quote form gets a column ---------------------------------- */

/* Inputs inherit the site's form styling; only the frame around them is new. */
#ff-sp.ffc-layout .ffc-quote-form .wpforms-container,
#ff-sp.ffc-layout .ffc-quote-form .wpforms-form { max-width: 100%; }

/* Both the section and its inner wrapper carried background:white and 24px of
   padding from the old full-width layout, which painted a white slab around
   the fields. The column keeps the tint; nothing inside it paints. */
#ff-sp.ffc-layout section.ffc-quote-form {
    background: var(--surface-alt);
    border-radius: 0;
}

#ff-sp.ffc-layout .ffc-quote-form .fixfactor-form-content {
    margin-top: 4px;
    padding: 0;
    background: transparent;
}

#ff-sp.ffc-layout .ffc-quote-form .wpforms-field { margin-bottom: 12px; }

/* On a tinted column a #d1d5db hairline all but disappears — the fields read
   as gaps rather than inputs. One stop darker, and white inside so each field
   is clearly a place to type. */
#ff-sp.ffc-layout .ffc-quote-form .wpforms-field input,
#ff-sp.ffc-layout .ffc-quote-form .wpforms-field textarea,
#ff-sp.ffc-layout .ffc-quote-form .wpforms-field select {
    border: 1.5px solid light-dark(#b4c2c9, rgba(255, 255, 255, 0.28)) !important;
    border-radius: var(--radius-input, 10px) !important;
    background: var(--surface) !important;
}

#ff-sp.ffc-layout .ffc-quote-form .wpforms-field textarea { min-height: 104px !important; }

#ff-sp.ffc-layout .ffc-quote-form .wpforms-field label,
#ff-sp.ffc-layout .ffc-quote-form .wpforms-field-label {
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: 0.01em;
    margin-bottom: 6px;
    color: var(--content-body, #1a1a1a);
}

#ff-sp.ffc-layout .ffc-quote-form .wpforms-submit-container {
    margin-top: 4px;
    padding: 0;
    text-align: left;
}

#ff-sp.ffc-layout .ffc-quote-form .wpforms-submit {
    min-height: 52px !important;
    border-radius: var(--radius, 12px) !important;
    font-size: 16px !important;
}

#ff-sp.ffc-layout .ffc-quote-form .wpforms-submit:hover { transform: none !important; }

#ff-sp.ffc-layout .ffc-form-fallback {
    padding: 16px;
    border: 1px solid var(--tile-border, #c8e4e8);
    border-radius: var(--radius, 12px);
    background: var(--surface);
    font-size: 14px;
    line-height: 1.6;
}

/* Phones: one column, and the form last — the explanation earns the scroll. */
@media (max-width: 900px) {
    #ff-sp.ffc-layout.fixfactor-no-price .fixfactor-sticky-sidebar {
        grid-template-columns: 1fr;
        grid-template-areas: "steps" "form";
    }

    #ff-sp.ffc-layout .ffc-quote-steps { padding: 20px 16px; }

    #ff-sp.ffc-layout .ffc-quote-form {
        padding: 20px 16px;
        border-left: 0;
        border-top: 1px solid var(--hair, rgba(0, 170, 196, 0.16));
    }

    #ff-sp.ffc-layout .ffc-quote-form .wpforms-field { margin-bottom: 10px; }
    #ff-sp.ffc-layout .ffc-quote-form .wpforms-field textarea { min-height: 92px !important; }
}


/* The focused field is the only one that matters, so it says so in the brand
   colour and a heavier edge — the base 2px teal border was being outranked by
   the tinted-column rule above. */
#ff-sp.ffc-layout .ffc-quote-form .wpforms-field input:focus,
#ff-sp.ffc-layout .ffc-quote-form .wpforms-field textarea:focus,
#ff-sp.ffc-layout .ffc-quote-form .wpforms-field select:focus {
    border: 2.5px solid var(--accent) !important;
    box-shadow: var(--focus-ring) !important;
    outline: none !important;
}

/* The artwork carries its own width rule declared after the phone block, so the
   phone value has to be restated or a 390px screen gets a 240px drawing. */
@media (max-width: 900px) {
    #ff-sp.ffc-layout .ffc-media.is-art { width: 148px; }
}


/* Content callouts (R0 restore). The P5 clean-up stripped the inline-styled
   boxes that authors had used for "please note" content; the class was added
   back in post_content and the visual lives here, on tokens instead of the
   old literal hexes. Two voices: informational (teal) and warning (amber). */
#ff-sp .ffx-callout {
    padding: 14px 18px;
    margin: 18px 0;
    background: var(--chrome-fill-faint, #f2fafb);
    border-left: 3px solid var(--accent, #00aac4);
    border-radius: 0 10px 10px 0;
}

#ff-sp .ffx-callout--warning {
    /* Amber wash has no token equivalent; single local literal per the rules. */
    --ffx-callout-warm-bg: var(--surface-warm);
    background: var(--ffx-callout-warm-bg);
    border-left-color: var(--accent-warm, #ffd100);
}

#ff-sp .ffx-callout > :first-child { margin-top: 0; }
#ff-sp .ffx-callout > :last-child { margin-bottom: 0; }


/* What-we-test component (R2). Handover checks rendered from config in
   fixfactor-core (service-tests.php) — a quiet checklist, not a callout:
   the teal check marks carry the meaning, the background stays plain. */
#ff-sp .ffx-tests { margin: 26px 0 6px; }

#ff-sp .ffx-tests h3 { margin: 0 0 12px; }

#ff-sp .ffx-tests-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px 22px;
}

#ff-sp .ffx-tests-list li {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin: 0;
}

/* The check is CSS, not markup: a mask filled with the accent token, so the
   same plain <li> works from the PHP renderer and from converted content. */
#ff-sp .ffx-tests-list li::before {
    content: '';
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    margin-top: 2px;
    background-color: var(--accent, #00aac4);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'%3E%3Ccircle cx='10' cy='10' r='9' stroke='%23000' stroke-width='1.6'/%3E%3Cpath d='M6 10.4l2.6 2.6L14 7.6' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'%3E%3Ccircle cx='10' cy='10' r='9' stroke='%23000' stroke-width='1.6'/%3E%3Cpath d='M6 10.4l2.6 2.6L14 7.6' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

@media (max-width: 900px) {
    #ff-sp .ffx-tests-list { grid-template-columns: 1fr; }
}

/* Symptom-page link — Layer 4, mini-card variant (chosen 17 Aug 2026).
   Speaks the related-cards language exactly: same tile border, radius,
   and hover (accent border + alt fill) as .ffrr-link. Question sits quiet
   on the left, the action label + arrow on the right; the arrow gives the
   design system's functional nudge on hover. Sits above the PCB
   decoration, hence the stacking context. */
#ff-sp .ff-symptom-note {
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 6px 12px;
    margin: 22px 0 0;
    padding: 12px 16px;
    border: 1px solid var(--ff-tile-border);
    border-radius: var(--radius, 12px);
    background: var(--surface);
    font-size: 0.95rem;
    line-height: 1.5;
    text-decoration: none;
    transition: border-color .15s ease, background-color .15s ease;
}

#ff-sp .ff-symptom-note:hover,
#ff-sp .ff-symptom-note:focus-visible {
    border-color: var(--accent);
    background: var(--surface-alt);
}

#ff-sp .ff-symptom-q { color: var(--content-secondary); }

#ff-sp .ff-symptom-go {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--action);
    font-weight: 600;
    white-space: nowrap;
}

#ff-sp .ff-symptom-go svg { transition: transform .15s ease; }

#ff-sp .ff-symptom-note:hover .ff-symptom-go svg,
#ff-sp .ff-symptom-note:focus-visible .ff-symptom-go svg { transform: translateX(3px); }

@media (prefers-reduced-motion: reduce) {
    #ff-sp .ff-symptom-note,
    #ff-sp .ff-symptom-go svg { transition: none; }
    #ff-sp .ff-symptom-note:hover .ff-symptom-go svg { transform: none; }
}
