/**
 * Degree comparison — W4 / P-25. Plugin v0.3.4.
 *
 * This stylesheet carries the whole of the widget's behaviour. There is no script
 * (§5.8): the scroll is `overflow-x`, the pinned row labels are `position: sticky`, and
 * the right-edge fade is an inert absolutely-positioned element. Nothing here hydrates,
 * so nothing here can fail to hydrate.
 *
 * Tokens only. No hardcoded hex outside the white cell fill, no external request, no
 * font family beyond the three already loaded (C-8).
 */

/* -------------------------------------------------------------------------
   Root

   `--esls-dc-surface` is the colour the edge fade resolves to, and it must match
   whatever the section behind the widget is actually painted. Cream is the default
   because C-3 requires these sections to be cream — a widget section on blue-800 is a
   navy void the moment the plugin is deactivated. An operator using a different
   surface overrides this one property on the section rather than editing the fade.
   ------------------------------------------------------------------------- */

.esls-degree-compare {
	--esls-dc-surface: var(--esls-cream-primary);
	/* The two figures the fade breakpoints below are derived from. Changing either
	   without changing those media queries puts a fade over a table that fits. */
	--esls-dc-label-w: 150px;
	--esls-dc-col-w: 190px;

	position: relative;
	text-align: left;
}

.esls-degree-compare__heading {
	font-family: "Fraunces", Georgia, serif;
	font-weight: 600;
	color: var(--esls-text-primary);
	margin: 0 0 12px;
}

.esls-degree-compare__intro {
	font-family: "Source Sans 3", system-ui, sans-serif;
	font-size: 17px;
	line-height: 1.6;
	color: var(--esls-text-secondary);
	margin: 0 0 24px;
	max-width: 62ch;
}

/* Screen-reader-only. Scoped to the widget, following the W1 and W3 precedent;
   `.esls-hidden` in the token sheet is the F-B fallback mechanism, a different job. */

.esls-degree-compare .esls-sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* -------------------------------------------------------------------------
   Scroll region — §5.7

   `overflow-x` here is safe next to a sticky first column because this element is a
   *descendant* of the section. P-13.1 rule 3 prohibits overflow on the *ancestors* of a
   sticky element, and the sticky elements are the cells inside this box, not the box.
   If this widget ever shares a page with a P-14 sticky rail, confirm the rail is not
   inside this wrapper.
   ------------------------------------------------------------------------- */

.esls-degree-compare__scroll {
	/* Containing block for the visually-hidden spans inside the cells. Without it they
	   resolve against the section, keep their static position out in the unclipped part
	   of the table, and drag the *page* sideways at 320px — a 1px box parked at x=550 is
	   still overflow. Caught by the layout gate; it is invisible to the eye and fatal to
	   the mobile floor. */
	position: relative;
	overflow-x: auto;
	/* Momentum scrolling on iOS, and a scrollbar that does not steal layout height on
	   platforms that reserve space for one. */
	-webkit-overflow-scrolling: touch;
	overscroll-behavior-x: contain;
}

/* The region is focusable so a keyboard user can scroll it at all (§5.10). Without
   `tabindex` the right-hand columns are unreachable without a pointer. */

.esls-degree-compare__scroll:focus-visible {
	outline: 2px solid var(--esls-blue-800);
	outline-offset: 2px;
}

/* -------------------------------------------------------------------------
   Table

   `border-collapse: separate` rather than `collapse`. Collapsed borders are owned by
   the table rather than by the cell, and WebKit drops them from a `position: sticky`
   cell as it scrolls — the pinned column loses its right-hand edge exactly when that
   edge is the thing telling the reader the rest of the table is moving underneath it.
   ------------------------------------------------------------------------- */

.esls-degree-compare__table {
	width: 100%;
	border-collapse: separate;
	border-spacing: 0;
	font-family: "Source Sans 3", system-ui, sans-serif;
	/* Fills the container when there is room, and refuses to squeeze below the sum of
	   its own minimum column widths when there is not — which is what turns "too narrow"
	   into a scroll rather than into four characters per line. */
	min-width: 100%;
}

/* Border-box so the two width properties are the whole cell, padding and border
   included. Elementor's reset supplies this globally, but the column budget below is
   arithmetic and it must not depend on a stylesheet this widget does not own. */

.esls-degree-compare__corner,
.esls-degree-compare__label,
.esls-degree-compare__col,
.esls-degree-compare__cell {
	box-sizing: border-box;
}

.esls-degree-compare__corner,
.esls-degree-compare__label {
	min-width: var(--esls-dc-label-w);
	width: var(--esls-dc-label-w);
}

.esls-degree-compare__col,
.esls-degree-compare__cell {
	min-width: var(--esls-dc-col-w);
}

/* -------------------------------------------------------------------------
   Head
   ------------------------------------------------------------------------- */

.esls-degree-compare__corner {
	background: var(--esls-dc-surface);
	border-bottom: 2px solid var(--esls-border-warm);
	padding: 0;
}

.esls-degree-compare__col {
	background: var(--esls-cream-alt);
	border-bottom: 2px solid var(--esls-border-warm);
	border-left: 1px solid var(--esls-border-warm);
	padding: 18px 16px;
	text-align: left;
	vertical-align: bottom;
}

.esls-degree-compare__col-name {
	display: block;
	font-family: "Fraunces", Georgia, serif;
	font-size: 22px;
	font-weight: 600;
	line-height: 1.2;
	color: var(--esls-text-primary);
}

.esls-degree-compare__col-full {
	display: block;
	margin-top: 4px;
	font-size: 13px;
	font-weight: 400;
	line-height: 1.35;
	color: var(--esls-text-secondary);
}

/* §5.10 / §1.7 — a highlighted column is marked in text as well as in colour. The flag
   is the text half; the rule below is the colour half, and neither carries it alone. */

.esls-degree-compare__col-flag {
	display: inline-block;
	margin-top: 8px;
	padding: 3px 8px;
	border-radius: var(--radius-md);
	background: var(--esls-orange-400);
	color: var(--esls-blue-900);
	font-size: 11px;
	font-weight: 700;
	letter-spacing: .08em;
	text-transform: uppercase;
}

.esls-degree-compare__col--highlight {
	border-top: 3px solid var(--esls-orange-400);
	background: var(--esls-cream-warm);
}

/* -------------------------------------------------------------------------
   Body
   ------------------------------------------------------------------------- */

.esls-degree-compare__label {
	background: var(--esls-dc-surface);
	border-bottom: 1px solid var(--esls-border-warm);
	padding: 16px 16px 16px 0;
	text-align: left;
	vertical-align: top;
	font-size: 13px;
	font-weight: 700;
	letter-spacing: .08em;
	text-transform: uppercase;
	/* Not `--esls-text-tertiary`: at 13px uppercase on cream this is a row header, not a
	   caption, and it is the only thing identifying the row once the table is scrolled
	   sideways. `--esls-text-secondary` measures 7.03:1 on cream. */
	color: var(--esls-text-secondary);
	line-height: 1.35;
}

.esls-degree-compare__cell {
	background: #FFFFFF;
	border-bottom: 1px solid var(--esls-border-warm);
	border-left: 1px solid var(--esls-border-warm);
	padding: 16px;
	vertical-align: top;
	font-size: 16px;
	line-height: 1.5;
	color: var(--esls-text-primary);
}

.esls-degree-compare__cell--highlight {
	background: var(--esls-cream-warm);
}

/* The em dash is decoration — the fact is the visually-hidden "Not yet published"
   beside it (§5.2). It is dimmed with a colour token rather than with `opacity`,
   because opacity composites against the cell fill and was exactly the V-17 contrast
   failure patched out of the course card in v0.3.3. */

.esls-degree-compare__empty {
	color: var(--esls-text-tertiary);
}

/* -------------------------------------------------------------------------
   Sticky first column — §5.6

   Pure CSS, and the whole reason horizontal scroll is usable rather than merely
   possible. The sticky cells need an opaque background of their own: without one the
   scrolling cells show through underneath them.
   ------------------------------------------------------------------------- */

.esls-degree-compare[data-sticky="yes"] .esls-degree-compare__corner,
.esls-degree-compare[data-sticky="yes"] .esls-degree-compare__label {
	position: sticky;
	left: 0;
	z-index: 2;
	background-clip: padding-box;
	/* The pinned edge. Carried on the cell rather than on the table, which is what the
	   `border-collapse: separate` note above is about.

	   Not `--esls-border-warm`, which is what every other border here uses. That token
	   measures 1.65:1 and is fine for a separator between cells that are already told
	   apart by their fill — but the pinned column's fill is cream against the cells'
	   white, a 1.03:1 difference, so this line is the only thing marking where the
	   frozen column ends and the moving table begins. A boundary carrying that much
	   meaning is a 1.4.11 non-text contrast case at 3:1; `--esls-text-tertiary` scores
	   5.27:1 against the white it sits beside. */
}

/* WebKit hardening — X-8 (proposed). iOS Safari does not reliably paint the
   background (nor, per the border-collapse note above, the borders) of a
   `position: sticky` table cell once the table has scrolled: the moving cells
   show through the pinned column and its text paints over them. Fill and pinned
   edge therefore live on an absolutely-positioned layer inside the cell —
   sticky is a positioned box, so `inset: 0` resolves against it, and an
   absolute layer is outside the sticky paint path WebKit gets wrong. z-index
   -1 keeps the layer under the cell's own text while the cell's z-index 2
   keeps it above the cells scrolling beneath. The 1.4.11 contrast reasoning
   for the edge token is unchanged from the note above. */
.esls-degree-compare[data-sticky="yes"] .esls-degree-compare__corner::after,
.esls-degree-compare[data-sticky="yes"] .esls-degree-compare__label::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: var(--esls-dc-surface);
	border-right: 1px solid var(--esls-text-tertiary);
}

/* -------------------------------------------------------------------------
   Foot — the per-column calls to action
   ------------------------------------------------------------------------- */

.esls-degree-compare__cell--cta {
	border-bottom: 0;
	padding-top: 20px;
	padding-bottom: 4px;
	background: transparent;
}

.esls-degree-compare tfoot .esls-degree-compare__corner {
	border-bottom: 0;
}

/* Orange fill with blue-900 text, matching W2's result CTA. White on orange-400
   measures 2.9:1 and is not an option on this palette. */

.esls-degree-compare__cta {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 44px;
	padding: 10px 22px;
	border-radius: var(--radius-md);
	background-color: var(--esls-orange-400);
	color: var(--esls-blue-900);
	font-size: 16px;
	font-weight: 600;
	line-height: 1.2;
	text-decoration: none;
	transition: background-color var(--duration-fast) var(--ease-out);
}

.esls-degree-compare__cta:hover,
.esls-degree-compare__cta:focus {
	background-color: var(--esls-orange-300);
	color: var(--esls-blue-900);
}

/* -------------------------------------------------------------------------
   Edge fade — §5.7

   P-13's mechanism, reused under C-1: the mechanism ports, the skin does not. This fade
   resolves to W4's own surface colour, and P-13's arrow button — brand furniture — is
   not ported with it.

   It is `aria-hidden` and `pointer-events: none`: it says nothing the focusable scroll
   region does not already announce, and it must never intercept a tap meant for the
   cell beneath it.

   WHETHER TO DRAW IT AT ALL IS A MEASUREMENT, NOT A BREAKPOINT. Whether the table
   overflows depends on how many columns were chosen and how long the operator's
   duration string is, and no media query can know either. A first cut guessed the
   widths at which a table stops overflowing and put a fade over a table that fitted.

   The base rule below is the fallback: the fade is drawn, and a coarse desktop floor
   removes it where four columns at their own minimum widths provably fit

     label 150px + (4 x 190px) + about 40px of container padding = 950px

   Where scroll-driven timelines are supported the fade stops guessing entirely: an
   inactive timeline — which is what a container with nothing to scroll has — leaves the
   animation unapplied, so `opacity: 0` from the @supports block stands and no fade is
   painted. Scroll it, and the fade appears; reach the right-hand end, and it goes. No
   JavaScript, and no assumption about content.
   ------------------------------------------------------------------------- */

.esls-degree-compare__fade {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	width: 40px;
	pointer-events: none;
	/* `transparent` rather than a zero-alpha copy of the surface colour: an operator who
	   overrides `--esls-dc-surface` gets a correct fade from one property instead of
	   two, and no literal from the palette is duplicated here. Browsers have
	   interpolated gradients in premultiplied alpha for a decade, so the grey smear this
	   used to cause is not a live concern on any target device. */
	background: linear-gradient(to right, transparent, var(--esls-dc-surface));
}

/* Fallback floor, for engines without scroll-driven timelines. */

@media (min-width: 1024px) {
	.esls-degree-compare__fade {
		display: none;
	}
}

@supports (animation-timeline: --esls-dc-x) and (timeline-scope: --esls-dc-x) {
	.esls-degree-compare {
		/* Lets the fade, which is a sibling of the scroll container rather than a
		   descendant of it, name that container's timeline. */
		timeline-scope: --esls-dc-x;
	}

	.esls-degree-compare__scroll {
		scroll-timeline: --esls-dc-x inline;
	}

	.esls-degree-compare__fade {
		/* Nothing to scroll means an inactive timeline means this value stands. */
		opacity: 0;
		animation: esls-dc-edge-fade linear both;
		animation-timeline: --esls-dc-x;
	}

	/* The desktop floor is the fallback's job, not this one's; once the timeline is
	   measuring, a wide viewport with a table that still overflows must keep its fade. */
	@media (min-width: 1024px) {
		.esls-degree-compare__fade {
			display: block;
		}
	}
}

@keyframes esls-dc-edge-fade {
	0%   { opacity: 1; }
	88%  { opacity: 1; }
	100% { opacity: 0; }
}

/* -------------------------------------------------------------------------
   Responsive — §1.8, 320px floor

   The column budget at the floor, and it is a budget rather than a preference:

     320px viewport - 40px of section padding = 280px of usable width
     280px - 108px of pinned label            = 172px for the leading column
     column minimum                             150px, leaving 22px of slack

   That slack is what stops the last column being permanently clipped behind the pinned
   label at the right-hand end of the scroll — a defect the layout gate caught at 320px
   before these numbers were tightened, and one no amount of scrolling can get past
   because the scroll is already at its maximum. If either figure is raised, re-run the
   gate.
   ------------------------------------------------------------------------- */

@media (max-width: 767px) {
	.esls-degree-compare__col {
		padding: 14px 12px;
	}

	.esls-degree-compare__col-name {
		font-size: 19px;
	}

	.esls-degree-compare__cell {
		padding: 14px 12px;
		font-size: 15px;
	}

	.esls-degree-compare__label {
		padding: 14px 12px 14px 0;
		font-size: 11px;
		letter-spacing: .06em;
		/* Last resort against engine text inflation (iOS Dynamic Type): a label
		   that cannot fit its cell wraps inside it rather than painting over the
		   scrolled cells. `break-word`, not `anywhere`: `anywhere` collapses the
		   cell's min-content width and auto table layout then narrows the column. */
		overflow-wrap: break-word;
	}

	/* At 320px a 150px label column is nearly half the viewport. It narrows; it does
	   not stop being sticky, because a scrolled table with no visible row label is
	   unreadable in a way a slightly cramped label is not. */
	.esls-degree-compare {
		--esls-dc-label-w: 108px;
		--esls-dc-col-w: 150px;
	}
}

/* -------------------------------------------------------------------------
   Single-programme state — §5.9
   ------------------------------------------------------------------------- */

.esls-degree-compare__single {
	background: #FFFFFF;
	border: 1px solid var(--esls-border-warm);
	border-radius: var(--radius-md);
	padding: 24px;
	max-width: 560px;
}

.esls-degree-compare__single-name {
	font-family: "Fraunces", Georgia, serif;
	font-size: 24px;
	font-weight: 600;
	line-height: 1.2;
	color: var(--esls-text-primary);
	margin: 0;
}

.esls-degree-compare__single-full {
	font-family: "Source Sans 3", system-ui, sans-serif;
	font-size: 15px;
	color: var(--esls-text-secondary);
	margin: 4px 0 0;
}

.esls-degree-compare__spec {
	font-family: "Source Sans 3", system-ui, sans-serif;
	margin: 20px 0 0;
}

.esls-degree-compare__spec-term {
	font-size: 13px;
	font-weight: 700;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--esls-text-secondary);
	margin: 16px 0 0;
}

.esls-degree-compare__spec-term:first-child {
	margin-top: 0;
}

.esls-degree-compare__spec-value {
	font-size: 16px;
	line-height: 1.5;
	color: var(--esls-text-primary);
	margin: 4px 0 0;
}

.esls-degree-compare__single .esls-degree-compare__cta {
	margin-top: 24px;
}

/* -------------------------------------------------------------------------
   Editor-only notice
   ------------------------------------------------------------------------- */

.esls-degree-compare--notice {
	font-family: "Source Sans 3", system-ui, sans-serif;
	border: 1px dashed var(--esls-border-warm);
	border-radius: var(--radius-md);
	padding: 20px 24px;
	background: var(--esls-cream-alt);
}

.esls-degree-compare__notice-title {
	font-size: 12px;
	font-weight: 700;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--esls-text-tertiary);
	margin: 0 0 8px;
}

.esls-degree-compare__notice-body {
	font-size: 15px;
	color: var(--esls-text-primary);
	margin: 0 0 8px;
}

.esls-degree-compare__notice-foot {
	font-size: 13px;
	color: var(--esls-text-secondary);
	margin: 0;
}

/* -------------------------------------------------------------------------
   Focus — §1.7

   Orange fails the 3:1 non-text minimum on this palette (2.96:1 on white, 2.79:1 on
   cream). Blue-800 scores 9.76:1 on cream and carries focus throughout.
   ------------------------------------------------------------------------- */

.esls-degree-compare :focus-visible {
	outline: 2px solid var(--esls-blue-800);
	outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
	.esls-degree-compare__cta {
		transition: none;
	}
}
