/*
 * Data Recovery cluster - shared component styles.
 *
 * Loaded on /data-recovery/ and every page beneath it. See
 * includes/core/dr-cluster-assets.php for the enqueue condition.
 *
 * Scope: every selector sits under #ff-dr, the wrapper the cluster pages carry
 * on their outermost element. That is for readability and so the sheet can be
 * lifted out as a component later - not for winning a specificity fight. There
 * is no theme left to out-shout, so nothing here uses !important.
 *
 * Tokens: Layer 2 semantic vocabulary only (--surface, --content, --action,
 * --accent, --border-*). The cluster pages declare these on #ff-dr.
 */

/* =============================================================================
   WHY FIXFACTOR - evidence photo beside four load-bearing facts
   Markup: section.fixfactor-why-us > .ff-why-split
             > figure.ff-why-evidence (img + figcaption)
             > .ff-why-facts > .ff-why-fact (span.ff-why-tag + h3 + p)
   ========================================================================== */

#ff-dr .ff-why-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    gap: clamp(2.5rem, 5vw, 4.5rem);
    align-items: start;
}

/* --- Evidence photo ------------------------------------------------------ */

#ff-dr .ff-why-evidence {
    margin: 0;
}

#ff-dr .ff-why-evidence img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 12px;
}

#ff-dr .ff-why-evidence figcaption {
    max-width: 46ch;
    margin-top: 0.85rem;
    color: var(--content-secondary);
    font-size: 0.9rem;
    line-height: 1.5;
}

/* --- Fact column --------------------------------------------------------- */

#ff-dr .ff-why-facts {
    display: grid;
    gap: clamp(1.75rem, 3vw, 2.5rem);
}

#ff-dr .ff-why-fact {
    min-width: 0;
}

#ff-dr .ff-why-tag {
    display: block;
    margin-bottom: 0.4rem;
    color: var(--accent-art);
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.02em;
}

#ff-dr .ff-why-fact h3 {
    margin: 0 0 0.5rem;
    color: var(--content-strong);
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1.3;
    letter-spacing: -0.01em;
}

#ff-dr .ff-why-fact p {
    max-width: 58ch;
    margin: 0;
    color: var(--content-body);
    font-size: 1rem;
    line-height: 1.6;
}

/* --- Stack below the primary breakpoint ---------------------------------- */

@media (max-width: 900px) {
    #ff-dr .ff-why-split {
        grid-template-columns: 1fr;
        gap: 2.25rem;
    }

    #ff-dr .ff-why-facts {
        gap: 1.75rem;
    }
}

@media (max-width: 576px) {
    #ff-dr .ff-why-fact h3 {
        font-size: 1.15rem;
    }
}

/* =============================================================================
   CASE STUDIES - tab strip
   The CSS-only radio tabs were drawn as detached folder tabs: 6.4px gaps, a
   top-only radius, an upward box-shadow, translateY(-3px) on hover and
   translateY(-5px) plus an extra 0.1rem of padding on the active one. Three
   consequences, all visible: the active tab sat five pixels above its
   neighbours, the strip wrapped onto two rows at 1440px and four at 390px, and
   switching tabs changed the strip's height, so everything below it moved.

   Replaced with one scrolling row on a shared rule, the active tab marked by
   its own bottom border. Nothing moves when you switch.
   ========================================================================== */

#ff-dr .fixfactor-tabs input[type="radio"] {
    /* Was display:none, which removed the radios from the tab order - the case
       studies could not be reached or switched from a keyboard at all. Clipped
       instead: invisible, still focusable. */
    display: block;
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* Strip and panel are one card. The strip is a tinted header band on it and
   the selected tab is the one that shares the panel's surface, so the two read
   as continuous instead of as a row of chips hovering above a box. */
#ff-dr .fixfactor-tabs-container {
    background: var(--surface);
    border: 1px solid var(--border-neutral);
    border-radius: 14px;
    overflow: hidden;
}

#ff-dr .fixfactor-tabs-labels {
    display: flex;
    flex-wrap: nowrap;
    justify-content: flex-start;
    gap: 0;
    margin: 0;
    padding: 0;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    background: var(--surface-alt);
    border-bottom: 1px solid var(--border-neutral);
}

#ff-dr .fixfactor-tabs-labels::-webkit-scrollbar {
    display: none;
}

#ff-dr .fixfactor-tabs-label {
    flex: 0 0 auto;
    margin: 0 0 -1px;
    padding: 1.05rem 1.35rem;
    background: none;
    border: 0;
    border-bottom: 1px solid transparent;
    border-radius: 0;
    box-shadow: none;
    transform: none;
    color: var(--content-secondary);
    font-size: 0.9375rem;
    font-weight: 600;
    letter-spacing: -0.005em;
    white-space: nowrap;
    scroll-snap-align: start;
    transition: color 0.18s ease, background-color 0.18s ease;
}

#ff-dr .fixfactor-tabs-label:hover {
    transform: none;
    color: var(--content-strong);
    background: rgba(0, 0, 0, 0.025);
}

#ff-dr #case1:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case1,
#ff-dr #case2:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case2,
#ff-dr #case3:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case3,
#ff-dr #case4:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case4,
#ff-dr #case5:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case5,
#ff-dr #case6:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case6 {
    /* The selected tab carries the panel's surface and covers the band's
       bottom rule, which is what joins it to the content below. Padding is
       identical to the inactive tabs, so the strip keeps its height and the
       panel does not jump when you switch. */
    padding: 1.05rem 1.35rem;
    background: var(--surface);
    transform: none;
    color: var(--action);
    font-weight: 700;
    border-bottom-color: var(--surface);
}

/* The separate 3px ::after bar is what the bottom border does now. */
#ff-dr #case1:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case1::after,
#ff-dr #case2:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case2::after,
#ff-dr #case3:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case3::after,
#ff-dr #case4:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case4::after,
#ff-dr #case5:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case5::after,
#ff-dr #case6:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case6::after {
    content: none;
}

#ff-dr #case1:focus-visible ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case1,
#ff-dr #case2:focus-visible ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case2,
#ff-dr #case3:focus-visible ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case3,
#ff-dr #case4:focus-visible ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case4,
#ff-dr #case5:focus-visible ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case5,
#ff-dr #case6:focus-visible ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case6 {
    outline: 3px solid var(--accent);
    outline-offset: -3px;
}

/* The wrapper owns the frame now. */
#ff-dr .fixfactor-case-content {
    margin: 0;
    border: 0;
    border-radius: 0;
    box-shadow: none;
}

/* --- Panel: header ------------------------------------------------------- */

#ff-dr .fixfactor-case-header {
    padding: clamp(1.75rem, 3vw, 2.5rem) clamp(1.5rem, 3vw, 2.5rem) 0;
    border-bottom: 0;
    text-align: left;
}

#ff-dr .fixfactor-case-title {
    margin: 0 0 1rem;
    color: var(--content);
    font-size: clamp(1.35rem, 2.2vw, 1.75rem);
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: -0.02em;
}

/* Metadata reads as one line of facts. Wide gaps do the separating - no rules,
   no pills; these are not actions and must not look like any. */
#ff-dr .fixfactor-case-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1rem;
    margin: 0 0 1.1rem;
}

#ff-dr .fixfactor-case-meta-item {
    display: inline-flex;
    align-items: center;
    gap: 1rem;
    color: var(--content-body);
    font-size: 0.875rem;
}

/* Hairline between facts, set at the same distance on both sides. */
#ff-dr .fixfactor-case-meta-item + .fixfactor-case-meta-item::before {
    content: "";
    flex: 0 0 auto;
    width: 1px;
    height: 1em;
    background: var(--border-neutral);
}

/* The four glyphs come from two different icon sets - calendar and database
   are solid, clock and pie chart are line drawings - so at 15px the row read
   as two blobs and two outlines. They label text that already says the same
   thing, so the row is stronger without them. */
#ff-dr .fixfactor-case-meta-item svg {
    display: none;
}

#ff-dr .fixfactor-case-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0;
}

#ff-dr .fixfactor-case-tag {
    padding: 0.3rem 0.7rem;
    background: var(--surface-alt);
    border: 1px solid var(--border-neutral);
    border-radius: 999px;
    color: var(--content-secondary);
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.4;
}

/* --- Panel: body --------------------------------------------------------- */

#ff-dr .fixfactor-case-body {
    display: block;
    padding: clamp(1.5rem, 3vw, 2rem) clamp(1.5rem, 3vw, 2.5rem) 0;
}

#ff-dr .fixfactor-case-image-large {
    height: auto;
    margin: 0 0 clamp(1.5rem, 3vw, 2rem);
    background: var(--surface-alt);
    border-radius: 12px;
    overflow: hidden;
}

/* The source images are 600x400. Full-bleed across a 1256px panel they were
   blown up past their pixel width and cropped by nothing. A fixed ratio with
   object-fit gives a calm editorial band instead. */
#ff-dr .fixfactor-case-image-large img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 7;
    object-fit: cover;
}

/* Measure. The body ran the full 1256px - about 160 characters a line. */
#ff-dr .fixfactor-case-content-wrap {
    max-width: 72ch;
    padding: 0;
}

#ff-dr .fixfactor-case-description {
    margin: 0 0 1.75rem;
    color: var(--content-body);
    font-size: 1.0625rem;
    line-height: 1.7;
}

#ff-dr .fixfactor-case-section {
    margin: 0 0 1.6rem;
}

/* "The Challenge" and "Our Solution" are labels for a spine the reader scans,
   not headings competing with the case title. */
#ff-dr .fixfactor-case-section-title {
    margin: 0 0 0.5rem;
    color: var(--accent-art);
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

#ff-dr .fixfactor-case-section-text {
    margin: 0;
    color: var(--content-body);
    font-size: 1rem;
    line-height: 1.7;
}

/* --- Panel: quote -------------------------------------------------------- */

#ff-dr .fixfactor-case-testimonial {
    max-width: 72ch;
    margin: 0 clamp(1.5rem, 3vw, 2.5rem) clamp(1.75rem, 3vw, 2.5rem);
    padding: clamp(1.25rem, 2.5vw, 1.75rem);
    background: var(--surface-alt);
    border: 0;
    border-radius: 12px;
}

#ff-dr .fixfactor-case-quote {
    margin: 0 0 0.85rem;
    color: var(--content-strong);
    font-size: 1.0625rem;
    font-style: normal;
    line-height: 1.65;
}

#ff-dr .fixfactor-case-author {
    margin: 0;
    color: var(--content-secondary);
    font-size: 0.875rem;
    font-weight: 600;
    text-align: left;
}

/* --- Panel: footer ------------------------------------------------------- */

#ff-dr .fixfactor-case-cta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin: 0;
    padding: clamp(1.25rem, 2.5vw, 1.5rem) clamp(1.5rem, 3vw, 2.5rem);
    background: var(--surface-alt);
    border-top: 1px solid var(--border-neutral);
}

#ff-dr .fixfactor-case-cta-text {
    margin: 0;
    color: var(--content-strong);
    font-size: 1rem;
    font-weight: 600;
}

#ff-dr .fixfactor-case-cta .fixfactor-button {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem 1.35rem;
    background: var(--action);
    border: 0;
    border-radius: 10px;
    box-shadow: none;
    color: var(--on-action);
    font-size: 0.9375rem;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
    transform: none;
    transition: background-color 0.18s ease;
}

#ff-dr .fixfactor-case-cta .fixfactor-button::after {
    content: "\2192";
    transition: transform 0.18s ease;
}

#ff-dr .fixfactor-case-cta .fixfactor-button:hover {
    background: var(--action-hover);
    box-shadow: none;
    transform: none;
}

#ff-dr .fixfactor-case-cta .fixfactor-button:hover::after {
    transform: translateX(2px);
}

@media (prefers-reduced-motion: reduce) {
    #ff-dr .fixfactor-case-cta .fixfactor-button,
    #ff-dr .fixfactor-case-cta .fixfactor-button::after,
    #ff-dr .fixfactor-tabs-label {
        transition: none;
    }

    #ff-dr .fixfactor-case-cta .fixfactor-button:hover::after {
        transform: none;
    }
}

@media (max-width: 640px) {
    #ff-dr .fixfactor-tabs-container {
        border-radius: 12px;
    }

    /* One fact per line. Wrapped, the hairlines ended up at the start of the
       second and third lines, pointing at nothing. */
    #ff-dr .fixfactor-case-meta {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.3rem;
    }

    #ff-dr .fixfactor-case-meta-item + .fixfactor-case-meta-item::before {
        display: none;
    }

    #ff-dr .fixfactor-case-meta-item {
        gap: 0;
    }

    #ff-dr .fixfactor-case-image-large img {
        aspect-ratio: 3 / 2;
    }

    #ff-dr .fixfactor-case-cta {
        align-items: stretch;
        flex-direction: column;
    }

    #ff-dr .fixfactor-case-cta .fixfactor-button {
        justify-content: center;
        width: 100%;
    }
}

/* =============================================================================
   FAILURE SCENARIOS - card hover
   The cards carried skewY(-1deg) translateY(-10px) scale(1.02) on hover: the
   card tilted, rose and grew. On the hub the hover rule changed nothing at all,
   so the same component behaved three different ways across the cluster.

   One signal instead: the border comes up. Resting border is neutral so that
   the change is legible - a teal-tinted resting border made the hover state
   almost indistinguishable from it.
   ========================================================================== */

/* The hub carries .ff-dr3-hub on the wrapper and a rule at (1,2,0) that this
   has to match to reach it - hence the doubled selector on each block. */
#ff-dr .fixfactor-scenario-card,
#ff-dr.ff-dr3-hub .fixfactor-scenario-card {
    align-content: start;
    border-color: var(--border-neutral);
    transform: none;
    box-shadow: none;
    transition: border-color 0.2s ease;
}

#ff-dr .fixfactor-scenario-card:hover,
#ff-dr .fixfactor-scenario-card:focus-within,
#ff-dr.ff-dr3-hub .fixfactor-scenario-card:hover,
#ff-dr.ff-dr3-hub .fixfactor-scenario-card:focus-within {
    transform: none;
    box-shadow: none;
    border-color: var(--border-active);
}

#ff-dr .fixfactor-scenario-card:hover .fixfactor-scenario-content,
#ff-dr .fixfactor-scenario-card:hover .fixfactor-scenario-icon {
    transform: none;
}

/* =============================================================================
   FAILURE SCENARIOS - anatomy cards (.ffs)
   Markup: section.ffs > .fixfactor-container > .ffs-grid > article.ffs-card
             > .ffs-card__head  (figure tile + num + h3 + part + route)
             > .ffs-card__body  (text + "What you'll notice" + symptom list)

   Replaces .fixfactor-scenario-card on the nine device pages. That component
   put the diagram in a 96px column with the part name underneath, where
   "Data structure, not hardware" wrapped onto four lines and the column sat
   empty for the rest of the card's height. Eight of the nine pages had no
   diagram at all.

   New classes rather than a rewrite of the old ones: the old selectors live in
   three sheets across the cluster and the hub still uses them. Nothing here
   has to out-shout anything, and the old rules simply stop matching.
   ========================================================================== */

#ff-dr .ffs-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.25rem;
    margin-top: clamp(2rem, 4vw, 3rem);
}

#ff-dr .ffs-card {
    display: flex;
    flex-direction: column;
    padding: clamp(1.35rem, 2.5vw, 1.75rem);
    background: var(--surface);
    border: 1px solid var(--border-neutral);
    border-radius: 14px;
    box-shadow: none;
    transform: none;
    transition: border-color 0.2s ease;
}

#ff-dr .ffs-card:hover,
#ff-dr .ffs-card:focus-within {
    border-color: var(--border-active);
}

/* --- head: diagram tile + identity ---------------------------------------- */

#ff-dr .ffs-card__head {
    display: flex;
    align-items: center;
    gap: clamp(0.9rem, 2vw, 1.25rem);
    padding-bottom: 1.15rem;
    border-bottom: 1px solid var(--border-neutral);
}

/* The tile is what turns the drawing into a diagram. Floating on the card it
   read as an oversized icon; inside a bordered, tinted square it reads as a
   schematic of the device the card is about. */
#ff-dr .ffs-card__figure {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 6rem;
    height: 6rem;
    background: var(--surface-alt);
    border: 1px solid var(--border-neutral);
    border-radius: 12px;
}

#ff-dr .ffs-card__ident {
    display: block;
    min-width: 0;
}

#ff-dr .ffs-card__num {
    display: block;
    color: var(--accent-art);
    font-size: 0.75rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.06em;
    line-height: 1;
}

#ff-dr .ffs-card__title {
    margin: 0.4rem 0 0;
    color: var(--content);
    font-size: 1.1875rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.25;
    text-transform: none;
}

#ff-dr .ffs-card__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 0.6rem;
    margin-top: 0.5rem;
}

#ff-dr .ffs-part {
    color: var(--content-secondary);
    font-size: 0.8125rem;
    line-height: 1.4;
}

/* Two visual classes, three words. The division that matters to someone
   holding a dead drive is whether anything is physically broken - that is what
   sets the price and the risk - so "Software-level" is the odd one out and
   looks it. Colour never carries the meaning on its own: the word does. */
#ff-dr .ffs-route {
    display: inline-block;
    padding: 0.2rem 0.5rem;
    border: 1px solid var(--border-neutral);
    border-radius: 6px;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    line-height: 1.3;
    text-transform: uppercase;
    white-space: nowrap;
}

#ff-dr .ffs-route--hw {
    background: var(--chrome-fill-hover);
    border-color: var(--chrome-border);
    color: var(--accent-art);
}

#ff-dr .ffs-route--data {
    background: var(--surface-fill);
    color: var(--content-secondary);
}

/* --- body ----------------------------------------------------------------- */

#ff-dr .ffs-card__body {
    padding-top: 1.15rem;
}

#ff-dr .ffs-card__text {
    margin: 0 0 1.1rem;
    color: var(--content-body);
    font-size: 0.9375rem;
    line-height: 1.6;
}

#ff-dr .ffs-card__label {
    margin: 0 0 0.35rem;
    color: var(--content-secondary);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    line-height: 1.4;
    text-transform: uppercase;
}

/* Symptoms stay a list to read. They were turned into bordered pills once and
   turned back: pills invite a click that does nothing and cost about a third
   of the card's height in padding. See dr-hdd.css for the original note. */
#ff-dr .ffs-symptoms {
    margin: 0;
    padding: 0;
    list-style: none;
}

#ff-dr .ffs-symptoms li {
    position: relative;
    margin: 0;
    padding: 0.28rem 0 0.28rem 1.45rem;
    color: var(--content-body);
    font-size: 0.875rem;
    line-height: 1.5;
}

#ff-dr .ffs-symptoms li::before {
    content: "\2014";
    position: absolute;
    left: 0;
    color: var(--action);
    font-weight: 700;
}

/* --- the diagram itself --------------------------------------------------- */

#ff-dr .ffs .ffd-svg {
    display: block;
    width: 4.25rem;
    height: 4.25rem;
}

#ff-dr .ffs .ffd-svg .ffd-off {
    stroke: var(--border-neutral);
    stroke-width: 1.4;
}

#ff-dr .ffs .ffd-svg .ffd-on {
    stroke: var(--accent);
    stroke-width: 2.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

#ff-dr .ffs .ffd-svg .ffd-tick {
    stroke-width: 2;
}

/* Hover does one job: the diagram asserts itself. The failed part thickens and
   the intact anatomy recedes, so pointing at a card answers "where is my
   fault" harder. Nothing lifts, tilts or grows. */
#ff-dr .ffs .ffd-svg .ffd-off,
#ff-dr .ffs .ffd-svg .ffd-on {
    transition: stroke-width 0.25s ease, opacity 0.25s ease;
}

#ff-dr .ffs-card:hover .ffd-svg .ffd-off {
    opacity: 0.45;
}

#ff-dr .ffs-card:hover .ffd-svg .ffd-on {
    stroke-width: 3.4;
}

@media (max-width: 900px) {
    #ff-dr .ffs-grid {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 420px) {
    #ff-dr .ffs-card__head {
        gap: 0.85rem;
    }

    #ff-dr .ffs-card__figure {
        width: 4.5rem;
        height: 4.5rem;
    }

    #ff-dr .ffs .ffd-svg {
        width: 3rem;
        height: 3rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    #ff-dr .ffs .ffd-svg .ffd-off,
    #ff-dr .ffs .ffd-svg .ffd-on {
        transition: none;
    }
}

/* =============================================================================
   FAQ - disclosure cards (.fff)
   Markup: section.fff > .fixfactor-container
             > .fixfactor-section-header (h2 + lead)
             > .fff-list > details.fff-item > summary.fff-q + .fff-a
             > p.fff-foot

   Replaces three different implementations of one section: the hub and seven
   device pages used a checkbox+label pair, the Mac page a variant of its own,
   and only /service-policy/ and /data-recovery-partnership/ used <details>.
   The third is the one worth copying - the hub was not a model, it had the
   same problem as the pages beneath it.

   <details> over checkbox: it is a real disclosure widget, so a screen reader
   announces the expanded state instead of "checkbox"; keyboard support is
   built in; and find-in-page opens a closed answer and highlights the hit,
   which content hidden behind a checkbox cannot do.

   Each question is its own card rather than a row on a ruled list. The ruled
   version was correct and looked it - a stack of hairlines with nothing to
   hold them. The card carries the same border language as the scenario cards
   above it, and the open state moves the border to --border-active, so the
   answer you are reading is the one the eye lands on.
   ========================================================================== */

/* From the scenarios section down, every section on a device page was white -
   five in a row. The tint goes here because this is where it does two jobs at
   once: it breaks that run, and it gives the white cards something to sit on. */
#ff-dr .fixfactor-faq.fff {
    background: var(--surface-alt);
}

#ff-dr .fff-list {
    display: grid;
    gap: 0.75rem;
    max-width: 56rem;
    margin: clamp(2rem, 4vw, 3rem) auto 0;
}

#ff-dr .fff-item {
    background: var(--surface);
    border: 1px solid var(--border-neutral);
    border-radius: 14px;
    transition: border-color 0.2s ease;
}

#ff-dr .fff-item:hover,
#ff-dr .fff-item[open] {
    border-color: var(--border-active);
}

#ff-dr .fff-q {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.15rem clamp(1rem, 2vw, 1.35rem);
    border-radius: 13px;
    color: var(--content-strong);
    font-size: 1.0625rem;
    font-weight: 600;
    line-height: 1.4;
    cursor: pointer;
    list-style: none;
    transition: color 0.18s ease;
}

/* Safari still paints the default triangle without this. */
#ff-dr .fff-q::-webkit-details-marker {
    display: none;
}

#ff-dr .fff-q::after {
    content: "+";
    flex: 0 0 auto;
    color: var(--action);
    font-size: 1.35rem;
    font-weight: 400;
    line-height: 1;
}

#ff-dr .fff-item[open] > .fff-q::after {
    content: "\2013";
}

#ff-dr .fff-q:hover {
    color: var(--content);
}

#ff-dr .fff-q:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: -3px;
}

#ff-dr .fff-a {
    padding: 0 clamp(1rem, 2vw, 1.35rem) clamp(1.15rem, 2vw, 1.35rem);
}

/* The rule is a pseudo-element on the wrapper, not a border on the paragraph:
   on the paragraph it inherited the 62ch measure and stopped short of the card
   padding, which read as an unfinished line. */
#ff-dr .fff-a::before {
    content: "";
    display: block;
    height: 1px;
    margin-bottom: 1rem;
    background: var(--border-neutral);
}

#ff-dr .fff-a p {
    max-width: 62ch;
    margin: 0;
    color: var(--content-body);
    font-size: 1rem;
    line-height: 1.65;
}

#ff-dr .fff-a p + p {
    margin-top: 0.85rem;
}

#ff-dr .fff-foot {
    max-width: 56rem;
    margin: 1.5rem auto 0;
    padding: 0 clamp(1rem, 2vw, 1.35rem);
    color: var(--content-secondary);
    font-size: 0.9375rem;
    line-height: 1.6;
    text-align: left;
}

/* Progressive: browsers that can animate a disclosure do; the rest just open.
   Nothing depends on it. */
@supports selector(::details-content) {
    #ff-dr .fff-item {
        interpolate-size: allow-keywords;
    }

    #ff-dr .fff-item::details-content {
        height: 0;
        overflow: hidden;
        transition: height 0.24s ease, content-visibility 0.24s allow-discrete;
    }

    #ff-dr .fff-item[open]::details-content {
        height: auto;
    }
}

@media (prefers-reduced-motion: reduce) {
    #ff-dr .fff-item,
    #ff-dr .fff-q {
        transition: none;
    }

    @supports selector(::details-content) {
        #ff-dr .fff-item::details-content {
            transition: none;
        }
    }
}

/* =============================================================================
   FAILURE TYPES - depth scale (.ffl)   hub only
   Markup: section.ffl > .fixfactor-container
             > .fixfactor-section-header
             > .ffl-legend (scale + one sentence)
             > .ffl-grid > article.ffl-card
                 > .ffl-card__head (meter + num + h3 + route)
                 > .ffl-card__body (text + label + list)

   The device pages get an anatomy diagram: the same device four times with a
   different part lit. That does not transfer here - the hub's four cards are
   failure categories across every device, so there is no single anatomy to
   light up.

   What the four categories do have is an axis: how deep into the device the
   fault sits. The meter encodes it - four layers, the affected ones lit - and
   one legend under the header teaches the scale so the four meters read
   without repeating labels. It is a small data visual, not an icon: it carries
   information the copy does not.
   ========================================================================== */

#ff-dr .ffl-legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem clamp(1.25rem, 3vw, 2.5rem);
    max-width: 60rem;
    margin: 0 auto;
    padding: 1.1rem clamp(1rem, 2vw, 1.5rem);
    background: var(--surface);
    border: 1px solid var(--border-neutral);
    border-radius: 12px;
}

#ff-dr .ffl-legend__scale {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    flex: 0 1 auto;
    min-width: 0;
}

#ff-dr .ffl-legend__step {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--content-strong);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

/* The arrow belongs to the gap between steps, not to a step, so the last one
   does not trail one. */
#ff-dr .ffl-legend__step + .ffl-legend__step::before {
    content: "\2192";
    margin-right: 0.4rem;
    color: var(--content-secondary);
    font-weight: 400;
}

#ff-dr .ffl-legend__swatch {
    width: 0.5rem;
    height: 1.1rem;
    background: var(--accent);
    border-radius: 2px;
}

#ff-dr .ffl-legend p {
    flex: 1 1 18rem;
    max-width: 52ch;
    margin: 0;
    color: var(--content-secondary);
    font-size: 0.875rem;
    line-height: 1.55;
}

#ff-dr .ffl-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.25rem;
    margin-top: clamp(1.5rem, 3vw, 2.25rem);
}

#ff-dr .ffl-card {
    display: flex;
    flex-direction: column;
    padding: clamp(1.35rem, 2.5vw, 1.75rem);
    background: var(--surface);
    border: 1px solid var(--border-neutral);
    border-radius: 14px;
    box-shadow: none;
    transform: none;
    transition: border-color 0.2s ease;
}

#ff-dr .ffl-card:hover {
    border-color: var(--border-active);
}

#ff-dr .ffl-card__head {
    display: flex;
    align-items: center;
    gap: clamp(0.9rem, 2vw, 1.25rem);
    padding-bottom: 1.15rem;
    border-bottom: 1px solid var(--border-neutral);
}

/* Same tile as the anatomy diagrams on the device pages, so the cluster reads
   as one system - different content, same frame. */
#ff-dr .ffl-meter {
    display: flex;
    flex: 0 0 auto;
    align-items: stretch;
    justify-content: center;
    gap: 0.45rem;
    width: 6rem;
    height: 6rem;
    padding: 1rem 0.9rem;
    background: var(--surface-alt);
    border: 1px solid var(--border-neutral);
    border-radius: 12px;
}

/* The bars run left to right, the same direction as the legend. An earlier
   version stacked them vertically - depth reads well downwards, but the legend
   teaches the scale horizontally and two axes for one idea is one too many. */
#ff-dr .ffl-bar {
    display: block;
    flex: 1 1 0;
    background: var(--border-neutral);
    border-radius: 3px;
}

#ff-dr .ffl-bar.is-on {
    background: var(--accent);
}

#ff-dr .ffl-card__ident {
    display: block;
    min-width: 0;
}

#ff-dr .ffl-card__title {
    margin: 0;
    color: var(--content);
    font-size: 1.1875rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.25;
    text-transform: none;
}

#ff-dr .ffl-card__route {
    display: inline-block;
    margin-top: 0.5rem;
    padding: 0.2rem 0.5rem;
    background: var(--chrome-fill-hover);
    border: 1px solid var(--chrome-border);
    border-radius: 6px;
    color: var(--accent-art);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    line-height: 1.3;
    text-transform: uppercase;
}

#ff-dr .ffl-card__body {
    padding-top: 1.15rem;
}

#ff-dr .ffl-card__text {
    margin: 0 0 1.1rem;
    color: var(--content-body);
    font-size: 0.9375rem;
    line-height: 1.6;
}

#ff-dr .ffl-card__label {
    margin: 0 0 0.35rem;
    color: var(--content-secondary);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    line-height: 1.4;
    text-transform: uppercase;
}

#ff-dr .ffl-symptoms {
    margin: 0;
    padding: 0;
    list-style: none;
}

#ff-dr .ffl-symptoms li {
    position: relative;
    margin: 0;
    padding: 0.28rem 0 0.28rem 1.45rem;
    color: var(--content-body);
    font-size: 0.875rem;
    line-height: 1.5;
}

#ff-dr .ffl-symptoms li::before {
    content: "\2014";
    position: absolute;
    left: 0;
    color: var(--action);
    font-weight: 700;
}

@media (max-width: 900px) {
    #ff-dr .ffl-grid {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 560px) {
    #ff-dr .ffl-meter {
        width: 4.5rem;
        height: 4.5rem;
        padding: 0.7rem 0.6rem;
        gap: 0.3rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    #ff-dr .ffl-card {
        transition: none;
    }
}

/* =============================================================================
   REVIEWS - carousel (.ffr)   hub only
   Markup: section.ffr > .fixfactor-container
             > .ffr-head (copy + .ffr-scores + .ffr-nav)
             > .fixfactor-reviews-carousel-wrap > .fixfactor-reviews-carousel
                 > a.fixfactor-review-card

   Still a carousel - native scroll-snap, same eight cards, same inline script.
   What changed: the arrows sat at -20px over the cards, five large amber stars
   times eight cards were the loudest thing on the page, the quotes were set in
   italic, the platform was grey small print, and the strongest signal we have -
   4.9 on Google, 5.0 on Trustpilot - was a footnote under the track. All of
   that moves into a header row, and the card gets a pinned footer.
   ========================================================================== */

#ff-dr .ffr-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1.5rem 2rem;
    margin-bottom: clamp(1.75rem, 3vw, 2.5rem);
}

#ff-dr .ffr-head__copy {
    flex: 1 1 30rem;
    max-width: 40rem;
    text-align: left;
}

/* The cluster's section headings are centred by a global rule and carry a
   ~36px vertical margin. Neither is wanted in a header row where the heading
   has to sit flush with the line under it. */
#ff-dr .ffr-head__copy h2 {
    margin: 0;
    text-align: left;
}

#ff-dr .ffr-head__copy p {
    max-width: 46ch;
    margin: 0.75rem 0 0;
    color: var(--content-body);
    font-size: 1.0625rem;
    line-height: 1.7;
}

#ff-dr .ffr-head__side {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem 1.5rem;
}

#ff-dr .ffr-scores {
    display: flex;
    align-items: stretch;
    gap: 0.75rem;
}

#ff-dr .ffr-score {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.9rem;
    background: var(--surface);
    border: 1px solid var(--border-neutral);
    border-radius: 10px;
    text-decoration: none;
    transition: border-color 0.2s ease;
}

#ff-dr .ffr-score:hover {
    border-color: var(--border-active);
}

#ff-dr .ffr-score__val {
    color: var(--content);
    font-size: 1.125rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
    line-height: 1;
}

#ff-dr .ffr-score__src {
    color: var(--content-secondary);
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1;
}

#ff-dr .ffr-mark {
    flex: 0 0 auto;
    width: 1rem;
    height: 1rem;
}

/* --- controls, in the header rather than over the cards ------------------- */

#ff-dr .ffr-nav {
    display: flex;
    gap: 0.5rem;
}

#ff-dr .ffr .fixfactor-carousel-arrow,
#ff-dr .ffr-nav .fixfactor-carousel-arrow {
    position: static;
    transform: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    background: var(--surface);
    border: 1px solid var(--border-neutral);
    border-radius: 10px;
    color: var(--action);
    cursor: pointer;
    transition: border-color 0.2s ease, color 0.2s ease, opacity 0.2s ease;
}

#ff-dr .ffr-nav .fixfactor-carousel-arrow:hover:not(:disabled) {
    border-color: var(--border-active);
    background: var(--surface);
    color: var(--action-hover);
}

#ff-dr .ffr-nav .fixfactor-carousel-arrow:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
}

/* Disabled rather than hidden: the control keeps its place, so the row does
   not reflow when you reach either end. */
#ff-dr .ffr-nav .fixfactor-carousel-arrow:disabled {
    opacity: 0.4;
    cursor: default;
}

#ff-dr .ffr-nav .fixfactor-carousel-arrow svg {
    width: 1.25rem;
    height: 1.25rem;
    fill: currentColor;
}

/* --- track ---------------------------------------------------------------- */

#ff-dr .ffr .fixfactor-reviews-carousel-wrap {
    position: static;
    margin: 0;
    padding: 0;
}

#ff-dr .ffr .fixfactor-reviews-carousel {
    display: flex;
    gap: 1rem;
    padding: 0.25rem 0 1.25rem;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scrollbar-width: thin;
    scrollbar-color: var(--border-neutral) transparent;
}

#ff-dr .ffr .fixfactor-reviews-carousel:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 4px;
}

#ff-dr .ffr .fixfactor-reviews-carousel::-webkit-scrollbar {
    height: 6px;
}

#ff-dr .ffr .fixfactor-reviews-carousel::-webkit-scrollbar-track {
    background: transparent;
}

#ff-dr .ffr .fixfactor-reviews-carousel::-webkit-scrollbar-thumb {
    background: var(--border-neutral);
    border-radius: 3px;
}

/* --- card ----------------------------------------------------------------- */

#ff-dr .ffr .fixfactor-review-card {
    display: flex;
    flex: 0 0 clamp(17rem, 24vw, 22rem);
    flex-direction: column;
    padding: clamp(1.35rem, 2.5vw, 1.6rem);
    background: var(--surface);
    border: 1px solid var(--border-neutral);
    border-radius: 14px;
    box-shadow: none;
    scroll-snap-align: start;
    text-decoration: none;
    transition: border-color 0.2s ease;
}

#ff-dr .ffr .fixfactor-review-card:hover {
    border-color: var(--border-active);
}

#ff-dr .ffr .fixfactor-review-card:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
}

#ff-dr .ffr-card__stars {
    display: flex;
    gap: 2px;
    margin-bottom: 0.9rem;
}

/* 15px, not 18: five amber glyphs times eight cards was the loudest element on
   the page, and the token brief puts amber on a short leash. */
#ff-dr .ffr-star {
    width: 0.9375rem;
    height: 0.9375rem;
    fill: var(--accent-warm);
}

/* Roman, not italic. A long italic passage is harder to read, and every one of
   these is a passage rather than a line. */
#ff-dr .ffr-card__text {
    margin: 0 0 1.25rem;
    color: var(--content-body);
    font-size: 0.9375rem;
    font-style: normal;
    line-height: 1.6;
}

#ff-dr .ffr-card__meta {
    display: block;
    margin-top: auto;
    padding-top: 0.9rem;
    border-top: 1px solid var(--border-neutral);
}

#ff-dr .ffr-card__author {
    display: block;
    color: var(--content-strong);
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.4;
}

#ff-dr .ffr-card__source {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.3rem;
    color: var(--content-secondary);
    font-size: 0.8125rem;
    line-height: 1.4;
}

@media (max-width: 700px) {
    #ff-dr .ffr-head {
        align-items: flex-start;
    }

    #ff-dr .ffr-head__side {
        justify-content: space-between;
        width: 100%;
    }

    #ff-dr .ffr .fixfactor-review-card {
        flex-basis: min(20rem, 82vw);
    }
}

@media (prefers-reduced-motion: reduce) {
    #ff-dr .ffr .fixfactor-reviews-carousel {
        scroll-behavior: auto;
    }

    #ff-dr .ffr .fixfactor-review-card,
    #ff-dr .ffr-nav .fixfactor-carousel-arrow,
    #ff-dr .ffr-score {
        transition: none;
    }
}

/* =============================================================================
   WHY FIXFACTOR - inverse band (.ffw)   hub only
   Markup: section.ffw > .ffw-grid
             > figure.ffw-figure (full-bleed photo, no caption, no frame)
             > .ffw-body > .ffw-body__inner
                 (eyebrow + h2 lede + sub + .ffw-facts > .ffw-fact)

   Replaced a centred heading over a framed-and-captioned photo beside four
   tagged cards - the same arrangement as half the page and half the internet.

   Three things change. The photo loses its frame, its radius and its caption
   and runs to the edge of the viewport, so it reads as a plane rather than an
   illustration with a note. The four facts stop being cards: each is one large
   statement, so typography carries the weight instead of boxes. And the whole
   band goes to the inverse register, which is the one place on this page where
   a hard stop is useful - it sits between two white sections.

   The register is not invented here: --surface-inverse (v4.3) is a declared set
   with measured contrast, already used by the footer and by the terms band on
   the partnership page.
   ========================================================================== */

#ff-dr .ffw {
    padding: 0;
    background: var(--surface-inverse);
    color: var(--content-inverse-body);
}

#ff-dr .ffw-grid {
    display: grid;
    grid-template-columns: minmax(0, 0.82fr) minmax(0, 1fr);
    align-items: stretch;
}

#ff-dr .ffw-figure {
    margin: 0;
    overflow: hidden;
}

/* No radius, no border, no caption. The image is cropped by the section, not
   framed by it. */
#ff-dr .ffw-figure img {
    display: block;
    width: 100%;
    height: 100%;
    min-height: clamp(22rem, 38vw, 34rem);
    object-fit: cover;
    object-position: 50% 45%;
}

#ff-dr .ffw-body {
    display: flex;
    align-items: center;
    padding: clamp(3rem, 6vw, 5rem) clamp(1.5rem, 4vw, 4.5rem);
}

#ff-dr .ffw-body__inner {
    width: min(42rem, 100%);
}

#ff-dr .ffw-eyebrow {
    display: block;
    margin-bottom: 0.9rem;
    color: var(--accent-inverse);
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* The only !important in this sheet, and it is answering one: the cluster's
   shared layer sets `#ff-dr h2 { color: var(--content) !important }` to hold a
   single heading colour, which paints this heading black on an ink band. No
   specificity can undo an !important, so it is matched rather than dodged.
   The blanket rule is worth narrowing at source - see the note in the report. */
#ff-dr .ffw-lede {
    max-width: 18ch;
    margin: 0;
    color: var(--content-inverse) !important;
    font-size: clamp(1.875rem, 3.4vw, 2.75rem);
    font-weight: 800;
    letter-spacing: -0.03em;
    line-height: 1.08;
    text-align: left;
    text-wrap: balance;
}

#ff-dr .ffw-sub {
    max-width: 46ch;
    margin: 1rem 0 0;
    color: var(--content-inverse-muted);
    font-size: 1rem;
    line-height: 1.6;
}

#ff-dr .ffw-facts {
    margin-top: clamp(2rem, 4vw, 2.75rem);
}

/* Hairlines, not cards. The rule belongs to the item so the last statement
   does not trail one. */
#ff-dr .ffw-fact + .ffw-fact {
    margin-top: 1.35rem;
    padding-top: 1.35rem;
    border-top: 1px solid var(--rule-inverse);
}

#ff-dr .ffw-fact__claim {
    max-width: 34ch;
    margin: 0;
    color: var(--content-inverse);
    font-size: clamp(1.0625rem, 1.5vw, 1.25rem);
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.35;
}

#ff-dr .ffw-fact__note {
    max-width: 54ch;
    margin: 0.4rem 0 0;
    color: var(--content-inverse-muted);
    font-size: 0.9375rem;
    line-height: 1.6;
}

@media (max-width: 900px) {
    #ff-dr .ffw-grid {
        grid-template-columns: 1fr;
    }

    #ff-dr .ffw-figure img {
        min-height: clamp(15rem, 48vw, 20rem);
    }
}

/* =============================================================================
   MOBILE - density pass (hub and device pages)

   Measured on the hub at 390px before this block: the page ran 15,409px and the
   device chooser alone took 2,935px of it - nineteen per cent of the whole page
   for nine one-per-row cards, each with a 140px image panel. The chooser is
   navigation; at that size it should behave like a menu, not like nine adverts.
   ========================================================================== */

@media (max-width: 600px) {
    /* Two per row. The grid is set to one column by three different sheets, so
       the selector matches the most specific of them. */
    #ff-dr .fixfactor-services-grid,
    #ff-dr.ff-dr3-hub .fixfactor-services-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.75rem;
    }

    /* The hub carries .ff-dr3-hub on the wrapper and pins the image box at
       135px from a rule at (1,2,0); the doubled selector is what reaches it. */
    #ff-dr .fixfactor-service-card,
    #ff-dr.ff-dr3-hub .fixfactor-service-card {
        min-height: 0;
    }

    #ff-dr .fixfactor-service-image,
    #ff-dr.ff-dr3-hub .fixfactor-service-image {
        height: 5.25rem;
        min-height: 0;
        padding: 0.5rem;
    }

    #ff-dr .fixfactor-service-image img,
    #ff-dr.ff-dr3-hub .fixfactor-service-image img {
        max-height: 100%;
        object-fit: contain;
    }

    #ff-dr .fixfactor-service-content,
    #ff-dr.ff-dr3-hub .fixfactor-service-content {
        min-height: 0;
        padding: 0.8rem 0.85rem 0.95rem;
    }

    #ff-dr .fixfactor-service-title,
    #ff-dr.ff-dr3-hub .fixfactor-service-title {
        margin: 0;
        font-size: 0.9375rem;
        line-height: 1.3;
    }

    #ff-dr .fixfactor-service-text,
    #ff-dr.ff-dr3-hub .fixfactor-service-text {
        display: none;
    }

    /* Section rhythm: the cluster's section padding is tuned for desktop and
       stacks up over ten sections. */
    #ff-dr .fixfactor-section,
    #ff-dr .ffl,
    #ff-dr .ffr,
    #ff-dr .fff {
        padding-top: 2.5rem;
        padding-bottom: 2.5rem;
    }

    #ff-dr .fixfactor-section-header {
        margin-bottom: 1.5rem;
    }

    /* Gallery tiles at 190px each, nine of them, is a lot of scrolling for
       supporting evidence. */
    #ff-dr .fixfactor-gallery-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.5rem;
    }

    #ff-dr.ff-dr3-hub .ff-dr3-proof .fixfactor-gallery-item {
        height: 118px;
    }
}

/* ==========================================================================
   Hub services grid - resting border + hover state (15 Aug 2026)

   Border first, because it was wrong before anything was added to it. The hub
   card declares `border: 1px solid var(--border-interactive)` and is then hit
   by `:nth-child(odd) { border-right: 1px solid var(--border-subtle) }` - a
   leftover from the two-column rail on the device pages, where an odd card
   sits against a column seam. On the hub's three-column grid it just means
   cards 1, 3, 5, 7 and 9 carry a right edge at .15 alpha while their other
   three edges sit at .4. That is the uneven outline: same card, two border
   colours. Reset to one value on all four sides.

   Hover: no motion, no lift, no shadow, no drawn line. Three colour changes
   that all say the same thing - the border goes to full brand, the icon panel
   takes the teal tint, the title goes to --action. State change, not
   decoration.
   ========================================================================== */

#ff-dr.ff-dr3-hub .fixfactor-service-card:nth-child(odd) {
    border-right-color: var(--border-interactive);
}

#ff-dr.ff-dr3-hub .fixfactor-service-card {
    transition: border-color .15s ease;
}

#ff-dr.ff-dr3-hub .fixfactor-service-image {
    transition: background-color .15s ease;
}

#ff-dr.ff-dr3-hub .fixfactor-service-title {
    transition: color .15s ease;
}

#ff-dr.ff-dr3-hub .fixfactor-service-card:hover,
#ff-dr.ff-dr3-hub .fixfactor-service-card:focus-visible {
    border-color: var(--border-active);
}

#ff-dr.ff-dr3-hub .fixfactor-service-card:hover .fixfactor-service-image,
#ff-dr.ff-dr3-hub .fixfactor-service-card:focus-visible .fixfactor-service-image {
    background: var(--chrome-fill-hover);
}

#ff-dr.ff-dr3-hub .fixfactor-service-card:hover .fixfactor-service-title,
#ff-dr.ff-dr3-hub .fixfactor-service-card:focus-visible .fixfactor-service-title {
    color: var(--action);
}

/* ==========================================================================
   FAQ - measure (15 Aug 2026)

   The card was 896px wide and the answer inside it 552px, so every open
   answer left 344px of empty card to its right - more than a third of the
   width doing nothing, with the +/- marker stranded far from the question it
   belongs to. Measured on the hub at 1440: longest question line 486px in a
   896px card.

   The list drops to 44rem. That is not an arbitrary number: it puts the card
   edge at 704px against the section lead's 736px, so the two finally line up
   instead of the accordion sitting inset inside a wider block of text.
   Horizontal padding grows with the narrower card (21.6 -> 28px), because the
   old value was 2.4% of the card width and read as no padding at all.
   ========================================================================== */

#ff-dr .fff-list,
#ff-dr .fff-foot {
    max-width: 44rem;
}

#ff-dr .fff-q {
    padding: 1.25rem clamp(1.1rem, 2.4vw, 1.75rem);
}

#ff-dr .fff-a {
    padding: 0 clamp(1.1rem, 2.4vw, 1.75rem) clamp(1.25rem, 2.4vw, 1.6rem);
}

#ff-dr .fff-a p {
    max-width: 64ch;
}

/* ==========================================================================
   Device pages - mobile corrections (15 Aug 2026)

   Measured on /hard-drive-data-recovery/ at 390 before touching anything.
   ========================================================================== */

@media (max-width: 768px) {

    /* --- HERO -------------------------------------------------------------
       Hero copy started 40px from the edge while every other section started
       at 12px, and it was centred while the whole rest of the page reads left.
       The h1 also inherited a desktop measure cap that computed to 285px
       inside a 350px column - a two-line heading with a ragged right edge for
       no reason.

       `section.fixfactor-hero` in the selector is not decoration: the rules
       being corrected are written that way and land at (1,2,1). */
    #ff-dr:not(.ff-dr3-hub) section.fixfactor-hero .fixfactor-hero-wrapper {
        padding-right: 0;
        padding-left: 0;
        text-align: left;
    }

    #ff-dr:not(.ff-dr3-hub) section.fixfactor-hero .fixfactor-hero-content,
    #ff-dr:not(.ff-dr3-hub) section.fixfactor-hero .fixfactor-hero-content h1,
    #ff-dr:not(.ff-dr3-hub) section.fixfactor-hero .fixfactor-hero-content p {
        max-width: none;
        padding: 0;
        text-align: left;
    }

    #ff-dr:not(.ff-dr3-hub) section.fixfactor-hero .fixfactor-hero-buttons {
        justify-content: flex-start;
    }

    /* --- One gutter ------------------------------------------------------
       Three left edges ran down a single page at 390: .fixfactor-container
       sections at 12px, .ff-dr3-inner sections and the hero at 20px, the
       gallery heading at 23px and the form fields at 24px. 12px is also too
       tight for a phone. Everything to 20px, which is what the two editorial
       bands already used. */
    #ff-dr .fixfactor-container {
        padding-right: 20px;
        padding-left: 20px;
    }

    /* --- SAFETY BAND: the stray line -------------------------------------
       Desktop draws a 2px amber rule across the top of each step. The mobile
       block rotated it into a vertical line down a 3.5rem left gutter and gave
       it `linear-gradient(180deg, #3bb8cc 0 45%, #ffd100 45% 49%, #3bb8cc 49%
       100%)` - a teal line with a four-percent amber blip in the middle of it,
       inside a section whose entire palette is amber. That is the blue bar and
       the artefact.

       The rule goes back to being a rule: horizontal, amber, above each step,
       with the number under it. Same vocabulary as desktop, and it hands back
       the 3.5rem gutter, which is 16% of the column at 390. */
    #ff-dr .ff-dr3-safety__rail {
        grid-template-columns: 1fr;
        gap: 1.75rem;
    }

    #ff-dr .ff-dr3-safety__rail li {
        min-height: 0;
        padding: 2.55rem 0 0;
    }

    #ff-dr .ff-dr3-safety__rail li::before {
        top: 0.95rem;
        left: 0;
    }

    #ff-dr .ff-dr3-safety__rail li::after,
    #ff-dr .ff-dr3-safety__rail li:last-child::after {
        top: 0;
        left: 0;
        width: 100%;
        height: 2px;
        background: var(--accent-warm);
    }

    /* --- Editorial measure caps ------------------------------------------
       `max-width: 12ch !important` is the right call at 1320px, where the
       heading sits in a narrow left column beside a three-up rail. At 390 the
       column IS the screen, and the cap computed to 214px: "If the drive /
       clicks, keep it / off" over three lines with a 136px hole beside it. */
    #ff-dr .ff-dr3-safety h2,
    #ff-dr .ff-dr3-process h2 {
        max-width: none !important;
    }
}

/* ==========================================================================
   Hub prose block - gutter (15 Aug 2026)

   .fixfactor-specialist-content sits straight inside its section with no
   .fixfactor-container around it, so it never picked up the page gutter. At
   390 the heading and every paragraph ran from x=0 to x=390 - text touching
   both edges of the screen.

   Fixed with the cluster's own width idiom rather than a media query, because
   it is then correct at every width: at 820px and above min() still resolves
   to 780px, which is exactly what the block measures today. Verified at 1440:
   left edge 330, width 780, unchanged.
   ========================================================================== */

#ff-dr .fixfactor-specialist-content {
    width: min(780px, calc(100% - 40px));
    margin-inline: auto;
}

/* ==========================================================================
   Device pages, services tiles - mobile layout (15 Aug 2026)

   The device-page card is a two-column grid: a 112px image box beside the
   text. That is right at 1320px. At 390 the grid gives each card 169px, the
   image box keeps 92px of it, and the title is left with a 50px column -
   narrow enough that "Accidentally Deleted Data" stacked into four lines with
   nowhere for the long words to break. The phone page was worse: a 35px title
   column, seven lines, 117px tall.

   On mobile the card stacks: image across the top, title underneath with the
   whole width of the card. Same two-up grid, same tiles, and the title column
   goes from 50px to 147px - one line instead of four.
   ========================================================================== */

@media (max-width: 600px) {

    #ff-dr:not(.ff-dr3-hub) .fixfactor-service-card {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        min-height: 0;
    }

    #ff-dr:not(.ff-dr3-hub) .fixfactor-service-image {
        width: 100%;
        height: 4.5rem;
        min-height: 0;
        padding: 0.55rem;
    }

    #ff-dr:not(.ff-dr3-hub) .fixfactor-service-image img {
        max-height: 100%;
        object-fit: contain;
    }

    #ff-dr:not(.ff-dr3-hub) .fixfactor-service-content {
        justify-content: flex-start;
        min-height: 0;
        padding: 0.15rem 0.7rem 0.85rem;
    }

    #ff-dr:not(.ff-dr3-hub) .fixfactor-service-title {
        margin: 0;
        font-size: 0.875rem;
        font-weight: 700;
        line-height: 1.25;
        hyphens: auto;
    }
}

/* ==========================================================================
   Hub hero - the dead space under it on mobile (15 Aug 2026)

   dr-cluster-shared.css already resets the hero's min-height on mobile:

       @media (max-width: 768px) {
           #ff-dr .fixfactor-hero          { min-height: auto; }
           #ff-dr .fixfactor-hero-wrapper  { min-height: 0; }
       }

   That reset never reached the hub. The hub declares its own taller hero as
   `#ff-dr.ff-dr3-hub .fixfactor-hero { min-height: 540px }` and
   `#ff-dr.ff-dr3-hub .fixfactor-hero-wrapper { min-height: 500px }`, both at
   (1,2,0), and the reset is at (1,1,0) - so it loses no matter which media
   query it sits in.

   The 500px exists to make room for the hero image. On mobile the image is
   display:none, so nothing filled it. Measured at 390: hero copy ended at
   y=367 and the section carried on to y=564 - 165px of empty page between the
   ratings row and the services section, which is what read as a fault.
   ========================================================================== */

@media (max-width: 768px) {
    #ff-dr.ff-dr3-hub .fixfactor-hero {
        min-height: 0;
    }

    #ff-dr.ff-dr3-hub .fixfactor-hero-wrapper {
        min-height: 0;
    }
}

/* ==========================================================================
   Case study tabs - the drift, and the indicator (15 Aug 2026)

   THE BUG. The strip is a horizontal scroller: `overflow-x: auto`. Per the
   overflow spec, once one axis is not `visible` the other computes to `auto`
   as well - so the strip was scrollable vertically too. It normally has
   nothing to scroll there, except that each tab carried `margin: 0 0 -1px`
   with `border-bottom: 1px solid transparent`, the trick that let the active
   tab cover the strip's bottom rule. The negative margin pulls the layout up
   by a pixel but the border box still counts towards scrollable overflow:

       clientHeight 58, scrollHeight 59  ->  one pixel of vertical scroll

   One pixel is enough. A swipe on a touch screen is never purely horizontal,
   so the strip drifted up and down while it was being scrolled. Reproduced by
   setting scrollTop: it moved.

   THE FIX removes the cause rather than clamping it. The active tab is now
   marked by a 3px bottom border in the brand colour - a plain underlined tab -
   so no tab needs to overhang the rule and none needs a negative margin. With
   that gone scrollHeight equals clientHeight and there is nothing to drift.
   `overflow-y: hidden` stays as a second line of defence.
   ========================================================================== */

#ff-dr .fixfactor-tabs-labels {
    overflow-y: hidden;
    scroll-padding-inline: 0.5rem;
}

#ff-dr .fixfactor-tabs-label {
    margin: 0;
    border-bottom: 3px solid transparent;
    transition: color .18s ease, background-color .18s ease, border-color .18s ease;
}

#ff-dr .fixfactor-tabs-label:hover {
    background: rgba(0, 0, 0, .02);
    border-bottom-color: var(--border-neutral);
}

#ff-dr #case1:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case1,
#ff-dr #case2:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case2,
#ff-dr #case3:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case3,
#ff-dr #case4:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case4,
#ff-dr #case5:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case5,
#ff-dr #case6:checked ~ .fixfactor-tabs-container .fixfactor-tabs-labels .label-case6 {
    margin: 0;
    background: var(--surface);
    border-bottom-color: var(--action);
}

/* A hairline between tabs: the strip reads as a set of choices rather than one
   run of words, and it survives a tab going active. */
#ff-dr .fixfactor-tabs-label + .fixfactor-tabs-label {
    box-shadow: inset 1px 0 0 var(--border-subtle);
}

@media (max-width: 768px) {
    #ff-dr .fixfactor-tabs-label {
        padding: 0.9rem 1.05rem;
        font-size: 0.875rem;
    }

    /* Five tabs never fit a phone: the strip measures 662px against 348px of
       screen. The mask sits on the strip's own box rather than on the scrolled
       content, so the fade stays pinned to the right edge and says there is
       more to the right. */
    #ff-dr .fixfactor-tabs-labels {
        -webkit-mask-image: linear-gradient(90deg, var(--content) calc(100% - 2.25rem), transparent 100%);
                mask-image: linear-gradient(90deg, var(--content) calc(100% - 2.25rem), transparent 100%);
    }
}

/* ==========================================================================
   Failure-scenario legend - mobile (15 Aug 2026)

   The legend is a row of labelled swatches joined by arrows. At 1320px it is
   one line. At 390 it wrapped: two lines on most pages, three on USB, external
   drives and RAID - and since the arrow is a ::before on every step after the
   first, a wrapped line began with a stranded "->". Measured on RAID: 188px
   tall to say four words.

   Rebuilt as what it actually is: a four-segment scale. Each layer takes an
   equal share of the width, its swatch stretched into a bar so the segments
   together read as one axis running left to right, and the label sits under
   its own segment. The arrows go - an axis does not need them - and so does
   the uppercase, which at this size costs more width than it earns.

   grid-auto-flow: column rather than repeat(4) so a page with three or five
   layers would still lay out.

   The paragraph needs its flex reset. The base rule is `flex: 1 1 18rem`; that
   basis is a width while the legend is a row, but the moment it becomes a
   column the same 18rem is read as a height and the paragraph inflates to
   exactly 288px.
   ========================================================================== */

@media (max-width: 600px) {

    #ff-dr .ffl-legend {
        flex-direction: column;
        align-items: stretch;
        gap: 0.85rem;
        padding: 1rem;
    }

    #ff-dr .ffl-legend__scale {
        display: grid;
        grid-auto-flow: column;
        grid-auto-columns: minmax(0, 1fr);
        gap: 0.4rem;
        width: 100%;
        align-items: start;
    }

    #ff-dr .ffl-legend__step {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: 0.4rem;
        color: var(--content-secondary);
        font-size: 0.6875rem;
        font-weight: 600;
        letter-spacing: 0;
        line-height: 1.25;
        text-transform: none;
    }

    #ff-dr .ffl-legend__step + .ffl-legend__step::before {
        content: none;
    }

    #ff-dr .ffl-legend__swatch {
        width: 100%;
        height: 5px;
        border-radius: 3px;
    }

    #ff-dr .ffl-legend p {
        flex: 0 0 auto;
        max-width: none;
        margin: 0;
        font-size: 0.8125rem;
        line-height: 1.5;
    }
}

/* =============================================================================
   DEVICE HERO - halo, entrance and 3D drift
   Markup: .fixfactor-hero-wrapper > .fixfactor-hero-image (or
           .fixfactor-hero-image-container) > img

   The device pages showed the drive, phone or Mac flat against the band: a
   cut-out with a soft box shadow and a single -5deg tilt that straightened on
   hover. The drone hero on the repair pages solves the same problem with a
   teal halo behind the object, and that halo is what makes the object read as
   lit rather than pasted. Same idea here.

   THE HALO'S SHAPE IS LOAD-BEARING. An `ellipse` with no size given uses
   farthest-corner: the radius is measured to the CORNER, so vertically the
   gradient reaches zero outside its own box - and a background is not painted
   outside the box, which cut the halo off along a straight line. The size is
   stated explicitly here (40% 38% of a box inset by 34%) so the fade always
   finishes inside, whatever the image's proportions. Measured on the HDD page:
   zero at 664px at the peak of the halo's breath, section floor at 677px -
   checked at 3440px wide, where the hero is shortest relative to the image.

   THREE LAYERS, THREE JOBS.
   - The wrapper carries the entrance and the drift, with its own perspective,
     so no parent needs one.
   - ::before is the halo. It drifts AGAINST the wrapper's rotation. Parallax
     is the only thing that reads as depth on a flat cut-out; rotation alone
     just looks like a wobble.
   - ::after is a small specular highlight on a third path, so the light does
     not move as one rigid sheet.
   The image keeps its own tilt and its hover straighten. Wrapper and image had
   to stay separate elements: an animation always beats a plain declaration on
   the SAME element, so a drift on the image would have killed the hover.

   Periods are 14s / 17s / 14s with different phases - far enough apart that a
   shared beat is rare enough not to be noticed.

   The drop shadow lives on the image, not the wrapper: a filter on the wrapper
   blurs the halo along with the device.
   ========================================================================== */

#ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image,
#ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image-container {
    position: relative;
    filter: none;
    animation: ffDrHeroEnter 1.15s cubic-bezier(0.22, 0.61, 0.36, 1) both,
               ffDrHeroDrift 14s 1.15s ease-in-out infinite;
}

#ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image::before,
#ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image-container::before {
    content: '';
    position: absolute;
    inset: -34% -34%;
    z-index: 0;
    pointer-events: none;
    background: radial-gradient(ellipse 40% 38% at 50% 50%, rgba(0, 170, 196, 0.32), var(--wash-brand-soft) 45%, rgba(0, 170, 196, 0) 100%);
    animation: ffDrHaloEnter 1.5s 0.15s ease-out both,
               ffDrHeroHalo 17s 1.65s ease-in-out infinite;
}

#ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image::after,
#ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image-container::after {
    content: '';
    position: absolute;
    inset: -26% -26%;
    z-index: 0;
    pointer-events: none;
    background: radial-gradient(ellipse 24% 26% at 40% 32%, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0) 70%);
    animation: ffDrHeroSheen 14s 1.15s ease-in-out infinite;
}

#ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image img,
#ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image-container img {
    position: relative;
    z-index: 1;
    filter: drop-shadow(0 16px 26px var(--overlay-soft));
}

/* Hover reads as the object turning to face you, not just flattening. */
#ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image:hover img,
#ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image-container:hover img {
    transform: perspective(800px) rotateY(0deg) scale(1.035);
}

/* The device arrives out of the depth and settles. The last frame is identical
   to the drift's first frame, so the handover between the two animations is
   invisible. */
@keyframes ffDrHeroEnter {
    0%   { opacity: 0; transform: perspective(1200px) rotateY(-13deg) rotateX(5deg) translate3d(0, 22px, -110px); }
    55%  { opacity: 1; }
    100% { opacity: 1; transform: perspective(1200px) rotateY(-3.4deg) rotateX(1.2deg) translate3d(0, 0, 0); }
}

@keyframes ffDrHeroDrift {
    0%   { transform: perspective(1200px) rotateY(-3.4deg) rotateX(1.2deg) translate3d(0, 0, 0); }
    50%  { transform: perspective(1200px) rotateY(3.4deg) rotateX(-1.2deg) translate3d(0, -7px, 30px); }
    100% { transform: perspective(1200px) rotateY(-3.4deg) rotateX(1.2deg) translate3d(0, 0, 0); }
}

@keyframes ffDrHaloEnter {
    from { opacity: 0;   transform: scale(0.55); }
    to   { opacity: 0.8; transform: scale(1); }
}

/* Against the device, not with it - see the note on parallax above. */
@keyframes ffDrHeroHalo {
    0%, 100% { opacity: 0.78; transform: translate3d(2.5%, 0, 0) scale(1); }
    50%      { opacity: 1;    transform: translate3d(-2.5%, -1%, 0) scale(1.04); }
}

@keyframes ffDrHeroSheen {
    0%, 100% { opacity: 0.7; transform: translate3d(-2%, 1.5%, 0); }
    50%      { opacity: 1;   transform: translate3d(4%, -2%, 0); }
}

@media (prefers-reduced-motion: reduce) {
    #ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image,
    #ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image-container,
    #ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image::before,
    #ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image::after,
    #ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image-container::before,
    #ff-dr:not(.ff-dr3-hub) .fixfactor-hero-image-container::after {
        animation: none;
    }
}
