/**
 * Island Dental Studio — sections & carousels.
 *
 *   17  Section heading variants
 *   18  Intro row
 *   19  Carousel
 *   20  Patient Stories
 *   21  Fee list
 *   22  CTA panel
 */

/* ═══════════════════════════════════════════════════════
   17  SECTION HEADING VARIANTS
   ═══════════════════════════════════════════════════════ */

.ids-section-head--center { text-align: center; }
.ids-section-head--center .ids-section-head__intro { margin-inline: auto; }

/* Heading on the left, a button on the right — until the button would crowd it. */
.ids-section-head-row {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--ids-space-6);
    margin-bottom: var(--ids-space-7);
}
.ids-section-head-row .ids-section-head { margin-bottom: 0; }
.ids-section-head-row__action { flex: none; }

.ids-section-foot {
    display: flex;
    justify-content: center;
    margin-top: var(--ids-space-7);
}

@media (max-width: 760px) {
    .ids-section-head-row { flex-direction: column; align-items: flex-start; gap: var(--ids-space-5); }
}

/* ═══════════════════════════════════════════════════════
   18  INTRO ROW
   Figma: eyebrow in a 240px rail, copy offset to 304px.
   ═══════════════════════════════════════════════════════ */

.ids-intro-row {
    display: grid;
    grid-template-columns: 240px minmax(0, 1fr);
    gap: var(--ids-space-8);
    margin-bottom: var(--ids-space-7);
}
.ids-intro-row:last-child { margin-bottom: 0; }
.ids-intro-row .ids-eyebrow { margin: 0; padding-top: 0.4em; }
.ids-intro-row__copy { display: flex; flex-direction: column; gap: var(--ids-space-6); }
.ids-intro-row__title { margin: 0; }
.ids-intro-row--narrow .ids-intro-row__title { max-width: 20ch; }
.ids-intro-row__body { max-width: 880px; }
.ids-intro-row--narrow .ids-intro-row__body { max-width: 720px; }
/* Where the frame runs the copy across the whole column rather than holding it
   to a measure (Treatments overview: 1008px of copy, not 880). */
.ids-intro-row--wide .ids-intro-row__body { max-width: none; }

/* A heading set one sentence to a line (Builder → Our Approach → "Set each
   sentence of the heading on its own line"). The lines are the measure, so the
   narrow column's 20ch limit is lifted: "Naturally beautiful results." must
   turn at its full stop, never inside itself. On a phone the display size
   comes down a step so the longest sentence still holds on one line. */
.ids-heading__line { display: block; }
.ids-hero__title--lines .ids-heading__line { text-wrap: balance; }
.ids-intro-row .ids-intro-row__title--lines { max-width: none; }
@media (max-width: 420px) {
    .ids-intro-row__title--lines,
    .ids-section-head__title--lines { font-size: clamp(22px, 6.4vw, var(--ids-h2)); }
    /* A lined hero title steps down the same way, so its short first sentence
       holds one line and the longer one balances onto two. */
    .ids-hero__title--lines { font-size: clamp(30px, 8.7vw, var(--ids-h1)); }
}

/* The split row: eyebrow and heading grouped on the left, the copy alone on
   the right. The heading column is about two-fifths of the row, so a three-
   line heading sits as a compact block beside its paragraphs instead of
   above them; its display size steps down a little so each sentence still
   holds its own line at the column's width. Below 1100px the column would be
   too narrow for that, so the row stacks in reading order. */
.ids-intro-row__lead { display: flex; flex-direction: column; gap: var(--ids-space-4); }
.ids-intro-row--split .ids-intro-row__body { max-width: 720px; }
@media (min-width: 1101px) {
    .ids-intro-row--split {
        grid-template-columns: minmax(0, 38fr) minmax(0, 62fr);
        gap: var(--ids-space-8);
        align-items: start;
    }
    .ids-intro-row--split .ids-eyebrow { padding-top: 0.25em; }
    .ids-intro-row--split .ids-intro-row__title { max-width: none; font-size: clamp(28px, 1.9vw + 8px, 34px); }
}
/* Stacked: the heading goes back to the ordinary display size, including the
   phone step-down that keeps each sentence of a lined heading on one line. */
@media (max-width: 1100px) {
    .ids-intro-row--split { grid-template-columns: minmax(0, 1fr); gap: var(--ids-space-5); }
    .ids-intro-row--split .ids-eyebrow { padding-top: 0; }
}

@media (max-width: 900px) {
    .ids-intro-row { grid-template-columns: minmax(0, 1fr); gap: var(--ids-space-4); }
    .ids-intro-row .ids-eyebrow { padding-top: 0; }

}

/* ═══════════════════════════════════════════════════════
   19  CAROUSEL
   A native horizontal scroller — real content, keyboard reachable and usable
   with JavaScript off. The track runs past both edges of the content column so
   cards read as passing through the page rather than starting at a wall.
   ═══════════════════════════════════════════════════════ */

.ids-carousel { position: relative; }

.ids-carousel__viewport {
    /* Escape the content column, then re-inset the track so the first slide
       still lines up with the copy above it. */
    margin-inline: calc(var(--ids-gutter) * -1);
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    /* Snapped slides line up with the copy above them rather than the raw
       viewport edge, while still being free to run past it. */
    scroll-padding-left: var(--ids-gutter);
    scroll-behavior: smooth;
    scrollbar-width: none;
    -ms-overflow-style: none;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
}
.ids-carousel__viewport::-webkit-scrollbar { display: none; }
.ids-carousel__viewport:focus-visible { outline: 2px solid var(--ids-sage); outline-offset: 4px; border-radius: var(--ids-radius-md); }

.ids-carousel__track {
    display: flex;
    gap: var(--ids-space-6);
    padding-inline: var(--ids-gutter);
    /* Stops the last slide snapping short of the edge. */
    width: max-content;
}

.ids-carousel__slide {
    flex: none;
    scroll-snap-align: start;
    /* Three across at desktop, sized off the content column so slide widths
       match the static grids on the same page. */
    width: calc((min(100vw, var(--ids-container)) - (2 * var(--ids-space-6))) / 3);
    min-width: 260px;
}
.ids-carousel--quotes .ids-carousel__slide { display: flex; }
.ids-carousel--quotes .ids-carousel__slide > * { width: 100%; }

/* While dragging with a mouse, suppress snap and text selection. */
.ids-carousel.is-dragging .ids-carousel__viewport { scroll-snap-type: none; scroll-behavior: auto; cursor: grabbing; }
.ids-carousel.is-dragging .ids-carousel__slide { pointer-events: none; }

/* Teleporting to keep the loop seamless must never animate. */
.ids-carousel.is-jumping .ids-carousel__viewport { scroll-behavior: auto; }

.ids-carousel__controls {
    display: flex;
    justify-content: center;
    gap: var(--ids-space-3);
    margin-top: var(--ids-space-6);
}
.ids-carousel__btn {
    display: grid;
    place-items: center;
    width: 56px;
    height: 56px;
    border: 1px solid var(--ids-sage);
    border-radius: 999px;
    background: transparent;
    color: var(--ids-primary);
    transition: background-color var(--ids-dur-fast) var(--ids-ease), color var(--ids-dur-fast) var(--ids-ease), border-color var(--ids-dur-fast) var(--ids-ease);
}
.ids-carousel__btn:hover { background: var(--ids-sage); color: var(--ids-dark); }
.ids-on-dark .ids-carousel__btn { border-color: rgba(255, 255, 255, 0.35); color: var(--ids-white); }
.ids-on-dark .ids-carousel__btn:hover { background: var(--ids-white); color: var(--ids-dark); }

/* A single slide is not a carousel. */
.ids-carousel.is-static .ids-carousel__controls { display: none; }
.ids-carousel.is-static .ids-carousel__viewport { overflow-x: visible; margin-inline: 0; }
.ids-carousel.is-static .ids-carousel__track { padding-inline: 0; width: auto; }

@media (max-width: 1100px) {
    .ids-carousel__slide { width: calc((min(100vw, var(--ids-container)) - var(--ids-space-6)) / 2); }
}
@media (max-width: 680px) {
    .ids-carousel__slide { width: min(82vw, 360px); }
    .ids-carousel__btn { width: 48px; height: 48px; }
}

/* ═══════════════════════════════════════════════════════
   20  PATIENT STORIES
   The photograph must stay present: the wash is a dark-green tint, not a
   blackout, and the cards are translucent glass over it.
   ═══════════════════════════════════════════════════════ */

.ids-stories {
    position: relative;
    padding-block: var(--ids-section-y-lg);
    overflow: hidden;
    isolation: isolate;
}
.ids-stories__media { position: absolute; inset: 0; z-index: -1; }
.ids-stories__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
/**
 * Overscan, so the drift can never expose an edge.
 *
 * The frame shows the middle 100% of an image 40% taller than it, leaving 20%
 * of spare picture above and below for the shift to move into. That is the
 * budget the module's strength is set against: a strength of s can move the
 * image by up to s/2 of the frame's height in either direction, so anything up
 * to 0.4 is safe here and the house value of 0.25 uses about three fifths of
 * the room. The offset itself is a custom property the module writes — one
 * property per frame, no inline styles, and a value the reduced-motion rule in
 * motion.css can neutralise on its own.
 */
.ids-stories[data-ids-parallax] .ids-stories__img {
    position: absolute;
    top: -20%;
    height: 140%;
    transform: translate3d(0, var(--ids-parallax-y, 0px), 0);
    will-change: transform;
}
.ids-stories__wash {
    position: absolute;
    inset: 0;
    /* The three stops the frame uses. Deep enough for white text at AA, light
       enough that the room, the plants and the light fittings all still read —
       this section must never flatten into a plain green block. */
    background: linear-gradient(180deg,
        rgba(73, 99, 94, 0.86) 0%,
        rgba(27, 53, 48, 0.89) 50%,
        rgba(27, 53, 48, 0.92) 100%);
}

.ids-stories__inner { position: relative; }
.ids-stories .ids-section-head__title { color: var(--ids-white); }

.ids-trust {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--ids-space-6);
    margin: var(--ids-space-8) 0 0;
    padding: var(--ids-space-7) 0 0;
    border-top: 1px solid var(--ids-line-on-dark);
    list-style: none;
}
/* With no reviews published the trust points are the whole band: the rule and
   the space that separated them from the carousel have nothing to separate. */
.ids-trust:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.ids-trust__item { color: var(--ids-accent); }
/* Drawn in the body face at 20/28, light weight — not in the display serif. */
.ids-trust__title {
    margin: var(--ids-space-3) 0 var(--ids-space-3);
    font-family: var(--ids-font-body);
    font-size: clamp(18px, 17.26px + 0.19vw, 20px);
    font-weight: 300;
    line-height: 1.4;
    letter-spacing: -0.2px;
    color: var(--ids-white);
}
.ids-trust__text { margin: 0; font-size: 14px; line-height: 22px; color: var(--ids-surface); }

/* ═══════════════════════════════════════════════════════
   20b VIDEO TESTIMONIALS
   Filmed reviews in the Patient Stories band: two 16:9 cards to a view, one
   where two would be cramped, never a partial card, one card per arrow press.
   The heading sits left and the arrows sit at its baseline on the right — the
   same head-row the team section uses. Playback belongs to the module
   (assets/js/modules/video-testimonials.js); these are the resting, hover
   and playing states it toggles, and nothing here moves on its own.
   ═══════════════════════════════════════════════════════ */

.ids-vt { --ids-vt-gap: var(--ids-space-6); }
/* The head row (§17) already sets the arrows at the heading's baseline and
   stacks them beneath it on narrow screens; nothing to add here. */
.ids-vt__head .ids-section-head { margin-bottom: 0; }
/* The arrows keep to the right even when no heading has been written. */
.ids-vt__controls { display: flex; gap: var(--ids-space-3); margin-left: auto; }
.ids-vt .ids-carousel__btn:disabled {
    opacity: 0.35;
    cursor: default;
    pointer-events: none;
}

.ids-vt__viewport {
    /* Room for a card's focus ring, which would otherwise be clipped. The
       inset is cancelled by the margin so the column width is unchanged. */
    padding: 6px;
    margin: -6px;
    /* Snap to the padding edge, so a resting card sits exactly on the column. */
    scroll-padding: 6px;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scrollbar-width: none;
    -ms-overflow-style: none;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
}
.ids-vt__viewport::-webkit-scrollbar { display: none; }
.ids-vt__viewport:focus-visible { outline: 2px solid var(--ids-sage); outline-offset: 4px; border-radius: var(--ids-radius-md); }

.ids-vt__track {
    display: flex;
    gap: var(--ids-vt-gap);
}
.ids-vt__slide {
    flex: 0 0 calc((100% - var(--ids-vt-gap)) / 2);
    min-width: 0;
    scroll-snap-align: start;
    scroll-snap-stop: always;
}

/* ── Card ── */
.ids-vt-card__frame {
    position: relative;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border-radius: var(--ids-radius-md);
    background: var(--ids-dark);
    isolation: isolate;
}
.ids-vt-card__player,
.ids-vt-card__cover { position: absolute; inset: 0; }
.ids-vt-card__player iframe {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
}
.ids-vt-card__cover {
    z-index: 1;
    transition: opacity var(--ids-dur) var(--ids-ease);
}
.ids-vt-card__img { width: 100%; height: 100%; object-fit: cover; }

/* The whole frame is the play / pause control. */
.ids-vt-card__toggle {
    position: absolute;
    inset: 0;
    z-index: 3;
    display: grid;
    place-items: center;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
/* The ring is drawn on the frame, outside the clipped area, not on the button. */
.ids-vt-card__toggle:focus-visible { outline: none; }
.ids-vt-card:has(.ids-vt-card__toggle:focus-visible) .ids-vt-card__frame {
    outline: 2px solid var(--ids-sage);
    outline-offset: 4px;
}

.ids-vt-card__icon {
    display: grid;
    place-items: center;
    width: clamp(60px, 6vw, 76px);
    height: clamp(60px, 6vw, 76px);
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.92);
    color: var(--ids-primary);
    box-shadow: 0 8px 24px rgba(9, 47, 39, 0.28);
    transition:
        transform var(--ids-dur-fast) var(--ids-ease),
        opacity var(--ids-dur-fast) var(--ids-ease),
        background-color var(--ids-dur-fast) var(--ids-ease);
}
/* The triangle's optical centre sits right of its box's. */
.ids-vt-card__icon--play svg { margin-left: 3px; }
.ids-vt-card__icon--pause { display: none; }
.ids-vt-card__toggle:hover .ids-vt-card__icon,
.ids-vt-card__toggle:focus-visible .ids-vt-card__icon { transform: scale(1.06); background: var(--ids-white); }
.ids-vt-card.is-loading .ids-vt-card__icon { opacity: 0.6; }

/* ── Name label ──
   Bottom-left, clear of the face, legible over light and dark stills alike:
   the same dark-green glass the before/after tags use. */
.ids-vt-card__label {
    position: absolute;
    left: var(--ids-space-4);
    bottom: var(--ids-space-4);
    z-index: 2;
    display: flex;
    flex-direction: column;
    gap: 1px;
    max-width: calc(100% - 2 * var(--ids-space-4));
    margin: 0;
    padding: 9px 14px 10px;
    border-radius: var(--ids-radius-badge);
    background: rgba(27, 53, 48, 0.66);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    color: var(--ids-white);
    pointer-events: none;
    transition: opacity var(--ids-dur) var(--ids-ease);
}
.ids-vt-card__name { font-size: 15px; font-weight: 500; line-height: 22px; }
.ids-vt-card__sub { font-size: 13px; line-height: 18px; color: var(--ids-surface); }

/* ── Playing ──
   Cover, label and play icon step aside so nothing sits over the patient.
   The label is faded, not removed, so it is still there to be read. The
   whole frame stays the control — a press anywhere on the film pauses it. */
.ids-vt-card.is-playing .ids-vt-card__cover,
.ids-vt-card.is-playing .ids-vt-card__label { opacity: 0; }
.ids-vt-card.is-playing .ids-vt-card__cover { pointer-events: none; }
.ids-vt-card.is-playing .ids-vt-card__icon--play { display: none; }
.ids-vt-card.is-playing .ids-vt-card__icon--pause { display: grid; opacity: 0; }
/* The centred Pause shows only while a pointer that can hover is over the
   card, or the control has keyboard focus. The hover rule is held to devices
   that hover: a phone's tap leaves :hover stuck on the card, which kept the
   icon pinned over the footage for the whole film. */
@media (hover: hover) {
    .ids-vt-card.is-playing .ids-vt-card__toggle:hover .ids-vt-card__icon--pause { opacity: 1; }
}
.ids-vt-card.is-playing .ids-vt-card__toggle:focus-visible .ids-vt-card__icon--pause { opacity: 1; }
/* On a touch screen the control is a small chip in the corner instead — the
   same dark glass as the name label — so there is a visible way to pause and
   nothing sits over the patient. */
@media (hover: none) {
    .ids-vt-card.is-playing .ids-vt-card__icon--pause {
        position: absolute;
        right: var(--ids-space-4);
        bottom: var(--ids-space-4);
        width: 40px;
        height: 40px;
        opacity: 1;
        background: rgba(27, 53, 48, 0.66);
        -webkit-backdrop-filter: blur(8px);
        backdrop-filter: blur(8px);
        color: var(--ids-white);
        box-shadow: none;
    }
    .ids-vt-card.is-playing .ids-vt-card__icon--pause svg { width: 18px; height: 18px; }
}

/* ── Cursor-following tip ──
   One element for the page, moved by the module through two custom
   properties. It takes no pointer events and only echoes the button's own
   label — nothing depends on it, and touch screens never get one. */
.ids-cursor-tip {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 120;
    padding: 8px 14px;
    border-radius: 999px;
    background: var(--ids-white);
    color: var(--ids-dark);
    font-family: var(--ids-font-body);
    font-size: 13px;
    font-weight: 500;
    line-height: 1;
    letter-spacing: 0.01em;
    white-space: nowrap;
    box-shadow: 0 8px 24px rgba(9, 47, 39, 0.22);
    pointer-events: none;
    opacity: 0;
    transform: translate3d(var(--ids-tip-x, 0px), var(--ids-tip-y, 0px), 0) translate(18px, 22px);
    transition: opacity var(--ids-dur-fast) var(--ids-ease);
    will-change: transform;
}
.ids-cursor-tip.is-visible { opacity: 1; }

/* Written reviews beneath the films, when a page has both. */
.ids-vt + .ids-carousel { margin-top: var(--ids-space-7); }

/* ── Grid (Patient Stories page) ──
   The same cards on the house grid: three to a row, two where three would be
   cramped, one on a phone, the last row never ragged (components.css §10). */
.ids-vt-grid { margin: 0; padding: 0; list-style: none; }
.ids-vt-grid__item { min-width: 0; }

@media (max-width: 900px) {
    /* Two frames here would be under 320px wide: one full card instead. */
    .ids-vt__slide { flex-basis: 100%; }
}
@media (max-width: 760px) {
    /* The head row has stacked (§17): the arrows sit under the heading, on
       the left, where a thumb reaches them. */
    .ids-vt__controls { margin-left: 0; }
}

/* ═══════════════════════════════════════════════════════
   20c DIGITAL DENTISTRY FILM
   A contained 16:9 frame beneath its intro row. The poster is a layer over
   the video and goes once the first frame has played (is-live); the chip in
   the corner mirrors the testimonial cards' touch chip and the caption their
   name label, so the two kinds of film share one visual language.
   ═══════════════════════════════════════════════════════ */

.ids-dv {
    position: relative;
    margin: 0;
    isolation: isolate;
}
.ids-dv__frame {
    position: relative;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border-radius: var(--ids-radius-lg);
    background: var(--ids-dark);
}
.ids-dv__video,
.ids-dv__poster {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}
.ids-dv__video { display: block; object-fit: cover; }
.ids-dv__poster { z-index: 1; transition: opacity var(--ids-dur) var(--ids-ease); }
.ids-dv__poster picture,
.ids-dv__img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ids-dv.is-live .ids-dv__poster { opacity: 0; }

.ids-dv__label {
    position: absolute;
    left: var(--ids-space-4);
    bottom: var(--ids-space-4);
    z-index: 2;
    max-width: calc(100% - 88px);
    margin: 0;
    padding: 7px 12px;
    border-radius: var(--ids-radius-badge);
    background: rgba(27, 53, 48, 0.66);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    color: var(--ids-white);
    font-size: 13px;
    line-height: 18px;
    pointer-events: none;
}

.ids-dv__toggle {
    position: absolute;
    right: var(--ids-space-4);
    bottom: var(--ids-space-4);
    z-index: 3;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: rgba(27, 53, 48, 0.66);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    color: var(--ids-white);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition:
        background-color var(--ids-dur-fast) var(--ids-ease),
        color var(--ids-dur-fast) var(--ids-ease),
        transform var(--ids-dur-fast) var(--ids-ease);
}
.ids-dv__toggle:hover,
.ids-dv__toggle:focus-visible { background: var(--ids-white); color: var(--ids-primary); transform: scale(1.06); }
.ids-dv__toggle:focus-visible { outline: 2px solid var(--ids-sage); outline-offset: 3px; }
.ids-dv__icon { display: none; line-height: 0; }
.ids-dv__icon svg { width: 18px; height: 18px; }
.ids-dv__icon--play svg { margin-left: 2px; }
.ids-dv:not(.is-playing) .ids-dv__icon--play { display: grid; }
.ids-dv.is-playing .ids-dv__icon--pause { display: grid; }

/* Playback refused or declined (reduced motion, reduced data): the poster is
   the picture, and the chip is the invitation — a little larger, so it reads. */
.ids-dv.is-static .ids-dv__toggle { width: 48px; height: 48px; }

/* ── The slideshow ──
   Photographs stacked in the frame, the current one opaque, the rest faded
   out beneath it (the flip frame's own technique, so nothing can shift). Dots
   along the bottom edge mark the images; small glass arrows sit at the sides
   for a pointer, and are hidden on touch screens, where a swipe does the job. */
.ids-dv__stage { position: absolute; inset: 0; }
.ids-dv__slide {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transition: opacity var(--ids-flip-dur, 900ms) var(--ids-ease);
}
.ids-dv__slide.is-current { opacity: 1; z-index: 1; }
.ids-dv__dots {
    position: absolute;
    left: 50%;
    bottom: var(--ids-space-4);
    z-index: 3;
    display: flex;
    gap: 8px;
    padding: 8px 10px;
    border-radius: 999px;
    background: rgba(27, 53, 48, 0.66);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    transform: translateX(-50%);
}
.ids-dv__dot {
    width: 8px;
    height: 8px;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.45);
    cursor: pointer;
    transition: background-color var(--ids-dur-fast) var(--ids-ease), transform var(--ids-dur-fast) var(--ids-ease);
}
.ids-dv__dot.is-current { background: var(--ids-white); transform: scale(1.25); }
.ids-dv__dot:hover { background: rgba(255, 255, 255, 0.8); }
.ids-dv__dot:focus-visible { outline: 2px solid var(--ids-sage); outline-offset: 3px; }
.ids-dv__arrow {
    position: absolute;
    top: 50%;
    z-index: 3;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: rgba(27, 53, 48, 0.66);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    color: var(--ids-white);
    cursor: pointer;
    transform: translateY(-50%);
    opacity: 0;
    transition: opacity var(--ids-dur-fast) var(--ids-ease), background-color var(--ids-dur-fast) var(--ids-ease), color var(--ids-dur-fast) var(--ids-ease);
}
.ids-dv__arrow--prev { left: var(--ids-space-4); }
.ids-dv__arrow--next { right: var(--ids-space-4); }
.ids-dv__arrow svg { width: 18px; height: 18px; }
.ids-dv--slides:hover .ids-dv__arrow,
.ids-dv--slides:focus-within .ids-dv__arrow { opacity: 1; }
.ids-dv__arrow:hover,
.ids-dv__arrow:focus-visible { background: var(--ids-white); color: var(--ids-primary); }
.ids-dv__arrow:focus-visible { outline: 2px solid var(--ids-sage); outline-offset: 3px; opacity: 1; }
@media (hover: none) {
    .ids-dv__arrow { display: none; }
}
@media (prefers-reduced-motion: reduce) {
    .ids-dv__slide { transition: none; }
}

@media (max-width: 680px) {
    .ids-dv__frame { border-radius: var(--ids-radius-md); }
    .ids-dv__label { left: var(--ids-space-3); bottom: var(--ids-space-3); max-width: calc(100% - 72px); padding: 6px 10px; font-size: 12px; line-height: 16px; }
    .ids-dv__toggle { right: var(--ids-space-3); bottom: var(--ids-space-3); }
    .ids-dv__dots { bottom: var(--ids-space-3); padding: 7px 9px; gap: 7px; }
}
@media (prefers-reduced-motion: reduce) {
    .ids-dv__poster, .ids-dv__toggle { transition: none; }
}

/* ═══════════════════════════════════════════════════════
   21  FEE LIST
   ═══════════════════════════════════════════════════════ */

.ids-fee-list { margin: 0; }
.ids-fee-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--ids-space-5);
    padding-block: 24px;
    border-bottom: 1px solid var(--ids-line);
}
.ids-fee-row:first-child { padding-top: 0; }
.ids-fee-row:last-child { border-bottom: 0; }
.ids-fee-row__label { display: flex; flex-direction: column; gap: 4px; font-size: 17px; line-height: 26px; color: var(--ids-dark); font-weight: 500; }
.ids-fee-row__note { font-size: 14px; line-height: 22px; font-weight: 400; color: var(--ids-body); }
.ids-fee-row__price {
    margin: 0;
    flex: none;
    font-family: var(--ids-font-heading);
    font-size: var(--ids-h4);
    color: var(--ids-primary);
}
/* "From" beside a figure: present, but in the note's voice rather than the
   price's, so the column still scans as a column of figures. */
.ids-fee-row__from {
    margin-right: 2px;
    font-family: var(--ids-font-body);
    font-size: 14px;
    font-weight: 400;
    color: var(--ids-body);
}

/* ═══════════════════════════════════════════════════════
   22  CTA PANEL
   ═══════════════════════════════════════════════════════ */

.ids-cta {
    max-width: var(--ids-container-wide);
    margin-inline: auto;
    /* Inset 24px from the page edge exactly as the hero is, and with no top
       padding of its own — the section above already provides the separation. */
    padding: 0 var(--ids-hero-inset) clamp(20px, 2.36vw, 34px);
}
/* The page behind the card carries on the colour of the section above, so the
   foot of the page closes as one block rather than a green band, a white strip
   and then the footer. The card itself is unchanged. */
.ids-cta-zone { background: var(--ids-surface); }

.ids-cta__panel {
    position: relative;
    display: flex;
    align-items: center;
    padding: clamp(56px, 7.78vw, 112px) clamp(24px, 4.44vw, 64px);
    border-radius: var(--ids-radius-lg);
    overflow: hidden;
    isolation: isolate;
}
.ids-cta__panel--center { justify-content: center; text-align: center; }
.ids-cta__panel--left { justify-content: flex-start; text-align: left; }

.ids-cta__media { position: absolute; inset: 0; z-index: -1; }
.ids-cta__img { width: 100%; height: 100%; object-fit: cover; }
/* See the note on .ids-stories__img — the same treatment, the same budget. */
.ids-cta__panel[data-ids-parallax] .ids-cta__img {
    position: absolute;
    top: -20%;
    height: 140%;
    transform: translate3d(0, var(--ids-parallax-y, 0px), 0);
    will-change: transform;
}

/* Three deliberate strengths rather than one generic black overlay. */
.ids-cta__wash { position: absolute; inset: 0; }
/* Medium is the strength drawn on every approved CTA panel: 71% to 76%. */
.ids-cta__wash--light  { background: linear-gradient(180deg, rgba(27,53,48,.52) 0%, rgba(27,53,48,.58) 100%); }
.ids-cta__wash--medium { background: linear-gradient(180deg, rgba(27,53,48,.71) 0%, rgba(27,53,48,.76) 100%); }
.ids-cta__wash--strong { background: linear-gradient(180deg, rgba(27,53,48,.82) 0%, rgba(27,53,48,.88) 100%); }

.ids-cta__body {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--ids-space-6);
    max-width: 720px;
}
.ids-cta__panel--center .ids-cta__body { align-items: center; }
.ids-cta__title {
    margin: 0;
    font-size: var(--ids-cta-title);
    line-height: var(--ids-cta-title-lh);
    letter-spacing: -0.015em;
    color: var(--ids-white);
}
.ids-cta__text {
    margin: 0;
    max-width: 640px;
    color: var(--ids-surface);
    font-size: var(--ids-body-lg);
}
.ids-cta__actions { margin-top: 0; }
.ids-cta__panel--center .ids-cta__actions { justify-content: center; }

@media (max-width: 560px) {
    .ids-cta__actions { flex-direction: column; align-items: stretch; width: 100%; }
    .ids-cta__actions .ids-btn { width: 100%; }
}
