/* ==========================================================================
   TESTIMONIAL CAROUSEL

   This one stylesheet is loaded in two places on purpose:

   1. In the page head, because the testimonial cards are server-rendered into
      light DOM slots so the quotes appear in the page source for crawlers and
      stay readable if the custom element never upgrades.
   2. Inside the shadow root, because MMX_Element.renderStylesheetLinks()
      collects head <link data-resource-code> elements and the component lists
      "testimonial-carousel" in styleResourceCodes.

   The LIGHT DOM section styles the cards. The SHADOW DOM section styles the
   carousel chrome (viewport, track, arrows, dots). Custom properties are set
   on the host by the component JS and inherit into both contexts.
   ========================================================================== */


/* ==========================================================================
   LIGHT DOM - server-rendered cards
   ========================================================================== */

/* THE SLIDE IS THE SNAP ITEM, THE CARD IS JUST ITS CONTENTS.

   Each slide is exactly one viewport wide and carries no max-width, so the
   scroll step, the viewport and the snap item are the same width by
   construction. That is what makes edge bleed impossible: there is no way for
   the item to end up narrower than the step it scrolls by.

   The card then sizes itself to Card Width inside that full-width slide, which
   decouples the visible card from the sliding area. The whole viewport width
   sweeps as the reader moves between quotes while the card stays centred at its
   own width.

   The inline padding is what keeps consecutive cards from butting up against
   each other mid-transition: half the gap sits inside the trailing edge of one
   slide and half inside the leading edge of the next, so the visible separation
   is the full --card-gap. box-sizing is border-box, so that padding comes out of
   the slide's own 100% rather than adding to it, and the snap step is untouched.

   These rules live in the light DOM section rather than as ::slotted() rules,
   because for a slotted element the outer document's rules beat the shadow
   tree's ::slotted rules at equal specificity. Declaring the slide's geometry
   once, here, removes the conflict rather than losing it. */

.testimonial-carousel__slide {
	/* center, not flex-start. The viewport is as tall as the TALLEST slide, so a short card pinned to
	   the top of its slide sits high inside it - and the overlay arrows, which are correctly centred
	   on the viewport, then land below the card. Centring the card makes the two centres the same
	   point. Invisible while Match All Cards to the Tallest was on, because every card filled its
	   slide; it appeared the moment that was switched off.

	   center rather than stretch: stretching would equalise every card's height whether or not the
	   editor asked for it, which is the thing the original flex-start was protecting against. */
	align-items: center;
	box-sizing: border-box;
	display: flex;
	flex: 0 0 100%;
	justify-content: center;
	scroll-snap-align: start;
	scroll-snap-stop: always;
	width: 100%;
}

/* align-items above is center rather than stretch on purpose. Stretching would equalise every
   card's height whether or not the editor asked for it, which would make the Equal Height setting
   meaningless. Equal height is done by --card-min-height, which the JS only sets when the setting
   is on and the quote is not scrolling. */

/* The two color defaults are declared here as real custom properties rather than
   as var() fallbacks. A fallback is invisible to any other rule that reads the
   same property, which is what broke an unconfigured card: the ::part rule below
   read --card-color, found nothing, and fell through to the typography theme's
   own dark slate. Declaring them on the card makes them inheritable values that
   every rule and every descendant can see, and an inline value emitted by
   instance.mvt still outranks this rule.

   Only card-inline properties may be declared this way. --card-width,
   --card-padding, --card-radius, --card-max-width and --card-min-height are set
   by the JS on the HOST, so declaring them here would shadow the host value;
   those keep the var(--x, fallback) form on purpose. */

.testimonial-carousel__card {
	/* Three levels, resolved in one place: a per-card override arrives as an inline style on this
	   element and beats this rule outright; failing that the component-wide Card Colors setting;
	   failing that these. */
	--testimonial-carousel__card-background: var(--testimonial-carousel__cards-background, #f5f5f5);
	--testimonial-carousel__card-color: var(--testimonial-carousel__cards-color, #000000);
	/* The marks follow the card's TEXT colour by default rather than a fixed green - black on the
	   default card, and still legible if the card is ever made dark. Quote Mark Color overrides it. */
	--testimonial-carousel__quote-mark-color: var(--testimonial-carousel__cards-quote-mark-color, var(--testimonial-carousel__card-color));

	position: relative;

	background-color: var(--testimonial-carousel__card-background);
	border-radius: var(--testimonial-carousel__card-radius, 16px);
	box-sizing: border-box;
	color: var(--testimonial-carousel__card-color);
	align-content: center;
	display: grid;
	flex: 0 1 auto;
	/* Row gap is the space between the quote and the name, and it wants to be much tighter than the
	   column gap between the mark and the text - one is a caption sitting under its quote, the other
	   is a decorative glyph in its own gutter. A single gap made the name look detached. */
	column-gap: 1.25rem;
	grid-template-columns: auto minmax(0, 1fr);
	row-gap: 0.75rem;
	margin: 0 auto;
	max-width: var(--testimonial-carousel__card-max-width, 1440px);
	min-height: var(--testimonial-carousel__card-min-height, auto);
	padding: var(--testimonial-carousel__card-padding, 40px 56px);
	width: var(--testimonial-carousel__card-width, 100%);
}

/* ONE grid, on the card, so the open mark holds column one and the quote, the closing mark and the
   name all share column two:

       [ open mark ] [ quote text ... closing mark ]
                     [ - name                      ]

   The grid used to live on the blockquote, which left the name outside it and hard against the
   card's left edge while the quote sat indented past the mark. Aligning them from two separate
   boxes would have meant hard-coding the mark's width; sharing one column means they cannot drift.

   With Quote Marks off there is no column-one child at all, so the auto track collapses to zero and
   leaves no phantom indent. */

/* Column two of the card, holding the quote and the name as one stack. A flex column rather than
   two grid rows: the name has to sit immediately under the last line of the quote, and a grid row
   that fills the card's height puts it at the bottom instead. min-height: 0 so the quote inside can
   shrink and scroll rather than pushing this column past the card. */

.testimonial-carousel__body {
	display: flex;
	flex-direction: column;
	grid-column: 2;
	grid-row: 1;
	min-height: 0;
	min-width: 0;
}

.testimonial-carousel__quote-row {
	border: 0;
	margin: 0;
	padding: 0;
	quotes: none;
	text-align: var(--testimonial-carousel__text-align, center);

	/* Maximum Quote Lines. A long review used to make the slide enormous; this caps it and ends the
	   last visible line with an ellipsis.

	   The clamp has to sit on this element rather than inside mmx-text, because the closing mark is
	   a sibling of the text and both have to be inside the clamped box for the mark to sit at the end
	   of the last line. The trade: when a quote IS clamped, the closing mark is part of what gets
	   cut. It is decorative and the quote is already truncated, so that is the cheaper loss. */
	-webkit-box-orient: vertical;
	-webkit-line-clamp: var(--testimonial-carousel__quote-max-lines, 8);
	display: -webkit-box;
	overflow: hidden;
}

/* Scroll instead of trimming. A definite height is what makes it scroll - and it also makes every
   card the same height whatever the quote length, which the clamp only approximates.

   line-clamp and -webkit-box are both undone here rather than left to lose a specificity contest:
   a box that is still -webkit-box with a line limit will not scroll, it just truncates inside a
   taller box. */

/* The height is the CARD's, not the quote box's.

   It used to sit on the quote row, which meant setting it to 100 still gave a ~211px card: 100 for
   the box, plus the card's own 40px top and bottom padding, plus the row gap, plus the name. The
   number in the panel has to be the number you measure on the page, so it moves here and the quote
   takes whatever is left after the padding and the name.

   grid-template-rows is what hands it over: minmax(0, 1fr) lets the quote row shrink below its
   content - a bare 1fr floors at min-content and the card would grow past its height instead of the
   quote scrolling - and auto keeps the name at its natural size. box-sizing is already border-box,
   so the padding comes out of the height rather than adding to it. */

testimonial-carousel[data-quote-overflow="scroll"] .testimonial-carousel__card {
	height: var(--testimonial-carousel__quote-box-height, 300px);
}

testimonial-carousel[data-quote-overflow="scroll"] .testimonial-carousel__quote-row {
	-webkit-line-clamp: none;
	display: block;
	/* height, not max-height. Every card is the same 300px whether its quote fills it or not, which
	   is what makes the carousel stop resizing as it moves between slides.

	   1.0.15 went the other way - max-height - because a definite height was padding out a SHORT
	   quote. That was the right call while the component was still matching cards to the tallest,
	   where the two compounded. With that off, a definite height is the thing making them uniform
	   rather than the thing distorting them. Both the component setting and the per-card override
	   feed this same property, so either can change it. */
	min-height: 0;

	/* hidden, not auto. A quote that fits needs no scrollport, and a scrollport that has nothing to
	   scroll still swallows the wheel while the pointer is over it - which is why hovering a short
	   quote stopped the page moving. overflow-y is switched to auto below, only on the boxes that
	   actually overflow.

	   hidden rather than visible so the measurement still works before the JS has run: clientHeight
	   stays at the cap and scrollHeight still reports the full content, which is what tells us
	   whether to switch it on. */
	overflow-y: hidden;

	/* A fade at the bottom edge, so a box with more below it looks like it has more below it.

	   Two layers doing the work of a measurement. The fade is attached to the SCROLLPORT, so it
	   stays pinned to the bottom edge while the text moves under it. The cover is the card's own
	   colour attached to the CONTENT, so it travels with the text and slides over the fade exactly
	   as the last line arrives. No JS, no scroll listener, and it is correct at both ends: nothing
	   to scroll means the content is shorter than the box and the cover already sits over the fade. */
	background:
		linear-gradient( to top, var(--testimonial-carousel__card-background) 0%, transparent 100% )
			bottom / 100% 2.5rem no-repeat local,
		linear-gradient( to top, var(--testimonial-carousel__card-background) 0%, transparent 100% )
			bottom / 100% 2.5rem no-repeat scroll;
}

/* The hint. Only on cards that can actually scroll - syncScrollHints() compares scrollHeight to
   clientHeight and sets data-scroll-hint, then clears it once the reader reaches the bottom. That is
   what was wrong before: the chevron was unconditional, so a short card that could not scroll still
   advertised that it could.

   Absolutely positioned on the CARD, not inside the scrollport, and that is deliberate. A hint in
   the scroll flow would add to scrollHeight - the very number being measured to decide whether to
   show it. Out of flow, measuring cannot change the answer, which is the difference between this and
   the button-equalising pass that oscillated.

   The arrow is a text glyph rather than an image or a mask, so it inherits the card's text colour
   without needing a mask to carry currentColor. */

/* Two pseudo-elements, because the label and the arrow want different sizes - one shared font-size
   made the arrow as small as the caption, which is what "tiny" meant. The arrow is also stretched
   horizontally: a wide flat chevron reads as "there is more below" far more clearly than a small
   symmetric triangle. */

.testimonial-carousel__card[data-scroll-hint]::before {
	bottom: 1.5rem;
	content: "Scroll Down";
	font-size: 0.8125rem;
	font-style: normal;
	left: 0;
	letter-spacing: 0.08em;
	line-height: 1;
	opacity: 0.7;
	pointer-events: none;
	position: absolute;
	right: 0;
	text-align: center;
	text-transform: uppercase;
	z-index: 1;
}

.testimonial-carousel__card[data-scroll-hint]::after {
	bottom: 0.55rem;
	/* Drawn, not typed. This was character U+25BE, which put the indicator at the mercy of whatever
	   font the card inherited shipping that glyph - and needed a scaleX to look right when it did.
	   Borders always render, and the width and height are now set independently. */
	border-left: 0.75rem solid transparent;
	border-right: 0.75rem solid transparent;
	border-top: 0.5rem solid currentColor;
	content: "";
	height: 0;
	left: 50%;
	opacity: 0.7;
	pointer-events: none;
	position: absolute;
	transform: translateX( -50% );
	width: 0;
	z-index: 1;
}


/* Now it can scroll. data-scrollable is the stable flag - set whenever the content exceeds the box,
   and left alone as the reader moves - so reaching the bottom does not switch scrolling back off. */

.testimonial-carousel__card[data-scrollable] .testimonial-carousel__quote-row {
	overflow-y: auto;
	overscroll-behavior: contain;
}

.testimonial-carousel__quote-row::before,
.testimonial-carousel__quote-row::after {
	content: none;
}

/* Inline all the way down, so the closing mark follows the last word instead of dropping to a line
   of its own. mmx-text renders its content in an element carrying a .type-* class, and those are all
   display: block - so making only the host inline would leave the block inner pushing the mark down.
   ::part reaches both. */

.testimonial-carousel__quote,
.testimonial-carousel__quote::part(text),
.testimonial-carousel__quote::part(text__inner) {
	display: inline;
}

.testimonial-carousel__quote:not([data-own-color])::part(text__inner),
.testimonial-carousel__attribution:not([data-own-color])::part(text__inner) {
	color: var(--testimonial-carousel__card-color);
}

/* The marks are decorative glyphs, so they are sized in rem rather than em - an em would scale them
   off the card's inherited body size, which has nothing to do with the quote's own typography.

   Both the size and the face are settings now. The default face is a serif because that is what the
   mockup draws; Match the Body Text publishes inherit instead. The previous default of 5.5rem was
   sized for a Georgia glyph at roughly 0.29 of its em box - when the face fell back to the sans body
   font the same box drew a much larger, heavier glyph, which is why they came out far bigger than
   the mockup. */

.testimonial-carousel__quote-mark {
	color: var(--testimonial-carousel__quote-mark-color, currentColor);
	font-family: var(--testimonial-carousel__quote-mark-font, Georgia, "Times New Roman", serif);
	font-size: var(--testimonial-carousel__quote-mark-size, 2.5rem);
	font-weight: 700;
	line-height: 1;
}

/* The open mark is the only thing in column one. height caps the oversized em box so it cannot
   claim a full line of space above the first line of the quote. */

.testimonial-carousel__quote-mark--open {
	display: block;
	grid-column: 1;
	grid-row: 1;
	height: 0.5em;
	margin-right: 0.75rem;
	margin-top: -0.05em;
}

/* Inline, immediately after the last word. No height cap here: it sits in the text flow and a
   half-em box would drag the last line's height around. */

.testimonial-carousel__quote-mark--close {
	display: inline;
	margin-left: 0.1em;
}

/* Column two, under the quote - which is what puts the name in line with the text instead of hard
   against the card's edge. text-align is left rather than the shared setting: the quote is justified
   by default and a justified single short line just sits left anyway, but an explicit value stops
   the name centring or right-aligning when the quote does. */

.testimonial-carousel__attribution-row {
	font-style: italic;
	margin-top: 0.75rem;
	text-align: var(--testimonial-carousel__text-align, center);
}

.testimonial-carousel__attribution-prefix {
	margin-right: 0.35em;
}

.testimonial-carousel__attribution {
	display: inline;
}

/* Non-current cards stay fully rendered in the scroll track - that is what
   makes the native swipe work - and are removed from the accessibility tree by
   the aria-hidden attribute alone. No visual suppression is applied here on
   purpose; the scroll position is what hides them. */


/* ==========================================================================
   SHADOW DOM - carousel chrome
   ========================================================================== */

:host {
	display: block;
}

/* THE WRAPPER IS A GRID, NOT A WRAPPING FLEX ROW.

   It was a flex row with flex-wrap and a full-width dots row, which relied on
   the line-breaking arithmetic working out: the viewport's flex-basis is 0, so
   whether the dots landed on their own line depended on the gap pushing the
   total past 100%. That is far too delicate a thing to hang the dots on, and it
   changed the moment the arrows stopped rendering.

   A two-row grid states the arrangement outright. The dots occupy their own row
   by name, so they cannot end up beside the viewport no matter which arrow style
   is active or whether any arrows exist at all. The arrow styles then only
   restate the template. */

[part~="wrapper"] {
	align-items: center;
	box-sizing: border-box;
	column-gap: 1rem;
	display: grid;
	grid-template-areas:
		"prev viewport next"
		"dots dots dots";
	grid-template-columns: auto minmax(0, 1fr) auto;
	justify-items: center;
	position: relative;
	width: 100%;
}

[part~="arrow-prev"] {
	grid-area: prev;
}

[part~="arrow-next"] {
	grid-area: next;
}

[part~="dots"] {
	grid-area: dots;
}

/* THE VIEWPORT IS ALWAYS AS WIDE AS THE SPACE IT IS GIVEN.

   It is never sized to Card Width. Its grid column is minmax(0, 1fr), so it
   absorbs whatever the arrows leave behind and the sliding area is the full
   width of the component - one full viewport width sweeps past on every step.
   Card Width is applied to the card inside each slide instead.

   justify-self overrides the wrapper's justify-items: center, which is there for
   the arrows and dots and would otherwise shrink the viewport to its contents. */

[part~="viewport"] {
	grid-area: viewport;
	height: var(--testimonial-carousel__viewport-height, auto);
	justify-self: stretch;
	min-width: 0;
	overflow-x: auto;
	overflow-y: hidden;
	scroll-behavior: smooth;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
	width: auto;
	-ms-overflow-style: none;
}

[part~="viewport"]::-webkit-scrollbar {
	display: none;
	height: 0;
	width: 0;
}

[part~="viewport"]:focus-visible {
	outline: 2px solid var(--testimonial-carousel__arrow-color, #26213f);
	outline-offset: 4px;
}

/* The gap lives HERE, between the slides, rather than as padding on each of them. As padding it
   also inset the first and last slide from the component's own edges, which made the card 40px
   narrower than every other component on the page at the same max width.

   This is only safe because goTo and syncIndexFromScroll both measure a slide's real offset now.
   With the old index * clientWidth arithmetic a column-gap would have drifted the snap by one gap
   per slide. */

[part~="track"] {
	column-gap: var(--testimonial-carousel__card-gap, 40px);
	display: flex;
	flex-wrap: nowrap;
}

/* The height only changes on phones, where it follows the current card. Transitioning it turns
   what would be a jump between two differently sized quotes into a resize you can follow. */

@media ( prefers-reduced-motion: no-preference ) {

	[part~="viewport"] {
		transition: height 0.25s ease-in-out;
	}
}


/* Arrows
   ========================================================================== */

[part~="arrow"] {
	align-items: center;
	appearance: none;
	background: none;
	border: 0;
	border-radius: 50%;
	color: var(--testimonial-carousel__arrow-color, #26213f);
	cursor: pointer;
	display: flex;
	flex: 0 0 auto;
	height: 2.75rem;
	justify-content: center;
	padding: 0;
	transition: opacity 0.15s ease-in-out, transform 0.15s ease-in-out;
	width: 2.75rem;
}

[part~="arrow"] svg {
	height: 1.75rem;
	width: 1.75rem;
}

/* Larger and thinner over the card, matching the mockup's weight. stroke-width is a presentation
   attribute, so CSS overrides the 2 the markup carries without touching the SVG. */

[data-arrow-style="overlay"] [part~="arrow"] svg {
	height: 2.75rem;
	stroke-width: 1.25;
	width: 2.75rem;
}

[part~="arrow"]:hover:not([disabled]) {
	transform: scale(1.1);
}

[part~="arrow"]:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 2px;
}

[part~="arrow"][disabled] {
	cursor: default;
	opacity: 0.25;
}

/* Overlay arrows sit on top of the card edges.

   The wrapper is full width, so these are inset to the card's own edges rather
   than pinned to the component edges. (100% - card width) / 2 is the gutter on
   one side of the centred card, so adding a nudge to it lands the arrow just
   inside the card. When Card Width is 100% the expression collapses to the
   nudge on its own. */

/* With no arrows in the flow there are no side columns to reserve. Collapsing to
   a single column also drops the two column-gaps the empty tracks would
   otherwise still contribute. */

[data-arrow-style="none"],
[data-arrow-style="overlay"] {
	grid-template-areas:
		"viewport"
		"dots";
	grid-template-columns: minmax(0, 1fr);
}

/* Bare chevrons, no disc. The mockup draws them as thin strokes sitting over the card, so the white
   circle the overlay style used to paint is gone and the colour comes from the Arrow Color setting
   rather than being derived from the card - an explicit setting survives a change of card colour,
   a derived one has to be re-derived. */

[data-arrow-style="overlay"] [part~="arrow"] {
	background-color: transparent;

	/* grid-area is what fixes the vertical alignment. The wrapper is position: relative and spans
	   BOTH rows - viewport and dots - so top: 50% was the midpoint of the pair, which sits below the
	   card's own centre by half the dots row.

	   An absolutely positioned child of a grid container that has a definite grid position uses that
	   AREA as its containing block, not the padding box. Naming the viewport area therefore makes
	   50% mean half the viewport, which is the card. Nothing else has to change - the left and right
	   insets still resolve against the same width. */
	grid-area: viewport;

	height: 3.5rem;
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	width: 3.5rem;
	z-index: 2;
}

[data-arrow-style="overlay"] [part~="arrow"]:hover:not([disabled]) {
	transform: translateY(-50%) scale(1.1);
}

[data-arrow-style="overlay"] [part~="arrow-prev"] {
	left: calc( ( 100% - var(--testimonial-carousel__card-width, 100%) ) / 2 + 0.75rem );
}

[data-arrow-style="overlay"] [part~="arrow-next"] {
	right: calc( ( 100% - var(--testimonial-carousel__card-width, 100%) ) / 2 + 0.75rem );
}


/* Arrows below the card, flanking the dots.

   The viewport spans all three columns so it stays full width, and the second
   row becomes the control row: arrow, dots, arrow. The outer columns are 1fr
   each so the trio centres under the card whatever width the dots come out at,
   and each arrow hugs the dots rather than the component edge. */

[data-arrow-style="below"] {
	grid-template-areas:
		"viewport viewport viewport"
		"prev dots next";
	grid-template-columns: 1fr auto 1fr;
}

[data-arrow-style="below"] [part~="arrow-prev"] {
	justify-self: end;
}

[data-arrow-style="below"] [part~="arrow-next"] {
	justify-self: start;
}


/* Dots
   ========================================================================== */

/* The row this sits in is assigned by the grid template, so this rule only has to
   lay the dots out inside it. No width, no order, no flex-basis - those were the
   levers that used to decide whether the row existed at all. */

[part~="dots"] {
	align-items: center;
	display: flex;
	gap: 0.5rem;
	justify-content: center;
	list-style: none;
	margin: 1rem 0 0;
	padding: 0;
}

[part~="dot"] {
	appearance: none;
	background-color: var(--testimonial-carousel__dot-color, #26213f);
	border: 0;
	border-radius: 50%;
	cursor: pointer;
	height: 0.625rem;
	opacity: 0.3;
	padding: 0;
	transition: opacity 0.15s ease-in-out, transform 0.15s ease-in-out;
	width: 0.625rem;
}

[part~="dot"]:hover {
	opacity: 0.6;
}

[part~="dot"]:focus-visible {
	outline: 2px solid var(--testimonial-carousel__dot-color, #26213f);
	outline-offset: 3px;
}

.testimonial-carousel__dot--current {
	opacity: 1;
	transform: scale(1.3);
}


/* Status region - announced, never seen
   ========================================================================== */

[part~="status"] {
	border: 0;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	height: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute;
	white-space: nowrap;
	width: 1px;
}


/* Single card - no chrome at all
   ========================================================================== */

[data-carousel="false"] [part~="arrow"],
[data-carousel="false"] [part~="dots"] {
	display: none;
}

[data-carousel="false"] [part~="viewport"] {
	overflow: visible;
	scroll-snap-type: none;
}


/* Dots hidden by setting
   ========================================================================== */

[data-arrow-style="none"] [part~="arrow"] {
	display: none;
}


/* Motion preferences
   ========================================================================== */

@media ( prefers-reduced-motion: reduce ) {

	[part~="viewport"] {
		scroll-behavior: auto;
	}

	[part~="arrow"],
	[part~="dot"] {
		transition: none;
	}

	[part~="arrow"]:hover:not([disabled]) {
		transform: none;
	}

	[data-arrow-style="overlay"] [part~="arrow"]:hover:not([disabled]) {
		transform: translateY(-50%);
	}
}


/* Small screens
   ========================================================================== */

/* Type that follows the screen below desktop.

   The quote's size is a fixed px value from the typography theme - 24px by default - which is right
   on a 1440px card and far too big on a 390px one. clamp gives a floor, a viewport-relative middle
   and a ceiling, so it scales continuously instead of stepping at a breakpoint.

   ::part is what reaches it. The theme's stylesheet is injected INSIDE mmx-text's shadow root, and a
   ::part rule written out here beats a rule written in there - that is the only hook into it.

   WORTH KNOWING: this takes precedence over the Tablet and Mobile sections of the Quote typography
   panel. Use one or the other, not both, or the panel will look like it is being ignored. */

@media ( max-width: 63.9375em ) {

	/* Both parts, because the block is what sets the line box and the span is what sets the glyphs.
	   Only reaches the non-themed path - a themed instance has no part="text" at all, which is why
	   instance.mvt injects the same values into mmx-text's shadow root instead. */
	.testimonial-carousel__quote::part(text),
	.testimonial-carousel__quote::part(text__inner) {
		font-size: clamp( 1rem, 2.4vw, 1.5rem );

		/* The theme's line-height is set for 24px type. Carried down to 16px it leaves the lines so
		   far apart the quote stops reading as a paragraph. Overridden with an ordinary one for the
		   same reason the size is: the value was chosen for a screen this is not. */
		line-height: 1.5;
	}

	.testimonial-carousel__attribution::part(text),
	.testimonial-carousel__attribution::part(text__inner) {
		font-size: clamp( 0.8125rem, 1.5vw, 1rem );
		line-height: 1.4;
	}

	.testimonial-carousel__quote-mark {
		font-size: var(--testimonial-carousel__quote-mark-size, 2rem);
	}
}


@media ( max-width: 47.9375em ) {

	/* Card Width is ignored on phones. Anything less than the full slide leaves a
	   measure too narrow to read on a 390px screen, so the card fills its slide
	   and the surrounding page gutter provides the breathing room. */

	.testimonial-carousel__card {
		gap: 1rem;
		max-width: none;
		padding: 1.5rem 1.25rem;
		width: 100%;
	}

	/* The gap moved to a column-gap on the track in 1.0.22, so this padding no longer separates
	   anything - it just took another 20px per side off an already narrow card, on top of the gap.
	   Removed; the track's column-gap does the separating at every width now. */

	/* Smaller than the tablet size, not larger. This rule sits after the tablet query, so whatever
	   it sets is what phones get - and it was restoring a size from when the default mark was much
	   bigger, leaving a phone with heavier marks than a tablet. */

	.testimonial-carousel__quote-mark {
		font-size: var(--testimonial-carousel__quote-mark-size, 1.75rem);
	}

	.testimonial-carousel__quote-mark--open {
		margin-right: 0.75rem;
	}

	/* No arrows on phones at all - the dots are the control.

	   They used to drop into a row beneath the card, which still cost a row of height and gave two
	   ways to do the same thing on the screen with the least room for either. Swiping is the natural
	   gesture here and the dots say where you are; the arrows are the redundant one.

	   display: none rather than visibility or a width of zero, so they leave the grid entirely and
	   the wrapper collapses to a single column with nothing reserved for them. */

	[part~="arrow"] {
		display: none;
	}

	/* The Scroll Down hint gets its own strip on phones.

	   It is absolutely positioned at the foot of the card, and on a phone-sized card the text runs
	   all the way down to meet it - which is why it was landing on top of the name. Rather than drop
	   the hint, the body column stops short by exactly the height of the hint, so the strip it sits
	   in is empty by construction.

	   The padding is on the BODY rather than the card, because the card's padding is a setting and
	   adding to a shorthand from here would fight whatever the editor put in it.

	   UNCONDITIONAL, and that is the point. 1.0.28 reserved it only while data-scroll-hint was set -
	   but that attribute comes from comparing scrollHeight to clientHeight, and adding padding
	   changes clientHeight. Reserve space, quote gets shorter, overflows more; reach the bottom, hint
	   clears, padding goes, quote gets taller, may no longer overflow. Measure, change the thing
	   measured, measure again. The strip costs a card that is not scrolling 2.75rem of text space,
	   which is the price of the layout not depending on its own measurement. */

	.testimonial-carousel__body {
		padding-bottom: 2.75rem;
	}

	[part~="wrapper"] {
		grid-template-areas:
			"viewport"
			"dots";
		grid-template-columns: minmax(0, 1fr);
	}

	[part~="wrapper"] [part~="dots"] {
		margin-top: 0.75rem;
	}

}
