/* =============================================================================
   Product details - Apple-style configurator (ADDITIVE)
   -----------------------------------------------------------------------------
   Styles ONLY the new sections added to Views/Shop/detail.cshtml:
     - condition (New/Used) selector
     - payment options (installment + lease terms)
     - trade-in panel + wizard
     - order summary
     - the sticky bar that drops in on scroll

   Everything already on the page (gallery, colour/storage chips, the legacy payment
   plan tabs, bundles, seller, specs, report, FAQ) is untouched: every rule here is
   namespaced under .sd-v2 / .sd-v2-modal / .sd-stickybar so nothing leaks.

   Design tokens below are lifted from the saved Apple buy page in web/design/apple
   (step1evolution.css, lazy-purchase-options.css). Notes on the ones that matter:

     tile        border-radius 12px, 1px solid #86868b, padding 15px, min-height 78px
     tile:checked border-width 2px + padding 14px  <- padding shrinks by exactly the
                 amount the border grows, so the tile does not shift on selection
     disabled    background #00000003, border #86868b6b, text #6e6e73
     easing      cubic-bezier(.4,0,.6,1) is Apple's signature curve
     stickybar   fixed, translateY(-100%) -> 0 over .5s ease-in-out

   Deliberately plain CSS, not Tailwind: this block lives inside a Bootstrap page,
   so it needs no wrapper class and no `npm run build:css` step.

   RTL-safe: logical properties throughout (inline-start/end, margin-inline...).
   ============================================================================= */

.sd-v2,
.sd-v2-modal,
.sd-stickybar {
    /* ---- Apple palette ---- */
    --sd-ink: #1d1d1f;          /* primary text */
    --sd-ink-2: #6e6e73;        /* secondary text, disabled label */
    --sd-ink-3: #86868b;        /* tertiary text, resting tile border */
    --sd-line: #d2d2d7;         /* hairlines, dividers */
    --sd-surface: #fff;
    --sd-surface-2: #f5f5f7;    /* Apple's light grey panel */
    --sd-blue: #0071e3;         /* selected border, links, primary button */
    --sd-blue-hover: #0077ed;
    --sd-green: #008a20;
    --sd-red: #e30000;

    /* ---- geometry ---- */
    --sd-radius-tile: 12px;
    --sd-radius-card: 18px;
    --sd-radius-pill: 980px;

    /* ---- motion ---- */
    --sd-ease: cubic-bezier(.4, 0, .6, 1);

    /* ---- type ---- */
    --sd-font: "SF Pro Text", "SF Pro Display", "SF Pro Icons", -apple-system,
               BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif;
}

.sd-v2 {
    font-family: var(--sd-font);
    color: var(--sd-ink);
    margin-block-start: 32px;
    -webkit-font-smoothing: antialiased;
}

/* Apple's type scale. Sizes/weights/letter-spacing/line-heights are theirs verbatim. */
.sd-v2 .sd-t-body   { font-size: 17px; font-weight: 400; letter-spacing: -.022em; line-height: 1.4705882353; }
.sd-v2 .sd-t-small  { font-size: 14px; font-weight: 400; letter-spacing: -.016em; line-height: 1.4285914286; }
.sd-v2 .sd-t-fine   { font-size: 12px; font-weight: 400; letter-spacing: -.01em;  line-height: 1.3333733333; }

/* ---- section frame ------------------------------------------------------- */

.sd-v2 .sd-section { margin-block-end: 40px; }

.sd-v2 .sd-section__title {
    font-size: 24px;
    font-weight: 600;
    letter-spacing: .009em;
    line-height: 1.1666666667;
    color: var(--sd-ink);
    margin: 0 0 4px;
}

.sd-v2 .sd-section__hint {
    font-size: 14px;
    font-weight: 400;
    letter-spacing: -.016em;
    line-height: 1.4285914286;
    color: var(--sd-ink-2);
    margin: 0 0 18px;
}

.sd-v2 .sd-section__value { font-weight: 600; color: var(--sd-ink); }

/* ---- the selectable tile -------------------------------------------------
   Apple's .form-selector-label, rebuilt on a <button>. -------------------- */

.sd-v2 .sd-cards { display: grid; gap: 10px; }
.sd-v2 .sd-cards--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.sd-v2 .sd-cards--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

.sd-v2 .sd-card {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    inline-size: 100%;
    min-block-size: 78px;               /* Apple: 4.8823529412rem */
    padding: 15px;
    border: 1px solid var(--sd-ink-3);
    border-radius: var(--sd-radius-tile);
    background-color: var(--sd-surface);
    color: var(--sd-ink);
    font-family: var(--sd-font);
    font-size: 17px;
    font-weight: 400;
    letter-spacing: -.022em;
    line-height: 1.2353641176;
    cursor: pointer;
    transition: border-color .18s var(--sd-ease), background-color .18s var(--sd-ease);
}

.sd-v2 .sd-card:hover:not(.is-disabled) { border-color: var(--sd-ink); }

.sd-v2 .sd-card.is-selected {
    /* Apple's trick: border grows 1px, padding shrinks 1px -> the tile never shifts. */
    border-width: 2px;
    border-color: var(--sd-blue);
    padding: 14px;
}

.sd-v2 .sd-card.is-disabled {
    background-color: #00000003;
    border-color: #86868b6b;
    color: var(--sd-ink-2);
    cursor: not-allowed;
}

.sd-v2 .sd-card:focus-visible {
    outline: 2px solid var(--sd-blue);
    outline-offset: 3px;
}

.sd-v2 .sd-card__label {
    display: block;
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -.022em;
    line-height: 1.2353641176;
    color: inherit;
}

.sd-v2 .sd-card__meta {
    display: block;
    margin-block-start: 3px;
    font-size: 12px;
    font-weight: 400;
    letter-spacing: -.01em;
    line-height: 1.3333733333;
    color: var(--sd-ink-2);
}

/* "Most popular" pill */
.sd-v2 .sd-pill {
    display: inline-block;
    margin-inline-start: 6px;
    padding: 2px 8px;
    border-radius: var(--sd-radius-pill);
    background: var(--sd-blue);
    color: #fff;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: -.01em;
    line-height: 1.45;
    vertical-align: middle;
}

.sd-v2 .sd-pill--muted { background: var(--sd-surface-2); color: var(--sd-ink-2); }

/* ---- monthly value - the only money these sections show ------------------ */

.sd-v2 .sd-monthly {
    display: block;
    margin-block-start: 6px;
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -.022em;
    line-height: 1.2353641176;
    color: var(--sd-ink);
}

.sd-v2 .sd-monthly small {
    font-size: 12px;
    font-weight: 400;
    letter-spacing: -.01em;
    color: var(--sd-ink-2);
}

.sd-v2 .sd-monthly-was {
    margin-inline-end: 6px;
    font-size: 13px;
    font-weight: 400;
    text-decoration: line-through;
    color: var(--sd-ink-2);
}

/* ---- condition ----------------------------------------------------------- */

.sd-v2 .sd-condition__grade {
    display: inline-block;
    margin-inline-start: 6px;
    padding: 1px 8px;
    border: 1px solid var(--sd-line);
    border-radius: var(--sd-radius-pill);
    background: var(--sd-surface-2);
    font-size: 11px;
    font-weight: 400;
    color: var(--sd-ink-2);
}

.sd-v2 .sd-used-banner {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 12px 16px;
    border-radius: var(--sd-radius-tile);
    background: var(--sd-surface-2);
    color: var(--sd-ink);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: -.016em;
}

.sd-v2 .sd-used-banner svg { flex: none; color: var(--sd-ink-2); }

/* ---- locked state ---------------------------------------------------------
   "Choose how to pay" stays inert until the trade-in question is answered: a
   trade-in credit changes the financed principal, so the monthly figures are
   provisional until the customer has said whether they have one.
   detail-configurator.js (initPaymentGate) toggles this, and also drops the
   controls out of the tab order - pointer-events alone leaves them reachable by
   keyboard. Applied only when the trade-in section is actually present. */

/* Reads as unavailable rather than just faint: the whole block is greyed and desaturated, the
   cards lose their white fill, and the hint states why. A bare opacity drop was too subtle to
   register as "you cannot use this yet". */
.sd-v2 .sd-section.is-locked {
    pointer-events: none;
    user-select: none;
    position: relative;
}

.sd-v2 .sd-section.is-locked .sd-methods {
    opacity: .4;
    filter: grayscale(1);
    transition: opacity .25s var(--sd-ease), filter .25s var(--sd-ease);
}

/* The heading keeps its ink in EVERY state, locked or not.
   It used to grey to --sd-ink-3 while locked, which meant "Payment options." and the grey
   instruction after it came out the same colour for as long as the section was locked - i.e. for
   the whole time the customer is still choosing, which is exactly when the two-tone is meant to be
   doing its work. The locked state is already carried by the controls below (.sd-methods drops to
   opacity .4 and grayscale), and that is the stronger signal of the two. */
.sd-v2 .sd-section.is-locked .sd-section__title { color: var(--sd-ink); }

/* The second half of the heading - "Select the one that works for you." after "Payment options."
   Same type as the statement it continues, so the two read as one sentence; only the colour
   separates them, and it is the same grey the capacity and colour prompts use (--sd-ink-3, the
   lighter of the two greys), so every "you have not chosen yet" line on the page is one colour. */
.sd-v2 .sd-section__title-sub {
    color: var(--sd-ink-3);
    /* The <h3> carries the size and weight; this only recolours. Stated so a future change to the
       heading cannot leave the two halves in different type. */
    font: inherit;
}

/* Grey in every state, including locked. The previous `color: inherit` here made it follow the
   heading, which was correct only while the heading greyed too - and that greying is now gone, so
   inheriting would just turn this half black and collapse the two-tone entirely. */
.sd-v2 .sd-section.is-locked .sd-section__title-sub { color: var(--sd-ink-3); }

/* NEVER RENDERED VISIBLY - removed from the UI per request.
   Not display:none, and not deleted from the markup either: initPaymentGate rewrites this
   element's textContent to say WHICH step is unanswered, and role="status" on it is what announces
   that to a screen reader. display:none would take it out of the accessibility tree too, so the
   locked state would become silent as well as invisible. Clipped to a 1px box instead: no pixels,
   still announced, and the JS keeps working untouched. */
.sd-v2 .sd-section__locked,
.sd-v2 .sd-section.is-locked .sd-section__locked {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
    background: none;
}

.sd-v2 .sd-section.is-locked .sd-section__locked::before { content: none; }

/* ---- payment method cards -------------------------------------------------
   Apple's .rf-po-bfe-dimension-base-label: full-width, LEFT-aligned, content pushed
   apart with space-between, padding 22px 18px, and the same 1px -> 2px border /
   padding-compensation trick as the tiles. Term tiles nest inside the selected card.
   -------------------------------------------------------------------------- */

/* margin-block-start restores the breathing room the section hint used to provide: it was removed
   from this section, leaving the heading's 4px sitting straight on top of the cards. */
.sd-v2 .sd-methods { display: grid; gap: 12px; margin-block-start: 20px; }

/* And a clear break before whatever follows the payment section (the order summary). */
.sd-v2 #sdPaymentSection { margin-block-end: 56px; }

.sd-v2 .sd-method {
    border: 1px solid var(--sd-ink-3);
    border-radius: var(--sd-radius-card);
    background: var(--sd-surface);
    overflow: hidden;
    transition: border-color .18s var(--sd-ease), box-shadow .18s var(--sd-ease);
}

/* --only is a panel, not a control: it must not react to the pointer. */
.sd-v2 .sd-method:hover:not(.is-selected):not(.sd-method--only) { border-color: var(--sd-ink); }

.sd-v2 .sd-method.is-selected {
    border-width: 2px;
    border-color: var(--sd-blue);
}

.sd-v2 .sd-method__head {
    display: flex;
    /* BASELINE, not flex-start: the price on the right must sit on the same line as the method
       TITLE on the left, and the two are different sizes (17px vs 13px), so aligning their box tops
       would leave the smaller one riding high. A flex item's baseline is its first line's, and
       .sd-method__text is a block whose first line IS the title - so the description below it is
       correctly ignored. It was align-items:flex-start with the price centred against the whole
       text block, which floated it between the title and the description, level with neither. */
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    inline-size: 100%;
    padding: 22px 18px;
    border: 0;
    background: transparent;
    color: inherit;
    font-family: var(--sd-font);
    text-align: start;
    cursor: pointer;
}

/* TWO ROWS: title + price share row 1, the description spans the FULL card width on row 2.
   As a plain flex row the description sat inside .sd-method__text and so was squeezed into whatever
   the price left over - "Pay less monthly. Return the device at the end of your term." wrapped early
   against a mostly empty right-hand column.

   Grid, with .sd-method__text set to display:contents so its two children become grid items in
   their own right. That keeps the markup untouched - .sd-method__text is a styling wrapper with no
   semantics, and every JS selector (.sd-method__head, .sd-method__from-price) still resolves.

   Scoped away from --static, which is a different layout: no price, so nothing to lay out beside,
   and its title/description must stay stacked in normal flow rather than becoming grid siblings. */
.sd-v2 .sd-method__head:not(.sd-method__head--static) {
    display: grid;
    grid-template-columns: 1fr auto;
    /* Explicitly 0 row gap: the base rule's shorthand `gap: 16px` sets BOTH axes, which as a grid
       would open a 16px trench between the title and the description on top of the description's
       own 3px margin. Only the column gap is wanted. */
    gap: 0 16px;
}

.sd-v2 .sd-method__head:not(.sd-method__head--static) > .sd-method__text { display: contents; }
.sd-v2 .sd-method__head:not(.sd-method__head--static) .sd-method__title { grid-row: 1; grid-column: 1; }
.sd-v2 .sd-method__head:not(.sd-method__head--static) .sd-method__from { grid-row: 1; grid-column: 2; }
.sd-v2 .sd-method__head:not(.sd-method__head--static) .sd-method__desc { grid-row: 2; grid-column: 1 / -1; }

/* Border grows 1px on selection, so padding drops 1px and the card never shifts. */
.sd-v2 .sd-method.is-selected .sd-method__head { padding: 21px 17px; }

.sd-v2 .sd-method__head:focus-visible { outline: 2px solid var(--sd-blue); outline-offset: -4px; }

/* The radio dot was removed per request - selection is carried by the card's blue 2px border
   alone, the same way the capacity and term tiles indicate it. */

.sd-v2 .sd-method__text { flex: 1 1 auto; min-inline-size: 0; }

.sd-v2 .sd-method__title {
    display: block;
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -.022em;
    line-height: 1.2353641176;
    color: var(--sd-ink);
}

.sd-v2 .sd-method__desc {
    display: block;
    margin-block-start: 3px;
    font-size: 12px;
    font-weight: 400;
    letter-spacing: -.01em;
    line-height: 1.3333733333;
    color: var(--sd-ink-2);
}

.sd-v2 .sd-method__from {
    /* flex:none keeps it at its natural width so space-between holds it against the end edge;
       vertical placement is the head's baseline alignment, NOT an align-self of its own. */
    flex: none;
    font-size: 14px;
    font-weight: 400;
    letter-spacing: -.016em;
    color: var(--sd-ink-2);
    white-space: nowrap;
}

.sd-v2 .sd-method__from b { font-weight: 600; color: var(--sd-ink); }

/* ---- single option: stated, not offered ----------------------------------
   With one payment method there is nothing to choose between, so the card loses
   its selector chrome - no blue selected border, no radio semantics, no
   expand/collapse. It becomes a plain titled panel. Same for a lone term below.
   -------------------------------------------------------------------------- */

.sd-v2 .sd-method--only,
.sd-v2 .sd-method--only.is-selected {
    border-width: 1px;
    border-color: var(--sd-line);
}

.sd-v2 .sd-method__head--static {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    inline-size: 100%;
    padding: 20px 18px 4px;
    cursor: default;      /* nothing to click */
}

.sd-v2 .sd-method--only.is-selected .sd-method__head--static { padding: 20px 18px 4px; }

/* A method whose term is stated on the row itself. No body to expand, so the head owns the full
   padding and the term + price read as one value on the end edge. */
.sd-v2 .sd-method--flat .sd-method__head { padding-block: 20px; }

/* One line: "12 months from $69/mo." (installment) or "From $115.75/mo. for 12 months" (lease).
   These were display:block, which stacked the duration, the amount and the /mo. suffix into three
   rows. Everything here is inline. */
.sd-v2 .sd-method__from { white-space: nowrap; }

/* The lease line carries its term in the sentence, so it is long enough to crowd the title beside
   it on a narrow screen. It is allowed to wrap - but only at its spaces, and the amount can still
   never be split from its /mo. suffix because no whitespace separates them in the markup. */
.sd-v2 .sd-method[data-sd-method="lease"] .sd-method__from { white-space: normal; }

.sd-v2 .sd-method__from b { display: inline; font-weight: 600; color: var(--sd-ink); }

.sd-v2 .sd-method__from-price {
    display: inline;
    font-size: 13px;
    color: var(--sd-ink-2);
}

/* Gap only where something precedes it. The installment row states its term in a sibling <b>; the
   lease row has none, and an unconditional margin there indented the line for no reason. */
.sd-v2 .sd-method__from b + .sd-method__from-price { margin-inline-start: 5px; }

.sd-v2 .sd-method__from-price small { font-size: 12px; }

.sd-v2 .sd-method__body { padding: 0 18px 20px; }
.sd-v2 .sd-method.is-selected .sd-method__body { padding: 0 17px 19px; }

/* The 1px compensation above pairs with a border that grows on selection. --only keeps a 1px
   border throughout, so it must keep its padding too - otherwise picking a term nudges the whole
   panel a pixel. (It can pick up .is-selected: setMode() marks the method card after a refetch.) */
.sd-v2 .sd-method--only.is-selected .sd-method__body { padding: 0 18px 20px; }

/* ---- lease disclosures ---------------------------------------------------- */

.sd-v2 .sd-lease-terms {
    margin-block-start: 16px;
    padding: 18px 20px;
    border-radius: var(--sd-radius-card);
    background: var(--sd-surface-2);
}

.sd-v2 .sd-lease-terms h4 {
    margin: 0 0 10px;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: -.016em;
    color: var(--sd-ink);
}

.sd-v2 .sd-lease-terms ul { margin: 0; padding: 0; list-style: none; }

.sd-v2 .sd-lease-terms li {
    position: relative;
    margin-block-end: 8px;
    padding-inline-start: 16px;
    font-size: 12px;
    font-weight: 400;
    letter-spacing: -.01em;
    line-height: 1.3333733333;
    color: var(--sd-ink-2);
}

.sd-v2 .sd-lease-terms li::before {
    content: "";
    position: absolute;
    inset-inline-start: 4px;
    inset-block-start: 7px;
    inline-size: 3px;
    block-size: 3px;
    border-radius: 50%;
    background: var(--sd-ink-3);
}

.sd-v2 .sd-lease-terms li:last-child { margin-block-end: 0; }

/* ---- buttons -------------------------------------------------------------
   Apple's pill button. ---------------------------------------------------- */

.sd-v2 .sd-btn,
.sd-stickybar .sd-btn {
    display: inline-block;
    padding: 12px 22px;
    border: 1px solid var(--sd-blue);
    border-radius: var(--sd-radius-pill);
    background: var(--sd-blue);
    color: #fff;
    font-family: var(--sd-font);
    font-size: 17px;
    font-weight: 400;
    letter-spacing: -.022em;
    line-height: 1.1764805882;
    text-align: center;
    cursor: pointer;
    white-space: nowrap;
    transition: background-color .18s var(--sd-ease), border-color .18s var(--sd-ease);
}

.sd-v2 .sd-btn:hover:not(:disabled),
.sd-stickybar .sd-btn:hover:not(:disabled) {
    background: var(--sd-blue-hover);
    border-color: var(--sd-blue-hover);
}

/* Both scopes, like the :hover and :focus-visible rules around it. The sticky bar sits OUTSIDE
   .sd-v2 (it is position:fixed and must not inherit the section's reveal state), so a .sd-v2-only
   rule left #sdStickyApply looking like a live blue button while it was disabled - the summary's
   Apply greyed out, its twin in the bar did not. */
.sd-v2 .sd-btn:disabled,
.sd-stickybar .sd-btn:disabled { opacity: .42; cursor: not-allowed; }

.sd-v2 .sd-btn:focus-visible,
.sd-stickybar .sd-btn:focus-visible { outline: 2px solid var(--sd-blue); outline-offset: 3px; }

.sd-v2 .sd-btn--ghost {
    background: transparent;
    color: var(--sd-blue);
    border-color: var(--sd-blue);
}

.sd-v2 .sd-btn--ghost:hover:not(:disabled) {
    background: rgba(0, 113, 227, .06);
    border-color: var(--sd-blue);
    color: var(--sd-blue-hover);
}

.sd-v2 .sd-btn--link {
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--sd-blue);
    font-family: var(--sd-font);
    font-size: 14px;
    letter-spacing: -.016em;
    cursor: pointer;
}

.sd-v2 .sd-btn--link:hover { text-decoration: underline; }

/* ---- trade-in ------------------------------------------------------------- */

.sd-v2 .sd-tradein__credit {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-block-start: 16px;
    padding: 12px 16px;
    border-radius: var(--sd-radius-tile);
    background: var(--sd-surface-2);
    color: var(--sd-ink);
    font-size: 14px;
    font-weight: 600;
    letter-spacing: -.016em;
}

.sd-v2 .sd-tradein__caveats { margin: 14px 0 0; padding: 0; list-style: none; }

.sd-v2 .sd-tradein__caveats li {
    position: relative;
    margin-block-end: 6px;
    padding-inline-start: 14px;
    font-size: 12px;
    font-weight: 400;
    letter-spacing: -.01em;
    line-height: 1.3333733333;
    color: var(--sd-ink-2);
}

.sd-v2 .sd-tradein__caveats li::before {
    content: "";
    position: absolute;
    inset-inline-start: 3px;
    inset-block-start: 7px;
    inline-size: 3px;
    block-size: 3px;
    border-radius: 50%;
    background: var(--sd-ink-3);
}

/* ---- order summary -------------------------------------------------------- */

/* Apple's rf-bfe-summary / rf-po-bfe-purchaseoptionssummary: a full-width #f5f5f7 panel with a
   15px radius and 20px 24px padding, laid out as a flex row rather than a narrow sidebar card.
   The recap rows sit on the start edge, the total and the CTA on the end edge. */
/* =============================================================================
   Order summary - Apple's rf-bfe-summary-section-fullWidth
   -----------------------------------------------------------------------------
   Two columns: the device presented on the start edge (headline, subheadline,
   large product shot), and a white price box on the end edge with the CTA under
   it. Full width, above the FAQ.
   ============================================================================= */

/* Taken from Apple's own step1evolution.css (web/design/apple/…_files), not approximated.

   Their split is section -> content, and ours maps onto it with no markup change:

     .rf-bfe-summary-section-fullWidth  ->  #sdSummarySection   the grey band, full bleed
     .rf-bfe-summary-content            ->  .sd-summary         1240px, centred, the columns
     .rf-bfe-summary-grid-image         ->  "media"             headline + sub + shot
     .rf-bfe-summary-grid-price         ->  "panel"             prices + CTA
     .rf-bfe-summary-grid               ->  (dropped)           was the fulfillment strip + CTA

   TWO columns where theirs has three. Their third flex child is a 328px rail holding a fulfillment
   strip with the Continue button under it; the strip was removed per request and the button moved
   into the price panel, directly under the figure - so the rail had nothing left to hold.

   Theirs:  .rf-bfe-summary-section-fullWidth {
                background-color:#f5f5f7; padding:39px 6.25% 0;
            }
   Full BLEED, edge to edge - not a rounded panel.

   ONLY THE GREY BLEEDS. The section itself stays in normal flow at the page's own width, and the
   background is painted by an absolutely-positioned ::before that reaches the viewport edges.

   The section used to bleed itself (`inline-size:100vw` + negative inline margins) with the
   content re-centred inside it by a max-width. That put the CONTENT on a different grid from the
   rest of the site: everything else on the page is centred in the DOCUMENT, whereas 100vw is the
   VIEWPORT - which includes the scrollbar - so the summary sat a few pixels right of the header,
   the breadcrumb and the gallery, and its own 1360px cap made it visibly wider than all three.
   Painting the grey instead of stretching the box leaves the content on the page's grid, where it
   lines up with the site header by construction rather than by matching numbers to it. */
.sd-v2 #sdSummarySection.sd-section {
    /* Containing block for the ::before below. ([data-sd-reveal]'s will-change already makes this
       one, but the reveal is decoration - the background must not depend on it.) */
    position: relative;
    /* No inline padding: the section's own edges ARE the page's content edges now, and insetting
       the content from them is exactly the misalignment this rule exists to avoid. The white price
       box carries its own padding, so nothing ends up flush against the grey. */
    padding: 39px 0 48px;
    margin-block-end: 40px;
}

/* The grey, and nothing else.
   left/right:50% + a -50vw margin on each side is the standard full-bleed escape: it spans 100vw
   centred on this element regardless of how many containers it is nested inside. Any overhang past
   the document (100vw counts the scrollbar) is cut by `html { overflow-x: clip }` further down -
   which is why the overhang is harmless HERE but was not when the content rode on it.

   PHYSICAL left/right, not the logical shorthand: the two values are equal, so a logical property
   buys nothing and cannot be reinterpreted by an RTL ancestor.

   No z-index: this and .sd-summary below are both positioned with z-index:auto, so they paint in
   tree order and the content lands on top of the grey. A negative z-index would work too, but only
   for as long as nothing above this ever grows a background of its own. */
.sd-v2 #sdSummarySection.sd-section::before {
    content: "";
    position: absolute;
    inset-block: 0;
    left: 50%;
    right: 50%;
    margin-left: -50vw;
    margin-right: -50vw;
    background-color: #f5f5f7;
}

.sd-v2 .sd-summary {
    /* Paints above the ::before - see the note on it. */
    position: relative;
    display: grid;
    /* Theirs is a flex row with `margin-inline-end:auto` on both halves, which lays out as two
       columns separated by the slack. A grid states that directly. */
    /* The image column takes the larger share. Equal 1fr tracks split the 832px left after the
       328px rail and the gaps into 416px each, which was capping the shot no matter how wide the
       hero itself asked to be - a grid item cannot outgrow its track. 1.5fr gives it ~500px and
       leaves ~330px for the prices, which is inside their own 420px cap anyway. */
    /* TWO columns. There was a third - a 328px rail holding the fulfillment strip and the CTA - but
       the strip was removed per request and the button moved up beside the price figure, so the
       track had nothing left in it. Dropping it hands its 328px back to the two that remain. */
    grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
    grid-template-areas: "media panel";
    align-items: stretch;
    column-gap: 40px;
    row-gap: 0;
    /* NO max-width and no auto margins. Apple caps .rf-bfe-summary-content at 1240px because their
       band is the page's only frame; ours sits inside the page's own, which the breadcrumb, the
       gallery and the site header all share, so a second cap here could only ever disagree with
       them. A 1360px one did exactly that - it made the summary the widest thing on the page.
       The frame above owns the width; this fills it. */
    inline-size: 100%;
    padding: 0;
}

/* ---- left: the device, presented ---- */

/* .rf-bfe-summary-image { display:flex; flex-direction:column; height:100%; width:22.3529411765rem }
   A column so the shot can be pushed to the BOTTOM with margin-top:auto, which is what keeps the
   image sitting on the band's baseline however tall the headline wraps. */
.sd-v2 .sd-summary__hero {
    grid-area: media;
    display: flex;
    flex-direction: column;
    block-size: 100%;
    /* Fills its track rather than naming a width. Apple's fixed 22.3529411765rem was the first
       limiter and a 27rem replacement was the second - both were smaller than the track once the
       grid gave this column the larger share, and a fixed width cannot grow into space it never
       asked for. The track owns the sizing now; see grid-template-columns above. */
    inline-size: 100%;
    min-inline-size: 0;
    text-align: start;
}

/* ---- the headline: "Your new / <name> / <closing line>" ----
   .rf-bfe-summary-image-headline { font-size:38px; font-weight:600; letter-spacing:.004em;
                                    line-height:1.2105263158 }  - SF Pro DISPLAY

   THREE STACKED LINES rather than Apple's one wrapping sentence, in both the waiting and the
   finished state. Theirs holds the name together with non-breaking spaces and lets the sentence
   wrap where it likes; ours gives "Your new" and the name a line each outright, so the name can
   never be split across a line break however narrow the column gets.

   The SIZE lives on the block and every line inherits it - which is what lets the whole statement
   step down together for a long name (see .is-long / .is-xlong) instead of the name shrinking away
   from the lines around it.

   Both states use this same class; the JS shows one and [hidden]s the other, and the utility block
   at the foot of this file makes that display:none !important, so `display:flex` here cannot
   resurrect a hidden block. */
.sd-v2 .sd-summary__intro {
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
    font-size: 38px;
    font-weight: 600;
    letter-spacing: .004em;
    line-height: 1.2105263158;
    color: var(--sd-ink);
}

.sd-v2 .sd-summary__intro-line {
    font-size: inherit;
    font-weight: inherit;
    letter-spacing: inherit;
    line-height: inherit;
    /* The name is the one line that can carry an unbroken token long enough to overrun the
       column - a model code, a spec string. Break it rather than let it push the grid out. */
    overflow-wrap: anywhere;
}

/* Two lines maximum for the name. Past that the statement stops being three lines and the shot
   below it gets squeezed; the tail of a name that long is never the part that identifies it. */
.sd-v2 .sd-summary__intro-name {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}

/* Apple's subheadline grey. The closing line is the quiet half of the statement - same 38px/600 as
   the two above it, only grey, so the three read as one big statement rather than as a title with
   a caption under it. .rf-bfe-summary-image-subheadline { color:#86868b } */
.sd-v2 .sd-summary__intro-tail { color: #86868b; }

/* Long-name steps. Applied server-side from the name's length (see _OrderSummary.cshtml), so the
   right size is in the first paint. Only the block's font-size changes - every line inherits it,
   so the three stay in one size. */
.sd-v2 .sd-summary__intro.is-long { font-size: 30px; letter-spacing: .006em; }
.sd-v2 .sd-summary__intro.is-xlong { font-size: 24px; letter-spacing: .009em; line-height: 1.1666666667; }

/* A white card, deliberately the same one as the price box on the other side of the grid: same
   --sd-surface fill and same 18px radius, so the two columns read as a matched pair sitting on the
   grey panel rather than as a floating cut-out next to a card.

   A definite height is what lets the image fill it. Left to the image's own intrinsic size the box
   would change height with every variant - a wide TV shot and a tall phone shot would give the row
   two different geometries - and the panel would jump as the customer changes colour. */
/* .rf-bfe-summary-image-wrapper { margin-top:auto; padding-top:42px; margin:0 auto }
   margin-block-start:auto is the load-bearing one: it eats the column's slack so the shot sits at
   the BOTTOM of the left column, level with the foot of the price list beside it. */
/* THE SQUARE IS THE CONTAINER, not the image.
   The 1:1 used to sit on the <img> itself, which meant the img WAS the square and any photo that
   did not fill it letterboxed inside its own box - the frame and the picture were the same element,
   so there was nothing for the picture to "fit inside".
   Now the wrapper owns the square and centres whatever it is given: a portrait shot fills the
   height and gutters at the sides, a landscape one fills the width - and either way the reserved
   box is identical, so nothing moves as the src changes.

   margin-block-start:auto keeps it bottom-aligned in the column; the 42px that used to be
   padding-block-start is gone with it, because padding inside an aspect-ratio box eats the square
   rather than spacing it. */
.sd-v2 .sd-summary__hero-media {
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-block-start: auto;
    margin-inline: auto;
    inline-size: 100%;
    /* CAPPED. `inline-size: 100%` with a 1:1 ratio means the square is as wide as its track and as
       tall as it is wide, so the image sizes itself off the grid rather than off anything about the
       image. That was survivable while a 328px rail was taking a third of the row; once the rail was
       removed the track grew by ~40% and the shot grew with it, to the point where it was the
       loudest thing in a panel whose subject is a price.

       400px is close to Apple's own 328px image cap with a little more presence, and it holds
       whatever the grid does next - the box stops tracking the column width from here. */
    max-inline-size: 400px;
    aspect-ratio: 1 / 1;
    padding: 0;
    background: none;
    border-radius: 0;
}

/* .rf-bfe-summary-image-img { display:block; height:auto; width:100%; max-width:328px }
   plus a RESERVED BOX, which theirs gets for free and ours cannot.

   Apple ships width="362" height="270" on the tag, so the browser knows the ratio before a byte
   arrives and holds the space. Our src is a File/ImgGet URL with no dimensions in the markup and no
   fixed size behind it, so with `height:auto` the box is zero until the bitmap decodes and then
   snaps to whatever ratio that particular photo happens to have. Every variant change re-ran that,
   and since the shot is bottom-aligned in the column the whole band moved with it.

   aspect-ratio states the box in CSS instead: the space is identical whether the image is loading,
   loaded, missing, portrait or landscape. 362/270 is Apple's own frame. object-fit:contain then
   letterboxes whatever actually arrives inside it rather than distorting it. */
/* FILLS the square container above. Both axes at 100% and no aspect-ratio of its own - the wrapper
   owns the square now, and a second ratio here would size the image independently of the box it is
   meant to fill.

   object-fit: contain, so the whole product stays visible and is never distorted; a photo whose
   shape does not match the square gutters inside it instead of being cropped. Switch this one word
   to `cover` if you would rather it reach every edge and lose the edges of the device. */
.sd-v2 .sd-summary__hero-img {
    display: block;
    inline-size: 100%;
    block-size: 100%;
    max-inline-size: 100%;
    max-block-size: 100%;
    /* The <img> is square in its own right, not only because the wrapper happens to be. Stated here
       as well so the element keeps its shape if it is ever used outside .sd-summary__hero-media, and
       so nothing in the source photo's intrinsic dimensions can pull the box out of square while it
       loads. The wrapper's 1:1 and this agree, so neither fights the other. */
    aspect-ratio: 1 / 1;
    object-fit: contain;
    transition: opacity .22s var(--sd-ease);
}

/* Held while detail-configurator.js swaps the src and waits for the new bitmap to decode, so the
   fade reveals the image rather than an empty box. */
.sd-v2 .sd-summary__hero-img.is-swapping { opacity: 0; }

/* Before syncSummaryPhoto() has supplied one. visibility rather than display so the image still
   occupies its place in the card and nothing reflows when the src lands. */
.sd-v2 .sd-summary__hero-img:not([src]) { visibility: hidden; }

/* ---- right: the price box ---- */

/* Apple's .rf-bfe-summary-grid-price - the right column.
   .rf-bfe-summary-price-section { max-width:420px; min-width:360px; padding-inline-end:20px }
   The cap is what stops the price sentence and the specs running the full width of a 1240px band -
   a measure that wide makes a 24px line hard to read back. */
.sd-v2 .sd-summary__panel {
    grid-area: panel;
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
    max-inline-size: 420px;
    padding-inline-end: 20px;
}

/* Apple's .rf-bfe-summary-price-box. No card, no shadow, no fill: theirs is plain text on the page
   background, and the previous white box only existed to sit on the grey panel that has now gone
   with it. */
.sd-v2 .sd-summary__box {
    display: flex;
    flex-direction: column;
    padding: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
}

/* ---- what you configured ----
   The column reads as a RECEIPT, in two blocks separated by one hairline:

       iPhone 17 Pro                 <- what it is
       Cosmic Orange · 256 GB
       ───────────────────────
       ● Installments                <- what it costs
       Pay $313/mo. for 6 months
       Trade-in credit      − $200

   Before, it was five text sizes stacked with nothing grouping them, so the eye had no order to
   follow and every line asked for the same attention. The rule does the grouping; the name leads at
   24px instead of 17px, because in a column with no card around it something has to be the heading
   and a 17px line beside a 38px headline was not it. */

.sd-v2 .sd-summary__product {
    margin: 0;
    font-size: 24px;
    font-weight: 600;
    letter-spacing: .009em;
    line-height: 1.1666666667;
    color: var(--sd-ink);
}

.sd-v2 .sd-summary__specs {
    /* min-block-size holds the line before a colour is resolved, so the figure below it does not
       shift the moment the first spec appears. */
    margin: 6px 0 0;
    min-block-size: 20px;
    font-size: 14px;
    font-weight: 400;
    letter-spacing: -.016em;
    line-height: 1.4285914286;
    color: var(--sd-ink-2);
}

.sd-v2 .sd-summary__spec { display: inline; }

/* Separator drawn only between two VISIBLE specs - the sibling combinator is what makes that work,
   since the first visible spec has no visible spec before it and so gets no leading middot. A fixed
   separator inside each span would strand one the moment its neighbour hides, and these hide
   constantly. */
.sd-v2 .sd-summary__spec:not([hidden]) ~ .sd-summary__spec:not([hidden])::before {
    content: "·";
    margin-inline: 7px;
    color: var(--sd-ink-3);
}

/* ---- payment method badge ----
   The active scheme, stated once, as a pill under the configuration line. Replaces the
   "Payment method | Installments" row that used to open the fact list.

   Sized and coloured like a status marker rather than a heading: it is an answer the customer
   already gave, so it confirms rather than announces. The blue dot is the only colour in the box
   apart from the trade-in tick, which is the point - it marks the one live choice. */
/* A LABEL over the price, not a pill beside it.
   The pill was a floating object in a column that has no other boxes - it read as a stray tag. As a
   caption directly above the figure it belongs to, it does the same job quietly and lets the price
   keep the emphasis.

   It also carries the receipt's one dividing rule, which is why it is display:flex rather than
   inline: a border on an inline box only spans the text, not the column. */
.sd-v2 .sd-summary__method {
    display: flex;
    align-items: center;
    gap: 7px;
    margin-block-start: 22px;
    padding-block-start: 22px;
    border-block-start: 1px solid #d2d2d7;
    color: var(--sd-ink-2);
    font-size: 13px;
    font-weight: 400;
    letter-spacing: -.01em;
    line-height: 1.2307692308;
    white-space: nowrap;
}

/* [hidden] on a flex box needs saying explicitly - the display wins otherwise, and renderSummary()
   hides this element by toggling that attribute.
   When it IS hidden the rule goes with it, so the figure below carries its own copy. */
.sd-v2 .sd-summary__method[hidden] { display: none; }

.sd-v2 .sd-summary__method-dot {
    flex: none;
    inline-size: 7px;
    block-size: 7px;
    border-radius: 50%;
    background: var(--sd-blue);
}

/* ---- the monthly figure ----
   One slot, two mutually exclusive occupants: the prompt or the price. The floor is on this slot
   rather than on the box, so the fact rows and the Apply button below never move - the figure
   resolves in place. */
/* Sits directly under its caption, so only a small gap - the 22px of air and the rule above belong
   to .sd-summary__method now.
   The floor drops with the figure: 104px was sized to hold a 44px display number and left a band of
   dead space around a 24px line. 52px still clears both occupants - the two-line prompt and the
   price sentence - which is all the floor is for. */
.sd-v2 .sd-summary__figure {
    display: flex;
    align-items: center;
    min-block-size: 52px;
    margin-block-start: 6px;
}

/* The method caption carries the receipt's dividing rule, but it is hidden until a method is
   chosen - and until then the price slot needs the rule instead, or the second block floats with
   nothing separating it from the name above.
   :has() reads "no visible method caption before me"; where it is unsupported the layout simply
   keeps the older spacing, which is the safe direction to fail in. */
.sd-v2 .sd-summary__box:has(.sd-summary__method[hidden]) .sd-summary__figure {
    margin-block-start: 22px;
    padding-block-start: 22px;
    border-block-start: 1px solid #d2d2d7;
}

.sd-v2 .sd-summary__empty {
    margin: 0;
    max-inline-size: 24ch;
    font-size: 15px;
    font-weight: 400;
    letter-spacing: -.016em;
    line-height: 1.3333733333;
    color: var(--sd-ink-3);
}

/* Same slot, different job: not "keep going" but "there is nothing to keep going to". Darker than
   the prompt because it is an answer rather than an invitation, and wider because the sentence is
   a real one - 24ch would break the explanation into a narrow column. Deliberately NOT red: the
   customer has done nothing wrong and nothing has failed. */
.sd-v2 .sd-summary__empty.is-not-eligible {
    max-inline-size: 40ch;
    color: var(--sd-ink-2);
}

/* ONE SENTENCE, not a stacked figure.
   Apple's price is a single line at .as-price-currentprice:
       { font-size:24px; font-weight:600; letter-spacing:.009em; line-height:1.1666666667 }
   reading "or $58.29/mo. for 24 mo." - verb, amount and term all the same size.

   Ours was a 13px label over a 44px number over a 13px term. That was built for a WHITE CARD on a
   grey panel, where the figure had a box of its own to fill. With the card gone and the column
   sitting directly on the band, a 44px number is the loudest thing on the page and shouts over the
   38px headline beside it - which is the one thing that is meant to lead.

   All three parts are inline now and inherit from here, so the line reads
   "Pay $313/mo. for 6 months" as one statement. */
.sd-v2 .sd-summary__price {
    display: block;
    font-size: 24px;
    font-weight: 600;
    letter-spacing: .009em;
    line-height: 1.1666666667;
    color: var(--sd-ink);
}

.sd-v2 .sd-summary__price-verb {
    display: inline;
    font: inherit;
    letter-spacing: inherit;
    color: inherit;
}

/* tabular-nums is the detail that matters most here: the amount is rewritten on every term change,
   and proportional digits make the whole line twitch as it does. */
.sd-v2 .sd-summary__price-amount {
    display: inline;
    margin: 0;
    font: inherit;
    letter-spacing: inherit;
    color: inherit;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* No longer raised or shrunk. At 44px the currency was a superscript unit beside a display number;
   at 24px it is just the first character of the amount, and lifting it only breaks the baseline. */
.sd-v2 .sd-summary__price-cur {
    font: inherit;
    letter-spacing: inherit;
    color: inherit;
    vertical-align: baseline;
    margin-inline-end: 1px;
}

/* "/mo." stays a shade lighter - it is the unit, and it is the one part of the line that never
   changes, so it should not compete with the number that does. */
.sd-v2 .sd-summary__price-amount small {
    margin-inline-start: 1px;
    font-size: inherit;
    font-weight: 400;
    letter-spacing: inherit;
    color: var(--sd-ink-2);
}

/* Inline, so "Pay $313/mo. for 6 months" is one sentence.
   A second, later `display:block` copy of this rule used to sit here from the stacked-figure
   layout; it silently won on source order and put the term back on its own line. */
.sd-v2 .sd-summary__price-term {
    display: inline;
    font: inherit;
    letter-spacing: inherit;
    color: var(--sd-ink-2);
}

/* ---- the terms behind the figure ---- */

.sd-v2 .sd-summary__facts { margin: 18px 0 0; }

/* Each row owns its own top hairline. On the list instead, it would survive every row hiding and
   leave a rule floating under the figure. */
.sd-v2 .sd-summary__fact {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding-block: 10px;
    border-block-start: 1px solid var(--sd-line);
    font-size: 13px;
    letter-spacing: -.01em;
    line-height: 1.3846153846;
}

.sd-v2 .sd-summary__fact dt {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: 400;
    color: var(--sd-ink-2);
}

.sd-v2 .sd-summary__fact dd {
    margin: 0;
    font-weight: 500;
    color: var(--sd-ink);
    text-align: end;
}

.sd-v2 .sd-summary__fact--credit dd { font-weight: 600; color: var(--sd-green); }
.sd-v2 .sd-summary__fact--credit dd b { font-weight: inherit; }

/* Tick on the trade-in row. Sized to the 13px label it sits in, not to the 15px it was when this
   was a standalone note block. */
.sd-v2 .sd-summary__note-icon {
    flex: none;
    inline-size: 14px;
    block-size: 14px;
    border-radius: 50%;
    background: var(--sd-green);
    position: relative;
}

.sd-v2 .sd-summary__note-icon::after {
    content: "";
    position: absolute;
    inset-inline-start: 4.5px;
    inset-block-start: 3px;
    inline-size: 4px;
    block-size: 6.5px;
    border: solid #fff;
    border-width: 0 1.5px 1.5px 0;
    transform: rotate(45deg);
}

/* Apple's third column (.rf-bfe-summary-grid, a 328px rail) and the fulfillment strip that filled
   it - .sd-summary__aside, .sd-summary__fulfillment and its __fulfil / __fulfil-icon /
   __fulfil-title parts - were REMOVED PER REQUEST along with their markup in _OrderSummary.cshtml.
   Their rules are gone with them rather than left orphaned.

   NOT to be confused with .sd-stickybar__fulfillment further down this file: that is the sticky
   bar's own scroller, a different element with different content, and it stays. */

/* ---- the price, and the button directly under it ----
       Pay $335/mo. for 6 months
       [        Apply        ]

   The button used to sit in a third column of its own, level with the foot of the panel. Under the
   figure it reads as the answer to it - the price states the offer and the button takes it, with
   nothing between them and no need to look across the summary to find the thing to press. */
.sd-v2 .sd-summary__action {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    inline-size: 100%;
}

/* .rf-bfe-summary-button-box-fullWidth {
       align-items:center; display:flex; flex-flow:row-reverse; padding-inline-start:0;
       padding-top:48px }

   Apple's 48px padding-top went with the column it belonged to - it was clearance below the
   fulfillment strip. Directly under one line of price it only needs enough to separate the two. */
.sd-v2 .sd-summary__cta {
    display: flex;
    flex-flow: row-reverse;
    align-items: center;
    padding-block-start: 20px;
    padding-inline-start: 0;
}

/* Apple's Continue is `class="button button-block rc-summary-button-height"`, and their tokens are:
       .button-block            { --sk-button-width:100%; --sk-button-display:block;
                                  --sk-button-border-radius:12px }
       .rc-summary-button-height{ height:44px }
       .rc-summary-button       { flex-grow:2 }
   A FULL-WIDTH block button, 44px tall, 12px radius - the width of what it sits in, not sized by
   its label. Under the price that is the width of the price panel, which is what makes it read as
   the panel's action rather than as a chip parked next to a number. */
.sd-v2 .sd-summary__cta .sd-btn {
    flex: 1;
    inline-size: 100%;
    block-size: 44px;
    padding-block: 0;
    padding-inline: 22px;
    border-radius: 12px;
    font-size: 17px;
}

/* =============================================================================
   FAQ accordion - Apple's buy-flow FAQ
   Built on <details>/<summary>: keyboard support, screen-reader semantics and
   find-in-page all come for free. Chevron + open animation are CSS only.
   ============================================================================= */

.sd-v2 .sd-faq { margin-block-start: 12px; }

.sd-v2 .sd-faq__list { border-block-start: 1px solid var(--sd-line); }

.sd-v2 .sd-faq__item { border-block-end: 1px solid var(--sd-line); }

.sd-v2 .sd-faq__q {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 18px 2px;
    cursor: pointer;
    list-style: none;                 /* kill the native marker... */
    font-size: 17px;
    font-weight: 400;
    letter-spacing: -.022em;
    line-height: 1.4705882353;
    color: var(--sd-ink);
    transition: color .18s var(--sd-ease);
}

.sd-v2 .sd-faq__q::-webkit-details-marker { display: none; }   /* ...Safari's too */

.sd-v2 .sd-faq__q:hover { color: var(--sd-blue); }
.sd-v2 .sd-faq__q:focus-visible { outline: 2px solid var(--sd-blue); outline-offset: 2px; }

.sd-v2 .sd-faq__q-text { flex: 1 1 auto; }

.sd-v2 .sd-faq__chevron {
    flex: none;
    display: inline-flex;
    color: var(--sd-ink-2);
    transition: transform .3s var(--sd-ease), color .18s var(--sd-ease);
}

.sd-v2 .sd-faq__item[open] .sd-faq__chevron { transform: rotate(180deg); color: var(--sd-blue); }
.sd-v2 .sd-faq__item[open] .sd-faq__q { color: var(--sd-ink); font-weight: 600; }

.sd-v2 .sd-faq__a {
    padding: 0 2px 20px;
    max-inline-size: 62ch;
}

.sd-v2 .sd-faq__a p {
    margin: 0;
    font-size: 14px;
    font-weight: 400;
    letter-spacing: -.016em;
    line-height: 1.5714;
    color: var(--sd-ink-2);
}

/* Answers slide open. Only applied where the browser can animate to height:auto
   (interpolate-size), so nowhere else does it clip content. */
@supports (interpolate-size: allow-keywords) {
    .sd-v2 .sd-faq__item::details-content {
        block-size: 0;
        overflow: hidden;
        transition: block-size .32s var(--sd-ease), content-visibility .32s allow-discrete;
    }
    .sd-v2 .sd-faq__item[open]::details-content { block-size: auto; }
}

@media (max-width: 575.98px) {
    .sd-v2 .sd-faq__q { font-size: 15px; padding: 15px 2px; }
    .sd-v2 .sd-faq__a { padding-block-end: 16px; }
    .sd-v2 .sd-faq__a p { font-size: 13px; }
}

/* =============================================================================
   Sticky bar - Apple's .rf-bfe-stickybar
   Fixed to the top, slides down from translateY(-100%) once the main CTA has
   scrolled out of view. pointer-events are off on the container so it never
   swallows clicks while hidden.
   ============================================================================= */

.sd-stickybar {
    position: fixed;

    /* The site header (.sticky-bar.stick) is permanently position:fixed at top:0 - "stick" is in
       the markup, not added on scroll.

       --sd-bar-top is THIS bar's own offset, and it is not the same as the header height: the
       header withdraws exactly when this bar appears, so the bar takes its place at 0. It only
       parks below the header while it is hidden (sliding up behind the nav rather than poking
       out above it). Using the header height here left the bar floating a header down the page.
       detail-configurator.js keeps it current; 0 is only the pre-JS value. */
    inset-block-start: var(--sd-bar-top, 0px);
    inset-inline-start: 0;
    inline-size: 100%;

    /* Deliberately below the site header's z-index:1000, so the bar slides up BEHIND the nav when
       it hides instead of poking out above it. */
    z-index: 999;
    pointer-events: none;
    font-family: var(--sd-font);
}

/* While the product bar is showing, the global header withdraws upward so the two never stack.
   Only a transform - the header keeps its layout box and every nav handler stays bound, so it
   slides straight back when the bar hides. */
header.sticky-bar.sd-header-withdrawn,
.sticky-bar.sd-header-withdrawn {
    transform: translateY(-100%);
    transition: transform .4s ease-in-out;
}

header.sticky-bar,
.sticky-bar {
    transition: transform .4s ease-in-out;
}

.sd-stickybar__content {
    /* Opaque white, NOT the translucent blur it had before: the selection chips are #f5f5f7, and
       against rgba(255,255,255,.92) that is a ~2% difference - the chips read as white and the
       colour looked like it had never been applied. A solid backdrop is what makes them visible. */
    background-color: #fff;
    border-block-end: 1px solid var(--sd-line);
    transform: translateY(-100%);
    transition: transform .5s ease-in-out;
}

.sd-stickybar.is-visible .sd-stickybar__content {
    transform: translateY(0);
    pointer-events: auto;
}

/* Apple's .rf-bfe-container: one gutter shared by both rows so name, price and the strip below
   line up on the same left edge. */
/* Mirrors the global header's frame exactly, so this bar's content lines up with the nav above
   it rather than sitting inset from it.
   Source: assets/css/header-revamp.css -> .header--nm .container
       max-width 1280px, padding-inline 16px, dropping to 0 at >=1280px.
   The previous 1180px + permanent 16px gutter left the title and Apply button roughly 66px
   inboard of the header's logo and account links. Keep these two in step if the header changes. */
.sd-stickybar__container {
    max-inline-size: 1280px;
    inline-size: 100%;
    margin-inline: auto;
    padding-inline: max(16px, env(safe-area-inset-left)) max(16px, env(safe-area-inset-right));
}

@media (min-width: 1280px) {
    .sd-stickybar__container {
        padding-inline: max(0px, env(safe-area-inset-left)) max(0px, env(safe-area-inset-right));
    }
}

/* ---- row 1: header ---- */

.sd-stickybar__header .sd-stickybar__container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding-block: 11px;
}

.sd-stickybar__title {
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -.022em;
    line-height: 1.2353641176;
    color: var(--sd-ink);
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sd-stickybar__price {
    font-size: 14px;
    font-weight: 400;
    letter-spacing: -.016em;
    line-height: 1.4285914286;
    color: var(--sd-ink-2);
    margin: 1px 0 0;
    white-space: nowrap;
}

.sd-stickybar__price b { font-weight: 600; color: var(--sd-ink); }

.sd-stickybar__actions { display: flex; align-items: center; gap: 12px; flex: none; }

.sd-stickybar .sd-btn { padding: 8px 18px; font-size: 14px; letter-spacing: -.016em; }

/* Apple's -withdimensionselected modifier. Once a configuration exists the bar carries two rows,
   so the header tightens to keep the whole thing from eating the viewport. */
.sd-stickybar__content.is-dimension-selected .sd-stickybar__header .sd-stickybar__container {
    padding-block: 8px;
}

/* ---- row 2: fulfillment scroller (Apple's .rf-bfe-stickybar-fulfillment) ----
   A hairline separates it from the header row, and the strip scrolls horizontally with paddlenav
   arrows either side. The scrollbar itself is hidden: the paddles and the edge fades are the
   affordance, exactly as on Apple's bar. -------------------------------------- */

.sd-stickybar__fulfillment {
    border-block-start: 1px solid var(--sd-line);
}

.sd-stickybar__scroller-crop {
    position: relative;
    display: flex;
    align-items: center;
}

.sd-stickybar__scroller-content {
    flex: 1 1 auto;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;              /* Firefox */
    -ms-overflow-style: none;           /* legacy Edge */
    scroll-behavior: smooth;
}

.sd-stickybar__scroller-content::-webkit-scrollbar { display: none; }

.sd-stickybar__platter {
    display: flex;
    align-items: center;
    gap: 8px;
    padding-block: 8px;
    inline-size: max-content;
}

/* Selection chips: same fill as the order summary, so the two surfaces that recap the
   configuration read as one material. #e8e8ed rather than Apple's #f5f5f7 - against the white
   bar, their grey was invisible. */
.sd-stickybar__cell {
    flex: none;
    padding: 4px 12px;
    border: 1px solid transparent;
    border-radius: var(--sd-radius-pill);
    background: #e8e8ed;
    font-size: 12px;
    font-weight: 400;
    letter-spacing: -.01em;
    line-height: 1.3333733333;
    color: var(--sd-ink-2);
    white-space: nowrap;
}

/* The chosen configuration reads as the primary information; delivery options sit behind it.
   Distinguished by weight and ink now that both share the same fill. */
.sd-stickybar__cell--dimension {
    font-weight: 500;
    color: var(--sd-ink);
}

/* ---- paddlenav ---- */

.sd-paddlenav {
    position: relative;
    flex: none;
    display: none;                      /* only meaningful once the strip overflows */
}

.sd-stickybar__scroller-crop.has-overflow .sd-paddlenav { display: block; }

.sd-paddlenav__arrow {
    inline-size: 28px;
    block-size: 28px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--sd-ink-2);
    cursor: pointer;
    transition: color .18s var(--sd-ease), opacity .18s var(--sd-ease);
}

.sd-paddlenav__arrow:hover:not(:disabled) { color: var(--sd-ink); }
.sd-paddlenav__arrow:disabled { opacity: .28; cursor: default; }
.sd-paddlenav__arrow:focus-visible { outline: 2px solid var(--sd-blue); outline-offset: 2px; }

/* Chevrons drawn in CSS - no icon font or SVG dependency, and they flip under RTL for free
   because the border box is rotated rather than pointing at a fixed direction. */
.sd-paddlenav__arrow::before {
    content: "";
    display: block;
    inline-size: 8px;
    block-size: 8px;
    margin-inline: auto;
    border-block-start: 1.5px solid currentColor;
    border-inline-end: 1.5px solid currentColor;
}

.sd-paddlenav--prev .sd-paddlenav__arrow::before { transform: rotate(-135deg); margin-inline-start: 12px; }
.sd-paddlenav--next .sd-paddlenav__arrow::before { transform: rotate(45deg);   margin-inline-end: 12px; }

/* Edge fades, so a cell scrolling out of view dissolves instead of being cut off. */
.sd-stickybar__scroller-crop.has-overflow::before,
.sd-stickybar__scroller-crop.has-overflow::after {
    content: "";
    position: absolute;
    inset-block: 0;
    inline-size: 24px;
    pointer-events: none;
    z-index: 1;
}

.sd-stickybar__scroller-crop.has-overflow::before {
    inset-inline-start: 28px;
    background: linear-gradient(to right, rgba(255,255,255,.92), rgba(255,255,255,0));
}

.sd-stickybar__scroller-crop.has-overflow::after {
    inset-inline-end: 28px;
    background: linear-gradient(to left, rgba(255,255,255,.92), rgba(255,255,255,0));
}

[dir="rtl"] .sd-stickybar__scroller-crop.has-overflow::before {
    background: linear-gradient(to left, rgba(255,255,255,.92), rgba(255,255,255,0));
}

[dir="rtl"] .sd-stickybar__scroller-crop.has-overflow::after {
    background: linear-gradient(to right, rgba(255,255,255,.92), rgba(255,255,255,0));
}

/* Screen-reader-only label on the paddle buttons. */
.sd-visuallyhidden {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* =============================================================================
   Trade-in - inline widget
   -----------------------------------------------------------------------------
   Port of Apple's .rf-bfe-tradeup-* / .rf-tradeupinline-* module. Replaced the
   modal wizard: the whole flow, condition questionnaire included, now lives in
   the page. Two radios side by side, a drawer spanning both beneath them, and
   one titled <select> per question inside it.
   ============================================================================= */

.sd-v2 .sd-tradeup__header { margin-block-end: 18px; }

/* Apple sets the section name and the credit range in ONE heading, the range in a
   lighter weight - not a title with a separate subtitle beneath it. */
.sd-v2 .sd-tradeup__title {
    margin: 0;
    font-size: 24px;
    font-weight: 600;
    letter-spacing: .009em;
    line-height: 1.1666666667;
    color: var(--sd-ink);
}

.sd-v2 .sd-tradeup__sub {
    font-weight: 400;
    color: var(--sd-ink-2);
}

.sd-v2 .sd-tradeup__row { display: grid; grid-template-columns: 1fr; gap: 24px; }

/* Single column stacked: options, then the drawer, then the info card. Explicit rows so the
   drawer follows the options it belongs to instead of being pushed below the info card. */
.sd-v2 .sd-tradeup__left { grid-row: 1; }
.sd-v2 .sd-tradeup__drawer { grid-row: 2; }

@media (min-width: 992px) {
    /* Single column since the "How does trade-in work?" card was removed - the two options and the
       drawer both span the full width now. Restoring that card means putting the second track
       (minmax(0, 300px)) back here and giving .sd-tradeup__right grid-column: 2. */
    .sd-v2 .sd-tradeup__row {
        grid-template-columns: minmax(0, 1fr);
        column-gap: 32px;
        row-gap: 20px;
        align-items: start;
    }

    /* Options and the info card share row 1; the drawer takes the whole of row 2, so it runs the
       full width of the widget rather than stopping at the left column. */
    .sd-v2 .sd-tradeup__left { grid-column: 1 / -1; grid-row: 1; }
    .sd-v2 .sd-tradeup__drawer { grid-column: 1 / -1; grid-row: 2; }
}

/* ---- the two options ----
   The drawer is no longer in here - it is a child of .sd-tradeup__row so it can span the full
   width of the widget. This grid holds only the two radio tiles. */
.sd-v2 .sd-tradeup__selectors {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}

@media (max-width: 575.98px) {
    .sd-v2 .sd-tradeup__selectors { grid-template-columns: minmax(0, 1fr); }
}

/* The radio itself is visually hidden but still focusable, so the label carries the
   selected styling and keyboard focus lands somewhere visible. */
.sd-v2 .sd-tradeup__input {
    position: absolute;
    opacity: 0;
    inline-size: 1px;
    block-size: 1px;
    margin: 0;
}

/* One tile height shared by the two option tiles and the "How does trade-in work?" card beside
   them, so the three read as a single row. Change it here and all three follow.
   92px rather than Apple's 78px: the info card's two lines of copy do not fit in 78, and growing
   the row is better than truncating the sentence to a fragment. */
.sd-v2 .sd-tradeup__row { --sd-tradeup-tile-h: 92px; }

.sd-v2 .sd-tradeup__label {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;      /* centred horizontally - the two tiles read as a pair of choices */
    text-align: center;
    gap: 3px;
    block-size: 100%;
    min-block-size: var(--sd-tradeup-tile-h);
    margin: 0;
    padding: 15px 17px;
    border: 1px solid var(--sd-ink-3);
    border-radius: var(--sd-radius-tile);
    background: var(--sd-surface);
    cursor: pointer;
    transition: border-color .18s var(--sd-ease);
}

.sd-v2 .sd-tradeup__label:hover { border-color: var(--sd-ink); }

/* Apple's border/padding compensation: the border grows 1px, the padding loses 1px,
   so the tile never shifts on selection. */
.sd-v2 .sd-tradeup__input:checked + .sd-tradeup__label {
    border-width: 2px;
    border-color: var(--sd-blue);
    padding: 14px 16px;
}

.sd-v2 .sd-tradeup__input:focus-visible + .sd-tradeup__label {
    outline: 2px solid var(--sd-blue);
    outline-offset: 3px;
}

.sd-v2 .sd-tradeup__label-title {
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -.022em;
    line-height: 1.2353641176;
    color: var(--sd-ink);
}

.sd-v2 .sd-tradeup__label-sub {
    font-size: 12px;
    font-weight: 400;
    letter-spacing: -.01em;
    line-height: 1.3333733333;
    color: var(--sd-ink-2);
}

/* ---- drawer ---- */

.sd-v2 .sd-tradeup__drawer {
    margin-block-start: 4px;
    padding: 22px;
    border: 1px solid var(--sd-line);
    border-radius: var(--sd-radius-card);
    background: var(--sd-surface-2);
}

/* ---- one module per question ---- */

/* Two questions per row, filling left-to-right then wrapping: device type + brand, then model +
   capacity, then the condition questions two at a time. Modules are appended one at a time as
   each answer comes back, and grid auto-placement puts each new one in the next free cell. */
/* ONE MODULE PER ROW. Model, capacity and each condition question get the full width of the
   widget - they are sequential steps, and pairing two of them side by side reads as though they
   were alternatives rather than an order to work through. */
.sd-v2 .sd-tradeup__modules {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    row-gap: 24px;
    align-items: start;
}

/* Help text now sits UNDER its select rather than beside it - at half width there is no room for
   Apple's side-by-side pairing. min-inline-size:0 so a long option label cannot widen the track. */
.sd-v2 .sd-tradeup__module {
    display: flex;
    flex-direction: column;
    /* Compounds with the title's own bottom margin, so it stays small - the two together are the
       gap between a question and its answer control. */
    gap: 2px;
    min-inline-size: 0;
}

/* Apple pairs the dropdown with its help copy side by side. There is room for that now each
   module owns a full row, so the select takes the start half and the guidance the end half. */
@media (min-width: 768px) {
    .sd-v2 .sd-tradeup__module:not(.sd-tradeup__module--choice) {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        column-gap: 28px;
        align-items: start;
    }

    /* The title spans both columns so the select and its help start on the same line. */
    .sd-v2 .sd-tradeup__module:not(.sd-tradeup__module--choice) .sd-tradeup__module-title {
        grid-column: 1 / -1;
    }
}

.sd-v2 .sd-tradeup__module .sd-tradeup__field { max-inline-size: 420px; }

/* Help copy beside the select - backend-supplied, so it may run to a few paragraphs and a link. */
.sd-v2 .sd-tradeup__module-help {
    font-size: 12px;
    line-height: 1.5;
    letter-spacing: -.01em;
    color: var(--sd-ink-2);
}

.sd-v2 .sd-tradeup__module-help p { margin: 0 0 8px; }
.sd-v2 .sd-tradeup__module-help p:last-child { margin-block-end: 0; }
.sd-v2 .sd-tradeup__module-help a { color: var(--sd-blue); text-decoration: none; }
.sd-v2 .sd-tradeup__module-help a:hover { text-decoration: underline; }

.sd-visuallyhidden {
    position: absolute;
    inline-size: 1px; block-size: 1px;
    padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.sd-v2 .sd-tradeup__module-title {
    /* 8px + the module's 2px row-gap = 10px to the control. Was 16px (too loose, and the deleted
       42px reservation put ~37px under a one-line title); 4px closed it up too far. */
    margin: 0 0 8px;
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -.022em;
    line-height: 1.2353641176;
    color: var(--sd-ink);
}

/* A two-line min-block-size used to sit here, reserving height so that two selects sharing a row
   ("What are you trading in?" beside "Which brand?") lined up. Both of those steps are gone - the
   wizard opens straight on the model - so under a one-line title it was only ever ~21px of dead
   space between the question and its dropdown. */

.sd-v2 .sd-tradeup__module-help {
    font-size: 12px;
    font-weight: 400;
    letter-spacing: -.01em;
    line-height: 1.3333733333;
    color: var(--sd-ink-2);
    margin: 0;
}

/* ---- the select ----
   Native <select>, restyled. A custom listbox would have to reimplement keyboard
   handling, type-ahead and the mobile picker for no gain. */
.sd-v2 .sd-tradeup__field { position: relative; }

.sd-v2 .sd-tradeup__select {
    appearance: none;
    -webkit-appearance: none;
    inline-size: 100%;
    padding: 13px 44px 13px 16px;
    border: 1px solid var(--sd-ink-3);
    border-radius: var(--sd-radius-tile);
    background: var(--sd-surface);
    color: var(--sd-ink);
    font-family: var(--sd-font);
    font-size: 15px;
    font-weight: 400;
    letter-spacing: -.016em;
    line-height: 1.4;
    cursor: pointer;
}

.sd-v2 .sd-tradeup__select:hover { border-color: var(--sd-ink); }

.sd-v2 .sd-tradeup__select:focus-visible {
    outline: 2px solid var(--sd-blue);
    outline-offset: 2px;
}

/* Chevron drawn in CSS, mirrored for RTL by flipping which edge it sits on. */
.sd-v2 .sd-tradeup__field::after {
    content: "";
    position: absolute;
    inset-inline-end: 18px;
    inset-block-start: 50%;
    inline-size: 8px;
    block-size: 8px;
    margin-block-start: -6px;
    border-inline-end: 1.5px solid var(--sd-ink-2);
    border-block-end: 1.5px solid var(--sd-ink-2);
    transform: rotate(45deg);
    pointer-events: none;
}

/* ---- estimate ---- */

/* ---- condition questions: radio tiles -------------------------------------
   Apple's .rf-tradeupinline-question - a two-up grid of .form-selector-label
   tiles, LEFT aligned with a title and optional small print. Dropdowns are used
   only for the device dimensions above; the condition answers carry explanatory
   copy and need to be readable side by side. --------------------------------- */

.sd-v2 .sd-tradeup__module--choice { display: block; }

.sd-v2 .sd-tradeup__module-desc {
    margin: 0 0 12px;
    font-size: 12px;
    line-height: 1.45;
    letter-spacing: -.01em;
    color: var(--sd-ink-2);
    max-inline-size: 62ch;
}

.sd-v2 .sd-tradeup__module-intro { margin: 0 0 6px; font-weight: 500; color: var(--sd-ink); }

.sd-v2 .sd-tradeup__module-desc ul { margin: 0; padding: 0; list-style: none; }

.sd-v2 .sd-tradeup__module-desc li {
    position: relative;
    padding-inline-start: 15px;
    margin-block-end: 4px;
}

.sd-v2 .sd-tradeup__module-desc li::before {
    content: "";
    position: absolute;
    inset-inline-start: 3px;
    inset-block-start: 7px;
    inline-size: 4px;
    block-size: 4px;
    border-radius: 50%;
    background: var(--sd-ink-3);
}

.sd-v2 .sd-tradeup__choices {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}

/* Kept at two columns even on mobile: the labels are a single word, so stacking them wastes
   height and makes a binary choice look like a list. */

.sd-v2 .sd-tradeup__choice { position: relative; display: flex; }

/* Visually hidden but still focusable, so the label carries the styling and focus is visible. */
.sd-v2 .sd-tradeup__choice-input {
    position: absolute;
    opacity: 0;
    inline-size: 1px;
    block-size: 1px;
}

/* Bare "Yes" / "No" - the criteria live in the points above, so the tile stays short and two
   genuinely fit on a row. Centred, because a one-word label reads oddly left-aligned in a wide box. */
.sd-v2 .sd-tradeup__choice-label {
    display: flex;
    align-items: center;
    justify-content: center;
    inline-size: 100%;
    margin: 0;
    padding: 14px 17px;
    border: 1px solid var(--sd-ink-3);
    border-radius: var(--sd-radius-tile);
    background: var(--sd-surface);
    cursor: pointer;
    text-align: start;
    transition: border-color .18s var(--sd-ease);
}

.sd-v2 .sd-tradeup__choice-label:hover { border-color: var(--sd-ink); }

/* Border grows 1px, padding drops 1px - the tile never shifts on selection. */
.sd-v2 .sd-tradeup__choice-input:checked + .sd-tradeup__choice-label {
    border-width: 2px;
    border-color: var(--sd-blue);
    padding: 13px 16px;
}

.sd-v2 .sd-tradeup__choice-input:focus-visible + .sd-tradeup__choice-label {
    outline: 2px solid var(--sd-blue);
    outline-offset: 3px;
}

/* ---- condition tiles ----
   One word - the condition's name - and nothing else, so the name IS the tile and sits dead centre
   on both axes.

   Every declaration here is deliberate rather than defensive:

     flex-direction   the base tile is a row, but saying so means --condition cannot be broken by a
                      later change to the shared tile it borrows from
     justify-content  centres the name across the tile's width
     align-items      centres it down the tile's height
     text-align       centres the name's own lines, which matters the moment a localised label
                      wraps - "New" never will, "Reconditionne" in a narrow column can
     min-block-size   gives the tile a height to centre WITHIN. Without it the label hugs its one
                      line of text and vertical centring has nothing to do - the tile is exactly as
                      tall as the word. This is what makes the two tiles read as a matched pair
                      rather than as two words with boxes drawn round them.

   Scoped to --condition so the trade-in Yes/No tiles, which share the base class, are untouched. */
.sd-v2 .sd-tradeup__choices--condition .sd-tradeup__choice-label {
    flex-direction: row;
    justify-content: center;
    align-items: center;
    min-block-size: 56px;
    padding: 12px 16px;
    text-align: center;
}

/* Selected state keeps the tile the same size - border grows 1px, padding drops 1px - so the name
   does not shift under the pointer. Restated because the padding above overrode the base rule's. */
.sd-v2 .sd-tradeup__choices--condition .sd-tradeup__choice-input:checked + .sd-tradeup__choice-label {
    padding: 11px 15px;
}

/* Full width so text-align has the whole tile to centre in, not just the span's own shrink-to-fit
   box. Belt and braces with justify-content above - either alone centres a single line, but a
   wrapped label needs both. */
.sd-v2 .sd-tradeup__choices--condition .sd-tradeup__choice-title {
    inline-size: 100%;
    text-align: center;
}

/* Sold out. The condition tile carries its name and nothing else, so the old "Out of stock" line
   inside it is gone and the state has to be drawn instead of written. Struck through as well as
   dimmed: dimming alone reads as "not selected" on a tile that is also unselected. */
.sd-v2 .sd-tradeup__choice-input:disabled + .sd-tradeup__choice-label {
    cursor: not-allowed;
    opacity: .45;
    border-style: dashed;
}

.sd-v2 .sd-tradeup__choice-input:disabled + .sd-tradeup__choice-label:hover {
    border-color: var(--sd-ink-3);
}

.sd-v2 .sd-tradeup__choice-input:disabled + .sd-tradeup__choice-label .sd-tradeup__choice-title {
    text-decoration: line-through;
}

/* Graded tiles ("Good" / "Damaged") carry their explanation inside, so they align to the start
   and stack title over description - Apple's rf-dimension-text-left. */
.sd-v2 .sd-tradeup__choices--rich .sd-tradeup__choice-label {
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 6px;
    padding: 16px 18px;
    text-align: start;
}

.sd-v2 .sd-tradeup__choices--rich .sd-tradeup__choice-input:checked + .sd-tradeup__choice-label {
    padding: 15px 17px;
}

.sd-v2 .sd-tradeup__choice-desc {
    font-size: 12px;
    font-weight: 400;
    letter-spacing: -.01em;
    line-height: 1.3333733333;
    color: var(--sd-ink-2);
}

.sd-v2 .sd-tradeup__choice-title {
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -.022em;
    line-height: 1.2353641176;
    color: var(--sd-ink);
}


/* "Done" under the modules - closes the editor and puts the existing result back. Only rendered
   while re-editing an answered trade-in, so it never appears on the first run through. */
.sd-v2 .sd-tradeup__collapse {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    inline-size: 100%;
    margin-block-start: 18px;
    padding-block-start: 14px;
    padding-inline: 0;
    border: 0;
    border-block-start: 1px solid var(--sd-line);
    background: transparent;
    color: var(--sd-blue);
    font-family: var(--sd-font);
    font-size: 14px;
    letter-spacing: -.016em;
    cursor: pointer;
}

/* Chevron pointing up - the control collapses the editor. */
.sd-v2 .sd-tradeup__collapse::after {
    content: "";
    inline-size: 8px;
    block-size: 8px;
    border: solid currentColor;
    border-width: 2px 2px 0 0;
    transform: rotate(-45deg);
    margin-block-start: 3px;
}

.sd-v2 .sd-tradeup__collapse:hover { text-decoration: underline; }
.sd-v2 .sd-tradeup__collapse:focus-visible { outline: 2px solid var(--sd-blue); outline-offset: 3px; }

/* ---- outcome panel: quote or recycle --------------------------------------
   Apple's .rf-tradeupinline-quote - a tick, the headline, the value, and an Edit
   button on the end edge. Replaces the question modules once there is a result.
   --------------------------------------------------------------------------- */

.sd-v2 .sd-tradeup__estimate { margin-block-start: 18px; }

.sd-v2 .sd-tradeup__quote {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 18px 20px;
    border-radius: var(--sd-radius-tile);
    background: var(--sd-surface);
}

.sd-v2 .sd-tradeup__quote-icon {
    flex: none;
    inline-size: 22px;
    block-size: 22px;
    margin-block-start: 1px;
    border-radius: 50%;
    background: var(--sd-green);
    position: relative;
}

/* tick */
.sd-v2 .sd-tradeup__quote-icon--ok::after {
    content: "";
    position: absolute;
    inset-inline-start: 7px;
    inset-block-start: 4px;
    inline-size: 6px;
    block-size: 11px;
    border: solid #fff;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}

/* recycle: neutral, not an error - the device is still useful */
.sd-v2 .sd-tradeup__quote-icon--recycle { background: var(--sd-ink-3); }

.sd-v2 .sd-tradeup__quote-icon--recycle::after {
    content: "";
    position: absolute;
    inset: 5px;
    border: 2px solid #fff;
    border-radius: 50%;
    border-block-start-color: transparent;
}

.sd-v2 .sd-tradeup__quote-body { flex: 1 1 auto; min-inline-size: 0; }

.sd-v2 .sd-tradeup__quote-label {
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -.022em;
    line-height: 1.2353641176;
    color: var(--sd-ink);
}

.sd-v2 .sd-tradeup__quote-priceheader {
    margin-block-start: 6px;
    font-size: 13px;
    letter-spacing: -.016em;
    line-height: 1.45;
    color: var(--sd-ink-2);
}

.sd-v2 .sd-tradeup__quote-price {
    margin-block-start: 2px;
    font-size: 24px;
    font-weight: 600;
    letter-spacing: .009em;
    line-height: 1.1666666667;
    color: var(--sd-ink);
}

.sd-v2 .sd-tradeup__quote-edit {
    flex: none;
    border: 0;
    padding: 0;
    background: transparent;
    color: var(--sd-blue);
    font-family: var(--sd-font);
    font-size: 14px;
    letter-spacing: -.016em;
    cursor: pointer;
}

.sd-v2 .sd-tradeup__quote-edit:hover { text-decoration: underline; }

@media (max-width: 575.98px) {
    .sd-v2 .sd-tradeup__quote { padding: 15px 16px; gap: 11px; }
    .sd-v2 .sd-tradeup__quote-label { font-size: 15px; }
    .sd-v2 .sd-tradeup__quote-price { font-size: 21px; letter-spacing: .011em; }
}

/* ---- "How does trade-in work?" card (Apple's .rc-decisionsection) ---- */

/* Same box as an option tile - same height, padding and radius - so it lines up with "No trade-in"
   rather than sitting proud of it. Content is centred for the same reason the tiles centre theirs. */
.sd-v2 .sd-tradeup__info {
    display: flex;
    flex-direction: column;
    justify-content: center;
    block-size: var(--sd-tradeup-tile-h);
    padding: 15px 17px;
    border: 1px solid var(--sd-line);
    border-radius: var(--sd-radius-tile);
    background: var(--sd-surface);
    overflow: hidden;
}

.sd-v2 .sd-tradeup__info-title {
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -.016em;
    line-height: 1.3;
    color: var(--sd-ink);
}

/* Clamped so a long translation cannot push the card past the shared tile height and break the
   alignment the height exists to create. */
.sd-v2 .sd-tradeup__info-desc {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin-block-start: 6px;
    font-size: 13px;
    font-weight: 400;
    letter-spacing: -.01em;
    line-height: 1.35;
    color: var(--sd-ink-2);
}


/* =============================================================================
   Legacy payment-plans block
   Superseded by "Choose how to pay". The markup MUST stay in the DOM - detail.js
   drives #paymentPlans / .payment-plans / .plan-button / .tb / setActivePlan and
   repaints it from getPaymentPlans2() on every variant change - so it is hidden
   rather than removed. !important beats the .d-none toggling detail.js does.
   ============================================================================= */

#paymentPlans.sd-legacy-plans { display: none !important; }

/* The standalone Buy button under the colour swatches (rendered when the listing is not
   installment-eligible). Superseded by the Apply button in the order summary, but detail.js
   binds .buyDevice / #buyDevice for the full-payment checkout path, so it is hidden, not removed. */
.sd-legacy-buy { display: none !important; }

/* Its container goes too. Everything inside is hidden now, but detail.css:170 gives .div_btns
   `border-top: 2px solid #EEEEEE; margin-top: 21px; padding-top: 20px`, so an empty one still
   drew a rule and a gap directly under the capacity list. Only the buy-case container is hidden -
   the "interested" and "reserved" cases share the class .div_btns but still show content. */
#buy_device .div_btns.sd-legacy-btns { display: none !important; }

/* Location + map: the map element must stay in the DOM because detail.js initMapD() calls
   new google.maps.Map(document.getElementById("map"), ...) with no null guard. */
.sd-map-hidden { display: none !important; }

/* =============================================================================
   Placement + responsive
   ============================================================================= */

/* Full-width band under the gallery + configuration row. Two columns on desktop:
   payment + trade-in on the left, the order summary parked on the right, which is what
   fills the space the old single-column placement left empty. */

/* No top rule. It spanned the whole container, so it drew a line under the gallery AND under the
   colour swatches beside it - reading as two stray dividers rather than one section break. The
   spacing separates the band from the row above on its own. */
.sd-v2--band {
    margin-block-start: 8px;
    padding-block-start: 40px;
    /* ---- ON the page's grid, with NO gutter correction ----
       This band renders inside a second, nested Bootstrap .container (detail.cshtml wraps it in
       `section.section-box > .container`). That would normally add a 12px gutter - but detail.css
       zeroes it outright:

           .shop-template .container { max-width: 100% !important; padding: 0 !important; }

       So the inner container IS the page frame, and the band needs no correction to sit on it. The
       gallery row beside it nets out to the same edges by a different route (.row's -12px cancelled
       by .col's +12px), which is why the two line up.

       A -12px margin was tried here to cancel a gutter that turns out not to exist. It pushed the
       band 12px OUTSIDE the frame instead - invisible-ish on desktop, but on a phone the page's own
       12px body gutter is all there is, so the band landed flush against the viewport edge. */
}

/* Single full-width column: trade-in, then payment, then the summary. The summary used to sit
   in a sticky right-hand rail; Apple's rf-bfe-summary is a full-width band above the FAQ, and
   that is what this now is. The sticky rail (and its --sd-summary-top offset) is gone with it. */
.sd-v2 .sd-band { display: block; }

/* ---- no white strip under the summary band ---------------------------------
   The summary's grey band is full bleed, so anything left below it reads as a white gap between
   the page and the site footer rather than as breathing room. Three sources, each killed only
   when there is genuinely nothing left to separate the band FROM:

     1. the summary's own 40px bottom margin, when no FAQ follows it inside the band
     2. the FAQ's bottom margin, when the FAQ is the last thing in the band
     3. #buy_device .section2's 45px bottom padding, when the band is the last section on the
        page - flagged server-side, since the sections that could follow are Razor-conditional
        and CSS cannot see whether they rendered (see sdBandIsLast in detail.cshtml)

   :last-child does the work for 1 and 2: _Faq.cshtml renders NOTHING when the listing has no FAQ,
   so .sd-band really is the last child in that case. Both rules therefore stop applying the
   moment a FAQ exists, and the gap comes back where it is doing a job. */
.sd-v2--band > .sd-band:last-child > #sdSummarySection.sd-section { margin-block-end: 0; }
.sd-v2--band > .sd-faq:last-child { margin-block-end: 0; }

#buy_device .section2.sd-flush-bottom { padding-block-end: 0; }

/* ---- the last two sources of white under the summary -----------------------
   With the margins above zeroed, a gap survived between the grey band and the site footer that no
   margin or padding accounted for. Both causes were line boxes, not spacing:

   1. style.css sets `.section-box { display: inline-block; width: 100% }`. A full-width inline-block
      lays out like a block, but it is still INLINE-LEVEL - it sits on its line box's baseline, and
      the space reserved below that baseline for descenders is real, unremovable height under every
      section on the page. `display: block` is the same layout without the line box.

   2. The section after the band contains only hidden content (see sd-empty-section in
      detail.cshtml). Its own box collapsed to zero, but as an inline-block it still generated a
      line box in .section2 - roughly a line-height of white from an element with nothing in it. */
#buy_device .section-box { display: block; }

#buy_device .sd-empty-section { display: none; }

/* ---- the page's side gutter on tablet and phone ----------------------------
   .section2 is the frame EVERY section on this page sits on - breadcrumb, gallery, configuration
   column, and the whole V2 band. It carries no inline padding of its own, so the only thing holding
   content off the screen edge is #buy_device.container's 12px, which is a desktop-scale gutter
   being asked to do a phone's job. At 375px that put the cards, the tiles and the summary 12px from
   the glass, which reads as touching.

   Widened HERE, on the shared frame, rather than per section: every section then moves together and
   they cannot drift out of line with each other, which is the whole point of the frame.
   10px + the container's 12px = 22px, Apple's own phone floor, and it leaves 331px of content at
   375px - within a pixel or two of the 328px their summary image is capped at.

   padding-inline, not the padding shorthand: .sd-flush-bottom above sets padding-block-end and the
   base rule in detail.css sets the block padding, and neither should be disturbed.

   The summary's grey is UNAFFECTED and stays edge to edge: it is painted by
   #sdSummarySection::before at 100vw, which is measured from the viewport and not from this box.
   That is exactly the split asked for - full-width background, inset content. */
@media (max-width: 991.98px) {
    #buy_device .section2 { padding-inline: 10px; }
}

/* =============================================================================
   position:sticky blocker  -  READ BEFORE CHANGING
   -----------------------------------------------------------------------------
   css/custome.css sets:

       #buy_device { overflow: hidden; position: relative; }

   #buy_device wraps this whole page, and an ancestor whose overflow is anything
   other than `visible` becomes the scroll container that sticky positions
   against. That container never scrolls itself, so every sticky descendant has
   zero travel and appears completely dead - which is exactly what happened to
   the order summary.

   `overflow-x: clip` + `overflow-y: visible` is the one combination that fixes
   it without side effects: the horizontal clipping the original rule was there
   for is kept, while the vertical axis stays truly visible and creates no scroll
   container. (Plain `visible` on one axis with `hidden` on the other is NOT an
   option - the spec forces the `visible` side to compute to `auto`, which would
   reintroduce the blocker and add a stray scrollbar. `clip` is the exception the
   spec allows to pair with `visible`.)

   This stylesheet loads at _Layout line 58, after custome.css at line 50, so an
   equal-specificity override is enough - no !important needed.
   ============================================================================= */

/* NO CLIPPING ON EITHER AXIS.
   -----------------------------------------------------------------------------
   custome.css:66 sets a blanket `#buy_device { overflow: hidden; position: relative }`
   with no stated reason. That was first narrowed to `overflow-x: clip; overflow-y: visible`
   to unblock sticky (see the note above), and the remaining horizontal clip then became
   the reason the order summary's grey band would not reach the screen edges:
   #sdSummarySection pushes itself out with `width:100vw` + negative inline margins, and a
   clipping ancestor cut it straight back to the container.

   `overflow-clip-margin: 50vw` was tried here first and did not take, so the clip goes
   entirely. Nothing on this page is known to depend on it - the original rule was a blanket
   hidden, not a considered one - and removing it is strictly better for sticky too: with
   neither axis clipped this element is not a scroll container at all, which is precisely
   what position:sticky wants.

   IF a horizontal scrollbar ever appears on this page, the cause is something inside
   overflowing that the blanket hidden used to mask. The fix is to find and contain THAT
   element, not to reinstate the clip here - doing so silently breaks the summary band again. */
#buy_device {
    overflow: visible;
    position: relative;
}

/* Scrollbar guard for the full-bleed band - now specifically for the grey itself, which is the
   only part of the summary still measured in vw (#sdSummarySection::before).
   100vw is the viewport INCLUDING the vertical scrollbar, so a 100vw band is ~15px wider than
   the document and overhangs the right edge. While #buy_device clipped, that was invisible; now
   that it does not, the overhang would show up as a horizontal scrollbar on every details page.

   Clipping at the ROOT is the right place for it: the root's clip rectangle IS the viewport, so
   the band still reaches both visible edges and only the scrollbar-width excess is cut.
   `clip` rather than `hidden` on purpose - hidden here would make <html> a scroll container and
   break position:sticky, which is the same trap documented for #buy_device above. */
html {
    overflow-x: clip;
}


/* =============================================================================
   Hero row - sticky gallery, page-scrolled configuration
   -----------------------------------------------------------------------------
   Apple's behaviour, and the reason this is NOT an inner scroll container:

   The GALLERY sticks. The configuration column beside it is ordinary page
   content that scrolls past it, and when the row ends the gallery releases and
   the page carries on to Trade in.

   An earlier attempt capped the configuration column's height and gave it
   overflow-y:auto. That was wrong on two counts: the wheel gesture felt like a
   nested pane rather than a page, and dragging its scrollbar bypassed the
   sequencing entirely. Sticky has neither problem - there is only ever ONE
   scroller (the page), so the scroll always feels native.

   align-self:flex-start is REQUIRED: Bootstrap's .row is a flexbox and stretches
   its children to full height by default, which silently makes sticky a no-op.

   --sd-pinned-top is the height of whatever chrome is fixed to the top RIGHT
   NOW: the site header at first, then the product bar once it drops in and
   withdraws the header. Offsetting from it is what stops the image sliding
   under either one. detail-configurator.js keeps it current.
   ============================================================================= */

/* ---- gallery width -------------------------------------------------------
   The image is capped by style.css:8312  .product-image-slider { max-width: 500px }.

   DO NOT reduce .galleries' 105px padding-inline-start to gain room. That gutter is
   reserved for the thumbnail rail, which style.css:8268 positions
   `position:absolute; left:0; width:94px` INSIDE the gallery. Removing the padding
   drops the rail straight on top of the main image - that is exactly what happened
   when it was tried. The extra width comes from the column split instead
   (col-lg-8 / col-lg-4 in detail.cshtml).

   min(...,100%) is the guard that matters: a fixed 620px overflows the column on
   narrower viewports and spills over the configuration column beside it.

   Scoped to #buy_device .sd-gallery-col so the shop, home and sell galleries keep
   their own sizing. Slick measures the container when it initialises, and these
   rules land before that, so the slide widths come out right without a refresh.
   -------------------------------------------------------------------------- */

@media (min-width: 992px) {
    #buy_device .sd-gallery-col .product-image-slider {
        max-inline-size: min(620px, 100%);
    }
}

@media (min-width: 992px) {
    #buy_device .sd-gallery-col {
        position: sticky;

        /* --sd-gallery-top is the column's OWN resting position, measured once per layout by
           detail-configurator.js. Because the offset already equals where the column sits at
           scroll 0, sticky engages immediately and the image never moves at all - it holds while
           the configuration column scrolls past it, and releases when the row ends.

           Using --sd-pinned-top here instead (header/bar height) is what made the image drift:
           the column started BELOW that offset, so it scrolled up to meet it first, then jumped
           again when the product bar changed the value mid-scroll. This one never changes while
           scrolling. */
        inset-block-start: var(--sd-gallery-top, 88px);
        align-self: flex-start;

        /* A gallery taller than the space under the pinned chrome would be pinned with its lower
           half permanently off-screen. Bound it to what is actually visible and let the image
           scale down inside, so the whole thing stays on screen instead of being cropped. */
        max-block-size: calc(100vh - var(--sd-pinned-top, 72px) - 32px);
        display: flex;
        flex-direction: column;
    }

    #buy_device .sd-gallery-col .gallery-image {
        min-block-size: 0;          /* lets the flex child actually shrink */
        display: flex;
        flex-direction: column;
    }

    #buy_device .sd-gallery-col .product-image-slider img,
    #buy_device .sd-gallery-col .detail-gallery img {
        /* Reserve for the fav/badge row above and the thumbnail strip below. Loosened from 190px
           so the extra width above is not immediately cancelled out by the height cap - a
           contained image scales on whichever axis binds first. */
        max-block-size: calc(100vh - var(--sd-pinned-top, 72px) - 150px);
        object-fit: contain;
        inline-size: auto;
        margin-inline: auto;
    }
}

@media (max-width: 991.98px) {
    .sd-v2 { margin-block-start: 24px; }
    .sd-v2 .sd-section { margin-block-end: 32px; }

    /* ---- the band tightens up to the configuration above it ----
       Stacked, "Choose how to pay" follows the capacity tiles directly, and the two were being held
       52px apart: .sd-v2's 24px margin above (this band is also a .sd-v2, so it was picking that up
       and overriding its own 8px) plus a 28px top padding. On desktop that distance separates a
       full-width band from a two-column row above it and is doing real work; stacked, both are just
       one column after another and it read as the page having lost its place.

       Restated AFTER .sd-v2 above deliberately - same specificity, so source order is what makes
       the 8px stick rather than the 24px. */
    .sd-v2--band {
        margin-block-start: 8px;
        padding-block-start: 16px;
    }
}

@media (max-width: 575.98px) {
    .sd-v2 .sd-section__title { font-size: 21px; letter-spacing: .011em; line-height: 1.1904761905; }
    .sd-v2 .sd-section__hint { font-size: 13px; margin-block-end: 14px; }

    /* ---- ONE OPTION PER ROW ----
       Three abreast came to about 105px per card at this width, and every part of the card was
       paying for it: "/mo." had to drop onto its own line, the "Most popular" pill onto a third,
       and the figure down to 15px in a box too narrow to say what it meant.

       One per row buys that width back, and the card is reshaped from a centred stack into a ROW to
       spend it - term on the leading edge, monthly on the trailing edge. That is deliberately the
       same shape as the capacity tiles directly above it, so the two controls the customer moves
       between read as one family rather than two designs.

       Both modifiers, so a two-term listing stacks exactly the way a three-term one does. */
    .sd-v2 .sd-cards--3,
    .sd-v2 .sd-cards--2 { grid-template-columns: minmax(0, 1fr); gap: 8px; }

    .sd-v2 .sd-card {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
        text-align: start;
        min-block-size: 64px;
        padding: 14px 16px;
    }
    /* -1px each side absorbs the selected state's second border pixel, so the row never resizes. */
    .sd-v2 .sd-card.is-selected { padding: 13px 15px; }

    /* min-inline-size:0 lets the term give way first; the price is the figure being compared, so it
       is the one that must never wrap or shrink. */
    .sd-v2 .sd-card__label { min-inline-size: 0; font-size: 15px; }
    .sd-v2 .sd-monthly { flex: none; margin-block-start: 0; font-size: 15px; text-align: end; }

    /* The pill and the "/mo." suffix are deliberately NOT overridden here. Both were forced onto
       their own line only because three columns left no room; the row has room, so they go back to
       sitting inline exactly as they do on desktop, which the base rules already say. */

    .sd-v2 .sd-mode-tabs { inline-size: 100%; }
    .sd-v2 .sd-mode-tab { flex: 1; padding-inline: 10px; }

    .sd-v2 .sd-tradein { padding: 18px; }
    .sd-v2 .sd-tradein__head { flex-direction: column; align-items: stretch; gap: 14px; }
    .sd-v2 .sd-tradein__head .sd-btn { inline-size: 100%; }

    .sd-v2 .sd-summary { padding: 22px 18px; }
    .sd-v2 .sd-summary__box { padding: 22px 20px 20px; }
    /* The headline's own sizes are NOT set here. Every width this block covers is also covered by
       the max-width:767.98px block near the foot of this file, and that one is later in source at
       the same specificity - so anything stated here for the headline is dead on arrival. It owns
       the headline at every width below 768px; see .sd-summary__intro there. */

    /* The figure scales with the box, and its slot with it - a 104px floor around a 36px number is
       dead space at this width. */
    .sd-v2 .sd-summary__price-amount { font-size: 36px; letter-spacing: -.019em; }
    .sd-v2 .sd-summary__figure { min-block-size: 92px; }

    .sd-stickybar__header .sd-stickybar__container { padding-block: 9px; gap: 12px; }
    .sd-stickybar__platter { padding-block: 6px; gap: 6px; }
    .sd-stickybar__cell { padding: 3px 10px; font-size: 11px; }
    .sd-stickybar__title { font-size: 14px; }
    .sd-stickybar__price { font-size: 12px; }
    .sd-stickybar .sd-btn { padding: 7px 14px; font-size: 13px; }

    .sd-v2 .sd-tradeup__title { font-size: 21px; letter-spacing: .011em; }
    .sd-v2 .sd-tradeup__drawer { padding: 16px; }
}

/* The 359.98px breakpoint that used to sit here dropped .sd-cards--3 from three columns to two.
   It is gone with the three-column layout itself: the cards are one per row from 575.98px down, and
   this rule being LATER in the file would have quietly put the very smallest screens back to two
   cramped columns - the one width least able to afford them. */

/* =============================================================================
   Breadcrumb — MOVED OUT of this file.

   It started here scoped to #buy_device, on the reasoning that the other pages
   rendering _Breadcrumb should not shift because this one was tidied. They then
   needed to match, so keeping it scoped would have meant either a growing list
   of page selectors or a copy per page.

   It now lives in assets/css/breadcrumb.css, unscoped, loaded from
   _header.cshtml so every page that can render the trail styles it identically.
   Nothing detail-specific was lost in the move — there was none.

   ONE thing is detail-specific and stays here: how the trail behaves when it does
   not fit. See below.
   ============================================================================= */

/* ---- the trail WRAPS on this page, it does not scroll -----------------------
   breadcrumb.css keeps the trail to a single line below 768px, scrolls the overflow horizontally,
   and ellipsises the current item. That is the right call for the trails it was written against -
   two or three short crumbs on Contact Us, FAQ, Terms.

   This page's trail is the longest on the site and got longer still: Home > Shop > Category >
   the full product name. Held to one line, most of it sits off-screen behind a horizontal gesture
   with nothing to advertise it, and the product name - the crumb identifying where you actually
   are - is the one that gets cut.

   So here it wraps. It costs a line or two at the top of the page and every crumb stays readable.
   row-gap because the wrapped lines need separating; the 2px inline gap does not change.

   SCOPED to #buy_device deliberately: the shared behaviour is still correct everywhere else, and
   the id beats breadcrumb.css's plain class regardless of which file loads last (breadcrumb.css
   comes from _Header, in the body, so it loads AFTER this file - specificity is doing the work
   here, not source order). */
@media (max-width: 767.98px) {
    #buy_device .page_title {
        flex-wrap: wrap;
        overflow-x: visible;
        row-gap: 4px;
    }

    /* The product name can now use those extra lines instead of being truncated into one. */
    #buy_device .page_title .page_title__current {
        overflow: visible;
        text-overflow: clip;
        white-space: normal;
    }
}

/* =============================================================================
   Storage + colour selectors  (LEGACY MARKUP, restyled in place)
   -----------------------------------------------------------------------------
   These chips are rendered by detail.cshtml and driven by detail.js
   (.gb.storage[data-value], #relatedItemColor .phone-color-box, the out-of-stock
   SVG cross, the "n/a" hiding). None of that is touched - this is presentation
   only, scoped to #buy_device so it cannot leak to the shop or home pages.

   Follows Apple's capacity picker: full-width stacked ROWS, label on the start
   edge, price/meta on the end edge (their .rf-po-bfe-...-right-rail variant uses
   flex-flow:row wrap + justify-content:space-between), 12px radius, 1px #86868b
   border, and the 2px-border / -1px-padding compensation when selected.
   ============================================================================= */

/* =============================================================================
   Sticky gallery
   -----------------------------------------------------------------------------
   Apple's buy page pins the product image while the configuration column beside
   it scrolls, then lets the whole page move on once that column runs out.

   No JS and no end coordinate needed: a sticky element is bounded by its
   containing block, which here is its own .col-lg-6. Bootstrap's .row is a flex
   container with align-items: stretch, so that column is as tall as the taller
   one beside it - the configuration column - and the image therefore releases
   precisely when the configuration runs out.

   Two things this depends on, both true today, but worth knowing if the gallery
   ever stops sticking:
     - no ancestor between .row and .gallery-image may set overflow to anything
       but visible; any value creates a new scroll container and sticky silently
       dies against it
     - .row must keep align-items: stretch, or the column collapses to the height
       of the image and there is nowhere left to travel
   ============================================================================= */

@media (min-width: 992px) {
    #buy_device .gallery-image {
        position: sticky;
        /* Parks under whatever is pinned at the top. --sd-pinned-top is the live height of the
           site header, or of the product bar once it has taken over. (--sd-summary-top was the old
           name from when the summary was a sticky rail; that rail is gone.) */
        inset-block-start: calc(var(--sd-pinned-top, 72px) + 16px);
    }
}

/* Colour above capacity.
   Reordered in CSS rather than in the markup: detail.cshtml renders the capacity chips first and
   detail.js binds both groups plus the "select the first available storage" bootstrap in that DOM
   order. Flipping the source would risk that; `order` changes only what the eye sees. */
#buy_device .deviceRelatedItemsContainer {
    display: flex;
    flex-direction: column;
}

#buy_device .deviceRelatedItemsContainer > #relatedItemColor { order: 1; }
#buy_device .deviceRelatedItemsContainer > .choose_right { order: 2; }

#buy_device .deviceRelatedItemsContainer {
    --sd-ink: #1d1d1f;
    --sd-ink-2: #6e6e73;
    --sd-ink-3: #86868b;
    --sd-line: #d2d2d7;
    --sd-blue: #0071e3;
    --sd-ease: cubic-bezier(.4, 0, .6, 1);
    font-family: "SF Pro Text", "SF Pro Display", -apple-system, BlinkMacSystemFont,
                 "Helvetica Neue", Helvetica, Arial, sans-serif;
}

#buy_device .deviceRelatedItemsContainer .choose_text_title {
    font-size: 17px;
    /* 700, matching the .fw-bold value that sits after the dash - "Color - Space Black" reads as one
       bold line with the label and the answer at the same weight, and only the unanswered prompt
       (lighter grey, same weight) marked out by colour. */
    font-weight: 700;
    letter-spacing: -.022em;
    line-height: 1.2353641176;
    color: var(--sd-ink);
    margin-block-end: 12px;
}

/* Capacity heading value slot
   -----------------------------------------------------------------------------
   The chosen capacity and the "nothing chosen yet" padlock occupy the SAME box,
   so selecting a capacity swaps the contents without the heading changing height
   and pushing the tiles below it. The slot - not either child - owns the size:
   whichever one is showing, the line measures the same.

   Literal fallbacks on every custom property: this block is legacy markup living
   outside .sd-v2, same as the step-gate rules further down. */
#buy_device .deviceRelatedItemsContainer .choose_text_title .sd-value-slot {
    display: inline-flex;
    align-items: center;
    justify-content: flex-start;
    /* A floor that clears BOTH occupants: the 17px value line (~21px) and the 13px prompt text.
       The slot holds it whichever one is showing, so answering the question cannot change the
       heading's height. Keep it at or above the taller of the two. */
    min-block-size: 24px;
    vertical-align: middle;
}

/* Both of these are RECORDS, not display - hidden unconditionally, so it does not matter what
   detail.js has toggled on them.

   Hidden, NOT emptied and NOT removed: detail-configurator.js readLegacySelection() reads their
   text to resolve the current selection, and those values feed the order summary's specs row and
   the sticky-bar chips. Clearing them would blank both surfaces. display:none does not affect
   textContent, so the reads keep working.

   #storageNameContainer  the capacity heading asks its question in place of reporting the answer,
                          so its value has nowhere to show
   #colorNameContainer    the colour heading DOES report its answer, but through #colorValueLabel -
                          a separate element, because that one also shows merely HOVERED colours and
                          a hovered name must never reach the summary or the sticky bar

   detail.js still writes into both and still toggles .is-hidden / .is-visible; those classes are
   inert. Left in place so restoring either value in situ is a CSS change alone. */
#buy_device .deviceRelatedItemsContainer .sd-value-slot #storageNameContainer,
#buy_device .deviceRelatedItemsContainer .sd-value-slot #colorNameContainer {
    display: none;
}

/* The instruction above a variant heading - "Pick your favorite color".
   A CAPTION, not a heading and not the .sd-step__hint padlock chip: it tells the customer what to
   do with the swatches below, and carries no background, padding or icon.

   SIZED WITH the heading, not under it: the "Color - ..." line below is a label reporting a value,
   so this is the line that actually asks the customer for something and it carries the same 17px.
   What separates the two is weight and colour - 500 in grey here against 700 in ink below - rather
   than one being visibly smaller than the other.

   --sd-ink-2, the DARKER of the two greys: at this size the line is meant to be read rather than
   skimmed past, and --sd-ink-3 washes out. */
#buy_device .deviceRelatedItemsContainer .sd-axis-prompt {
    margin: 0 0 6px;
    font-size: 17px;
    font-weight: 500;
    line-height: 1.2353641176;
    letter-spacing: -.022em;
    color: var(--sd-ink-2, #6e6e73);
}

/* Stands in for the capacity VALUE while none is chosen - "How much space do you
   need?", or the screen-size / generic wording on other categories. The server
   picks which; see capacityAxisPrompt in detail.cshtml.

   Deliberately NOT a padlock, and deliberately NOT a chip. .sd-step__hint means
   "this step is locked, answer the one above first" and gets a grey pill to say
   so; this is only a question the heading is asking, so it renders as plain
   text - no background, no padding, no icon.

   Set in the SAME type as the "Storage - " label it continues - it reads as one
   sentence with the heading, so a smaller size made it look like a footnote that
   had drifted up. Inherited rather than restated at 17px so it tracks the label
   through any future breakpoint change instead of silently falling out of step.

   Weight 700 matches the .fw-bold on the value it stands in for, so answering the
   question swaps the text without the line changing weight - only the colour
   changes, grey for the question, brand colour for the answer.

   --sd-ink-3, the LIGHTER of the two greys, not --sd-ink-2: the label beside it is
   now bold ink, so at the darker grey the question competed with it. Same grey as
   .sd-section__title-sub, so every unanswered prompt on the page matches. */
/* ALWAYS shown - it is the slot's only occupant now that the value is hidden above, so there is
   nothing left to toggle against and no state in which the heading should trail off after its
   dash. The .is-visible class detail.js still adds is therefore redundant rather than required. */
#buy_device .sd-value-prompt {
    display: inline-flex;
    align-items: center;
    color: var(--sd-ink-3, #86868b);
    font-size: inherit;
    line-height: inherit;
    letter-spacing: inherit;
    font-weight: 700;
    white-space: nowrap;
    vertical-align: middle;
}

/* ---- capacity rows ---- */

/* ONE capacity per row. Each row carries a label AND a "From $45.83/mo. for 24 months" figure,
   which two columns cramped; full-width rows also match Apple's capacity picker.
   minmax(0, 1fr) rather than a bare 1fr so a long price line shrinks the tile instead of blowing
   the track out past the grid. */
#buy_device .deviceRelatedItemsContainer .gbs {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
    /* Capacity is the last thing in this container, so this is the gap before the price block.
       Trimmed from 28px now the empty .div_btns that used to sit between them is gone. */
    margin-block-end: 4px;
}

/* Grid rather than flex: with a long price line on the end edge, flex children refuse to shrink
   below their content and the row overflows its card. minmax(0, …) lets both columns actually
   give way, so long capacity labels and long price lines both stay inside the border. */
#buy_device .deviceRelatedItemsContainer .gb.storage {
    position: relative;
    display: grid;
    /* Capacity on the start edge, the price on the end edge - SIDE BY SIDE, not stacked.
       minmax(0, …) on both tracks is what keeps them inside the tile: neither column can refuse
       to shrink. */
    grid-template-columns: minmax(0, auto) minmax(0, 1fr);
    /* BOTH are needed: align-items centres each cell inside its row, align-content centres the row
       block itself inside the tile. Without the second, the row sits at the top of the min-height
       box and all the slack lands at the bottom - which is what made the top padding look smaller. */
    align-items: center;
    align-content: center;
    column-gap: 12px;
    row-gap: 4px;
    inline-size: 100%;
    /* A FLOOR, not a height. The tile is usually one label beside one price line, but that line can
       wrap on a narrow card and a lease line can join it, so the box grows to its content rather
       than every tile paying for the tallest case. */
    min-block-size: 76px;
    margin: 0;
    /* Trimmed from 20px/22px: 12px of vertical padding came off every tile, tall ones included. */
    padding: 14px 20px;
    border: 1px solid var(--sd-ink-3);
    border-radius: 12px;
    background: #fff;
    color: var(--sd-ink);
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -.022em;
    line-height: 1.2353641176;
    text-align: start;
    cursor: pointer;
    transition: border-color .18s var(--sd-ease);
}

#buy_device .deviceRelatedItemsContainer .gb.storage:hover:not(.out-of-stock) {
    border-color: var(--sd-ink);
}

#buy_device .deviceRelatedItemsContainer .gb.storage.selected {
    border-width: 2px;
    border-color: var(--sd-blue);
    padding: 13px 19px;   /* compensates the extra border - the row never shifts */
}

#buy_device .deviceRelatedItemsContainer .gb.storage.out-of-stock {
    background: #00000003;
    border-color: #86868b6b;
    color: var(--sd-ink-2);
    cursor: not-allowed;
}

/* Capacity on the start edge, price on the end edge - the two grid columns declared above. */
#buy_device .deviceRelatedItemsContainer .gb.storage .sd-storage__label {
    grid-column: 1;
    min-inline-size: 0;
    max-inline-size: 100%;
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -.022em;
    line-height: 1.2353641176;
    color: inherit;
    overflow-wrap: break-word;
}

/* Price lines stacked on the END edge, right-aligned against the capacity label. */
#buy_device .deviceRelatedItemsContainer .gb.storage .sd-storage__meta {
    grid-column: 2;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    min-inline-size: 0;
    max-inline-size: 100%;
    gap: 3px;
    font-size: 13px;
    font-weight: 400;
    letter-spacing: -.016em;
    line-height: 1.4285914286;
    color: var(--sd-ink-2);
    text-align: end;
}

/* Deliberately NOT nowrap: "From $45.83/mo. for 24 months" cannot fit one line on a narrow card,
   and forcing it to try is what pushed the text outside the border. Wrapping is the graceful
   failure; the balance hint keeps a two-line wrap from leaving one orphan word. */
#buy_device .deviceRelatedItemsContainer .gb.storage .sd-storage__price {
    max-inline-size: 100%;
    overflow-wrap: break-word;
    text-wrap: balance;
}

/* The monthly IS the tile's figure - it took over the emphasis the "Buy from" line used to carry
   before that line was removed.

   Targeted BY NAME, not by :first-child as it was: positional emphasis was only ever correct for
   as long as the buy line happened to sit first, and it would transfer itself silently to whatever
   ended up leading. The lease line stays the quieter of the two overall - it inherits
   .sd-storage__meta's 400 / --sd-ink-2 for its words, and lifts only its amount (below). */
#buy_device .deviceRelatedItemsContainer .gb.storage .sd-storage__price--monthly {
    font-weight: 600;
    color: var(--sd-ink);
}

/* The FIGURE on the lease line reads at the monthly's weight and ink, while "or lease" and
   "/mo. for 12 months" around it stay muted - so the two tile lines scan as one column of prices
   even though the lease is the secondary offer. On the monthly line this is a no-op: that whole
   line already carries both, and restating them here keeps one rule for "this is the amount"
   rather than letting <b>'s default 700 diverge from the 600 above. */
#buy_device .deviceRelatedItemsContainer .gb.storage .sd-storage__amount {
    font-weight: 600;
    color: var(--sd-ink);
}

#buy_device .deviceRelatedItemsContainer .gb.storage.selected .sd-storage__meta { color: var(--sd-ink); }

@media (max-width: 600px) {
    #buy_device .deviceRelatedItemsContainer .gb.storage { padding: 16px 18px; }
    #buy_device .deviceRelatedItemsContainer .gb.storage.selected { padding: 15px 17px; }
}

/* The legacy out-of-stock cross is a full-bleed SVG; Apple just dims the row instead. */
#buy_device .deviceRelatedItemsContainer .gb.storage .cross-overlay { display: none; }

/* A grid item now, so it is pinned across both columns instead of landing in whichever cell
   happens to be free and squeezing the price stack. */
#buy_device .deviceRelatedItemsContainer .gb.storage.out-of-stock::after {
    grid-column: 1 / -1;
    content: attr(data-oos-label);
    font-size: 12px;
    font-weight: 400;
    letter-spacing: -.01em;
    color: var(--sd-ink-2);
}

/* ---- colour swatches ---- */

#buy_device #relatedItemColor { margin-block-end: 28px; }

/* The selected swatch's ring is drawn OUTSIDE its 28px box (0 0 0 4px). With no room around the
   swatch the first one's ring sat flush against the list edge and read as clipped.
   The room is given to each <li> rather than to the <ul>: padding on the list plus a negative
   margin to cancel it just moves the problem, because the overhang then lands outside the list
   box where an ancestor's overflow can still clip it. Inside an li nothing can clip it.
   gap drops 12px -> 4px so the spacing between swatches is unchanged: 4 (li) + 4 (gap) + 4 (li). */
#buy_device #relatedItemColor ul {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin: 0;
    padding: 0;
    list-style: none;
}

#buy_device #relatedItemColor ul li {
    display: flex;
    padding: 4px;
    margin: 0;
}

/* custom-rtl.css sets `.phone-color-box { margin-left: 10px }` unscoped, which indents the first
   swatch and knocks the whole row out of line with the capacity tiles above. Spacing here comes
   from the list gap, so the margin is zeroed. (Its `margin-right: unset !important` resolves to 0
   anyway, so nothing is being fought over.) */
#buy_device #relatedItemColor .phone-color-box {
    display: block;
    margin: 0;
    inline-size: 28px;
    block-size: 28px;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
    cursor: pointer;
    transition: box-shadow .18s var(--sd-ease), transform .18s var(--sd-ease);
}

#buy_device #relatedItemColor .phone-color-box:hover { transform: scale(1.06); }

/* Apple rings the selected swatch rather than outlining it - 2px gap, then the blue ring. */
#buy_device #relatedItemColor .phone-color-box.selected {
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12),
                0 0 0 2px #fff,
                0 0 0 4px var(--sd-blue);
}

/* A colour with no purchasable capacity. This used to be inline styling applied by the JS that built
   the swatches; they are server-rendered now, so the rule has to live here or a sold-out colour is
   indistinguishable from an available one.

   A struck-through circle rather than the capacity tiles' cross-overlay svg: at 28px a two-line cross
   reads as noise, and one diagonal is unmistakable. */
#buy_device #relatedItemColor .phone-color-box.disabled {
    position: relative;
    opacity: .4;
    cursor: not-allowed;
}

#buy_device #relatedItemColor .phone-color-box.disabled:hover { transform: none; }

#buy_device #relatedItemColor .phone-color-box.disabled::after {
    content: "";
    position: absolute;
    inset-inline-start: -2px;
    inset-inline-end: -2px;
    inset-block-start: 50%;
    block-size: 2px;
    background: #d0021b;
    border-radius: 2px;
    transform: rotate(-45deg);
    transform-origin: center;
}

@media (max-width: 575.98px) {
    /* KEEPS A FLOOR HEIGHT, and a taller one than the type alone would give.
       `min-block-size: 0` used to sit here, on the reasoning that a stacked tile should grow to its
       content. It does grow - but its content at this width is one 15px label beside one 13px price,
       so "grow to content" bottomed out around 50px: a thin strip that neither looked tappable nor
       matched the 76px tiles the same list shows one breakpoint up. These are the primary control on
       the page and the whole row is the hit target, so the floor is worth more than the pixels it
       costs. 64px clears Apple's 44px minimum comfortably and still leaves a two-line price room to
       push past it. */
    #buy_device .deviceRelatedItemsContainer .gb.storage {
        padding: 18px 16px;
        font-size: 15px;
        min-block-size: 64px;
    }
    /* -1px on each side absorbs the selected state's 2px border, so choosing a tile cannot resize it. */
    #buy_device .deviceRelatedItemsContainer .gb.storage.selected { padding: 17px 15px; }
    /* 22px here was the last of the run-up to the payment band, which has been tightened at this
       width - see .sd-v2--band in the 991.98 block. Trimmed to match rather than left to reinstate
       half the gap that was just removed. */
    #buy_device .deviceRelatedItemsContainer .gbs { gap: 8px; margin-block-end: 12px; }
}

/* =============================================================================
   Scroll reveal
   Applied by detail-configurator.js adding .is-revealed. Fails OPEN: the class is
   added immediately when IntersectionObserver is missing or the user asked for
   reduced motion, so content is never left invisible.
   ============================================================================= */

.sd-v2 [data-sd-reveal] {
    opacity: 0;
    transform: translateY(20px);
    transition: opacity .6s var(--sd-ease), transform .6s var(--sd-ease);
    will-change: opacity, transform;
}

.sd-v2 [data-sd-reveal].is-revealed { opacity: 1; transform: none; }

/* Stagger children so a section assembles rather than snapping in. */
.sd-v2 [data-sd-reveal] .sd-card,
.sd-v2 [data-sd-reveal] .sd-summary__box > * {
    opacity: 0;
    transform: translateY(10px);
    transition: opacity .45s var(--sd-ease), transform .45s var(--sd-ease);
}

.sd-v2 [data-sd-reveal].is-revealed .sd-card,
.sd-v2 [data-sd-reveal].is-revealed .sd-summary__box > * { opacity: 1; transform: none; }

.sd-v2 [data-sd-reveal].is-revealed .sd-card:nth-child(1) { transition-delay: .06s; }
.sd-v2 [data-sd-reveal].is-revealed .sd-card:nth-child(2) { transition-delay: .12s; }
.sd-v2 [data-sd-reveal].is-revealed .sd-card:nth-child(3) { transition-delay: .18s; }
.sd-v2 [data-sd-reveal].is-revealed .sd-card:nth-child(4) { transition-delay: .24s; }

.sd-v2 [data-sd-reveal].is-revealed .sd-summary__box > *:nth-child(2) { transition-delay: .05s; }
.sd-v2 [data-sd-reveal].is-revealed .sd-summary__box > *:nth-child(3) { transition-delay: .10s; }
.sd-v2 [data-sd-reveal].is-revealed .sd-summary__box > *:nth-child(4) { transition-delay: .15s; }
.sd-v2 [data-sd-reveal].is-revealed .sd-summary__box > *:nth-child(5) { transition-delay: .20s; }


/* Motion is decoration here, never the only way to see content. */
@media (prefers-reduced-motion: reduce) {
    .sd-v2 [data-sd-reveal],
    .sd-v2 [data-sd-reveal] .sd-card,
    .sd-v2 [data-sd-reveal] .sd-summary__box > * {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
    }
    .sd-stickybar__content { transition: none !important; }
    .sd-v2 .sd-summary__hero-img { transition: none !important; }
    .sd-v2 .sd-summary__hero-img.is-swapping { opacity: 1 !important; }
}

/* ---- utility ------------------------------------------------------------- */

.sd-v2 [hidden], .sd-stickybar [hidden] { display: none !important; }

.sd-v2 .is-busy { position: relative; pointer-events: none; opacity: .5; }

.sd-sr {
    position: absolute;
    inline-size: 1px; block-size: 1px;
    padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* STACKS AT 992px, not 768px.
   The grid was `1.5fr 1fr 328px` when this breakpoint was set, and that third track was a FIXED
   328px rail - it did not shrink with the viewport, it took the same bite out of a smaller one. At
   768px that left the price column around 180px to hold a 36px figure and a "for 24 months" line,
   which wrapped into a mess.
   The rail has since gone, but the breakpoint stays where it is: two columns at 768px would still
   be tight, and stacking through the whole tablet range costs nothing on desktop. */
@media (max-width: 991.98px) {
    /* One column, so both parts stack. Declared explicitly: the desktop template names two columns,
       and leaving it would put "media panel" side by side inside a single-column grid. */
    .sd-v2 .sd-summary {
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas:
            "media"
            "panel";
        column-gap: 0;
        padding: 0;
    }


    /* Theirs drops to `padding:32px 6.25% 0` at this width. Block only - the inline edges are the
       page's own at every width, see the note on this rule's base declaration. */
    .sd-v2 #sdSummarySection.sd-section { padding: 32px 0 38px; }

    /* The column stops being a fixed 22.35rem and the shot loses its bottom-alignment job, since
       there is no second column left to align to.

       CENTRED here, where the desktop starts its text on the leading edge. Stacked, the headline no
       longer has a price column beside it to align against - it sits directly over the product shot,
       which is itself centred, so a left-aligned title reads as knocked out of place above a centred
       image. text-align on the column rather than align-items on the flex children: the name line
       keeps its -webkit-box line clamp, which shrink-to-fit would interfere with. */
    .sd-v2 .sd-summary__hero { inline-size: 100%; text-align: center; }

    .sd-v2 .sd-summary__hero-media { margin-block-start: 0; padding-block-start: 28px; }

    /* .rf-bfe-summary-image-img { max-width:328px; width:87.5vw } */
    .sd-v2 .sd-summary__hero-img { inline-size: 87.5vw; max-inline-size: 328px; }

    /* Theirs: .rf-bfe-summary-image-headline drops with the page's type scale. The long-name steps
       drop from there rather than keeping their desktop sizes - the column is narrower here, so a
       name that needed a step down on desktop still needs one. */
    .sd-v2 .sd-summary__intro { font-size: 28px; letter-spacing: .007em; line-height: 1.1428571429; }
    .sd-v2 .sd-summary__intro.is-long { font-size: 24px; letter-spacing: .009em; }
    .sd-v2 .sd-summary__intro.is-xlong { font-size: 20px; letter-spacing: .012em; }

    /* Stacked, the price column follows the image rather than sitting beside it. */
    .sd-v2 .sd-summary__panel { margin-block-start: 26px; }

    /* The floor stops the fact rows and the CTA jumping when the figure resolves. Keep it - but
       only as much of it as the smaller figure actually needs. */
    .sd-v2 .sd-summary__figure { min-block-size: 84px; margin-block-start: 16px; }
}

/* ---- step cascade ----------------------------------------------------------
   Colour -> capacity -> condition -> trade-in -> payment. Each step is inert
   until the one above it has been chosen; detail-configurator.js owns which.

   Deliberately NOT scoped under .sd-v2: the colour and capacity blocks are
   legacy markup living outside that wrapper, so every custom property used
   here carries a literal fallback. The .sd-section steps get .is-locked as
   well and keep the payment gate's existing treatment.
   -------------------------------------------------------------------------- */

[data-sd-step].is-step-locked {
    pointer-events: none;
    user-select: none;
}

/* Grey the CONTROLS, not the heading. A greyed-out title reads as "this section
   is broken"; a greyed-out control set reads as "not yet". */
[data-sd-step].is-step-locked .gbs,
[data-sd-step].is-step-locked > ul,
[data-sd-step].is-step-locked .sd-tradeup__row,
[data-sd-step].is-step-locked .sd-tradeup__module,
[data-sd-step].is-step-locked .sd-methods {
    opacity: .4;
    filter: grayscale(1);
    transition: opacity .25s var(--sd-ease, ease), filter .25s var(--sd-ease, ease);
}

/* The hint for a locked step - the same padlock chip .sd-section__locked uses,
   restated so it stands up outside .sd-v2. Only ever visible while locked.

   DESCENDANT, not a direct child: the hint now lives INSIDE its section's title
   (the capacity .choose_text_title, the condition h3, the trade-in h3) so that it
   reads as a caption beside the heading it belongs to rather than as a separate
   line under it. A `>` here would silently stop matching. */
/* NEVER RENDERED VISIBLY - the padlock badge was removed from the UI per request, on the capacity
   heading and on every other step that shares this class (condition, trade-in).
   Kept in the markup and clipped rather than display:none'd, for the same reason as
   .sd-section__locked above: display:none also removes it from the accessibility tree, so a locked
   step would stop being announced as well as stop being drawn. No pixels, still readable by a
   screen reader, nothing in the JS to change. */
.sd-step__hint,
[data-sd-step].is-step-locked .sd-step__hint {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
    background: none;
}

[data-sd-step].is-step-locked .sd-step__hint::before { content: none; }

/* ── Sold-out condition tile ─────────────────────────────────────────────────
   A condition that exists at this colour + capacity but has no stock is drawn,
   not dropped - the same rule the colour swatches and capacity tiles follow, so
   the customer can see the option and see that it is unavailable here.

   The treatment is the capacity tiles' exactly: a muted fill, muted text, and an
   "Out of stock" caption (data-oos-label, set in detail.js). No line is drawn over
   it - see the note further down for why the red diagonal was taken off. The radio
   is disabled in the markup, so this is presentation only - pointer-events on the
   label stop the click landing before that matters. */
.sd-v2 .sd-tradeup__choice.is-out-of-stock .sd-tradeup__choice-label {
    position: relative;
    overflow: hidden;
    background: var(--sd-surface-2);
    border-color: var(--sd-line);
    color: var(--sd-ink-2);
    cursor: not-allowed;
    pointer-events: none;
}

.sd-v2 .sd-tradeup__choice.is-out-of-stock .sd-tradeup__choice-title {
    opacity: .55;
}

/* The red diagonal lived here, on ::before. REMOVED - the tile is dimmed and
   captioned now, nothing is drawn across it. It was borrowed from the colour
   swatch, where a red slash is the only way a 28px circle can say anything at
   all; a condition tile has a name and a caption, so the line was adding alarm
   to a message the words already carried, and it ran straight through the word
   it was meant to qualify. The capacity tiles reached the same conclusion
   earlier - their legacy cross-overlay SVG is display:none'd for this reason.

   ::before is free again. Nothing else on this tile uses it. */

/* "Out of stock", under the name. Reads the label off the wrapper so the string
   stays localised in detail.js (CONDITION_LABELS.outOfStock) rather than being
   hard-coded in CSS content. */
.sd-v2 .sd-tradeup__choice.is-out-of-stock .sd-tradeup__choice-label::after {
    content: attr(data-oos-label);
    position: absolute;
    inset-block-end: 4px;
    inset-inline: 0;
    text-align: center;
    font-size: 11px;
    font-weight: 400;
    letter-spacing: -.01em;
    color: var(--sd-ink-2);
    pointer-events: none;
}

/* Room for that caption, so it never sits on top of the name. */
.sd-v2 .sd-tradeup__choice.is-out-of-stock .sd-tradeup__choice-label {
    padding-block-end: 20px;
}
