/**
 * Catalogue, book card, product page.
 * Logical properties only - no physical left/right in flow layout.
 */

/* ---- Grid --------------------------------------------------------------- */

/* Gap is 16px, measured off both prototype grids: the homepage row (1152 wide, three
   373.33px columns) and the catalogue (868 wide, three 278.66px). It was 20px. */
.jd-grid--books {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--jd-space-8);
}

@media (max-width: 1080px) { .jd-grid--books { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 768px)  { .jd-grid--books { grid-template-columns: 1fr; } }

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

.jd-book {
	display: flex;
	flex-direction: column;
	background-color: var(--jd-surface);
	border: var(--jd-border);
	border-radius: var(--jd-radius-card);
	box-shadow: var(--jd-shadow-card);
	overflow: hidden;
	transition: border-color var(--jd-transition);
}

.jd-book:hover { border-color: var(--jd-hairline-strong); }

/* Covers stand on a shelf: a paper panel closed by a hairline. */
.jd-book__coverlink {
	display: grid;
	place-items: center;
	padding: var(--jd-space-12) var(--jd-space-10);
	background-color: var(--jd-paper);
	border-block-end: var(--jd-border);
	min-block-size: 220px;
}

.jd-book__cover {
	max-block-size: 180px;
	inline-size: auto;
	object-fit: contain;
}

/* Roughly two-thirds of the catalogue has no cover image, so this is the common
   case rather than an edge case. A navy plate carrying the title reads as a
   deliberate binding; a broken-image icon would dominate the shop page. */
.jd-book__cover--fallback {
	display: grid;
	place-items: center;
	inline-size: 128px;
	block-size: 180px;
	padding: var(--jd-space-8);
	background-color: var(--jd-navy);
	color: var(--jd-on-navy);
	font-size: var(--jd-fs-2xs);
	line-height: 1.45;
	text-align: center;
}

.jd-book__body {
	display: flex;
	flex-direction: column;
	gap: var(--jd-space-5);
	padding: var(--jd-space-10);
	flex: 1 1 auto;
}

.jd-book__title {
	font-family: var(--jd-font-latin);
	font-size: var(--jd-fs-base);
	font-weight: 500;
	line-height: 1.4;
	color: var(--jd-ink);
}

.jd-book__title a { color: inherit; }

/* Rules ABOVE and BELOW, 6px/1px inside them - el.92 (screen 02) and el.113 (screen 01)
   both measure the biblio row as a 29px band closed on both edges, not an underlined
   caption. `line-height: normal` for the same reason: the prototype leaves it unset and
   --jd-lh-body was stretching the row to 17.85px. */
.jd-book__biblio {
	margin-block: var(--jd-space-5);
	padding: var(--jd-space-3) 1px;
	border-block: var(--jd-border);
	line-height: normal;
}

.jd-book__sep { margin-inline: var(--jd-space-3); }

/* Price over the VAT line in ONE column, the tag beside the pair and top-aligned with the
   figure - el.96-102. `align-items: center` had the tag floating against the middle of a
   two-line block. */
.jd-book__pricerow {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: var(--jd-space-4);
	margin-block: var(--jd-space-1) var(--jd-space-6);
	flex-wrap: wrap;
}

.jd-book__pricecol { min-inline-size: 0; }

.jd-book__pricerow .price,
.jd-book__pricerow .woocommerce-Price-amount {
	font-family: var(--jd-font-mono);
	font-variant-numeric: tabular-nums;
	font-size: var(--jd-fs-lg);
	font-weight: 500;
	line-height: normal;
	color: var(--jd-navy);
}

.jd-book__terms {
	font-size: var(--jd-fs-3xs);
	line-height: normal;
	color: var(--jd-text-muted);
	margin-block-start: var(--jd-space-1);
}

/*
 * The card CTA is a full-width block, not a padded pill: the prototype sizes it 339x44 —
 * the card's whole inner width - with only 6px of inline padding, 14px text and a
 * transparent border that reserves the same box the hover state paints (el.125/143/161).
 * The generic .jd-btn--primary is a standalone button (16px text, 24px inline padding), so
 * it has to be narrowed here rather than changed globally, which would shrink every other
 * primary button on the site.
 */
.jd-book__add {
	margin-block-start: auto;
	inline-size: 100%;
	font-size: var(--jd-fs-sm);
	line-height: normal;
	padding-inline: var(--jd-space-4);
	border-color: transparent;
}

.jd-book__add:hover { border-color: transparent; }

.woocommerce .jd-book a.jd-book__portal {
	background-color: transparent;
	border-color: var(--jd-navy);
	color: var(--jd-navy);
}

.woocommerce .jd-book a.jd-book__portal:hover {
	background-color: var(--jd-navy);
	border-color: var(--jd-navy);
	color: var(--jd-on-navy);
	text-decoration: none;
}

.jd-chip {
	display: inline-flex;
	align-items: center;
	font-size: var(--jd-fs-2xs);
	padding: var(--jd-space-3) var(--jd-space-6);
	border: var(--jd-border);
	border-radius: var(--jd-radius-tag);
	color: var(--jd-text-secondary);
}

.jd-chip:hover {
	border-color: var(--jd-hairline-strong);
	color: var(--jd-navy);
	text-decoration: none;
}

/* ---- Catalogue layout --------------------------------------------------- */

/* store.dc.html:361 - `padding:34px 24px 72px` on the screen container. */
.jd-catalog { padding-block: 34px 72px; }

.jd-catalog__head { margin-block-end: 0; }

/*
 * The head is ONE row: the 221-wide title block against a 195-wide meta block, their
 * baselines aligned, then an 8px gap and the hairline (el.34-40). The count and the sort
 * control used to sit in a toolbar of their own inside the results column, 868 wide and
 * 25px lower, which also stretched the kicker and the H1 to the full 1152.
 */
.jd-catalog__headrow {
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--jd-space-8);
	flex-wrap: wrap;
	margin-block-end: var(--jd-space-4);
}

.jd-catalog__headmain { min-inline-size: 0; }

.jd-catalog__kicker {
	letter-spacing: var(--jd-track-wide);
	line-height: normal;
	margin-block-end: var(--jd-space-2);
}

.jd-catalog__title {
	font-size: var(--jd-fs-display);
	line-height: 1.4;
}

.jd-catalog__meta {
	display: flex;
	align-items: center;
	gap: var(--jd-space-6);
}

.jd-catalog__meta .woocommerce-ordering { margin: 0; }

.jd-catalog__count {
	font-size: 12.5px;
	line-height: normal;
	color: var(--jd-text-secondary);
	white-space: nowrap;
}

.jd-catalog__count .jd-mono { font-size: 11.5px; }

/* el.40 - a 1px top border, 14px above it and 24px below. */
.jd-catalog__rule {
	border-block-start: var(--jd-border);
	margin-block: var(--jd-space-7) var(--jd-space-12);
}

/* ---- University portal head (prototype screen 09) -----------------------
 * Same archive, different head: a breadcrumb instead of the kicker, and the term
 * description set in a hairline strip rather than as running intro text.
 */

.jd-catalog--portal { padding-block: var(--jd-space-13) 72px; }

.jd-crumbs {
	font-size: var(--jd-fs-2xs);
	line-height: normal;
	color: var(--jd-text-muted);
	margin-block-end: 14px;
}

.jd-crumbs a { color: var(--jd-text-secondary); }
.jd-crumbs a:hover { color: var(--jd-navy); }
.jd-crumbs [aria-current="page"] { color: var(--jd-ink); }

.jd-crumbs__sep {
	margin-inline: 8px;
	color: var(--jd-hairline);
}

.jd-catalog__head--portal .jd-catalog__title {
	font-size: 31px;
	line-height: var(--jd-lh-title);
	margin-block-end: 10px;
}

.jd-catalog__head--portal .jd-catalog__headrow { margin-block-end: 0; }
.jd-catalog__head--portal-no-description { margin-block-end: var(--jd-space-13); }

.jd-catalog__intro--strip {
	border-block: 1px solid var(--jd-hairline);
	padding-block: 10px;
	padding-inline: 2px;
	font-size: 11.5px;
	letter-spacing: .06em;
	color: var(--jd-text-secondary);
	margin-block-end: var(--jd-space-13);
}

.jd-catalog__intro--strip p { margin: 0; }

/* ---- Protected portal login (prototype screen 06) ----------------------
 * The archive head above already owns the breadcrumb, H1 and partnership strip.
 * These measurements begin at the centred 520px gate column (06 el.42-53).
 */

.jd-gate__col {
	max-inline-size: 520px;
	margin-inline: auto;
}

.jd-gate__card {
	background-color: var(--jd-surface);
	border: var(--jd-border);
	border-radius: var(--jd-radius-card);
	box-shadow: var(--jd-shadow-card);
	padding: var(--jd-space-13);
}

.jd-gate__title {
	display: flex;
	align-items: center;
	gap: var(--jd-space-5);
	font-size: 21px;
	line-height: normal;
	margin: 0 0 var(--jd-space-5);
}

.jd-gate__lock { display: inline-flex; color: var(--jd-navy); }

.jd-gate__lede {
	border-block: var(--jd-border);
	padding-block: 9px;
	padding-inline: var(--jd-space-1);
	font-size: var(--jd-fs-2xs);
	color: var(--jd-text-secondary);
	line-height: 2;
	margin: 0 0 var(--jd-space-9);
}

.jd-gate__message,
.jd-gate__replacement,
.jd-gate__account-note,
.jd-gate__provisioning {
	font-size: 11.5px;
	line-height: 1.9;
	color: var(--jd-text-secondary);
}

.jd-gate__message,
.jd-gate__replacement {
	padding: var(--jd-space-5) var(--jd-space-6);
	border: var(--jd-border);
	border-radius: var(--jd-radius-btn);
	margin-block: 0 var(--jd-space-7);
}

.jd-gate__message--error { color: var(--jd-danger); }
.jd-gate__replacement { color: var(--jd-navy); }
.jd-gate__account-note { margin: 0 0 var(--jd-space-7); }
.jd-gate__provisioning { margin: var(--jd-space-6) 0 0; }

.jd-gate__help {
	font-size: 11.5px;
	color: var(--jd-text-secondary);
	line-height: 1.9;
	margin-block: var(--jd-space-6) 0;
}

.jd-gate__help a {
	color: var(--jd-navy);
	font-weight: 500;
	border-block-end: 1px solid var(--jd-navy);
}

.jd-gate__help a:hover { text-decoration: none; }

.jd-btn.jd-gate__browse {
	display: flex;
	inline-size: 100%;
	margin-block-start: var(--jd-space-7);
	min-block-size: 46px;
	background-color: var(--jd-surface);
	font-size: var(--jd-fs-xs);
	font-weight: 600;
	line-height: normal;
	padding-block: 1px;
	padding-inline: var(--jd-space-3);
}

.jd-btn.jd-gate__browse:hover {
	border-color: var(--jd-navy);
	color: var(--jd-navy);
	text-decoration: none;
}

/* ---- University portal drill-down (prototype screens 07 and 08) -------- */

.jd-portal { margin-block-end: 0; }

.jd-portal__path {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--jd-space-4);
	margin-block: 0 var(--jd-space-8);
	font-size: var(--jd-fs-2xs);
	line-height: normal;
	color: var(--jd-text-secondary);
}

.jd-portal__pathlabel {
	font-size: 10px;
	letter-spacing: var(--jd-track-label);
	color: var(--jd-text-muted);
}

.jd-portal__crumb {
	font-size: var(--jd-fs-2xs);
	font-weight: 500;
	color: var(--jd-navy);
	border-block-end: 1px solid transparent;
}

a.jd-portal__crumb:hover {
	color: var(--jd-navy);
	border-block-end-color: var(--jd-navy);
	text-decoration: none;
}

.jd-portal__sep {
	font-size: var(--jd-fs-2xs);
	color: var(--jd-hairline);
}

.jd-portal__list {
	list-style: none;
	margin: 0;
	padding-block: var(--jd-space-2);
	padding-inline: var(--jd-space-9);
	background-color: var(--jd-surface);
	border: var(--jd-border);
	border-radius: var(--jd-radius-card);
}

.jd-portal__link {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--jd-space-6);
	padding-block: var(--jd-space-7);
	padding-inline: var(--jd-space-2);
	border-block-end: 1px solid var(--jd-paper-deep);
	line-height: normal;
	color: var(--jd-ink);
}

.jd-portal__link:hover {
	background-color: var(--jd-paper);
	color: var(--jd-navy);
	text-decoration: none;
}

.jd-portal__name {
	font-size: var(--jd-fs-sm);
	font-weight: 600;
	color: var(--jd-navy);
}

.jd-portal__meta {
	display: inline-flex;
	align-items: center;
	gap: var(--jd-space-4);
	flex-shrink: 0;
}

.jd-portal__lock {
	display: inline-flex;
	align-items: center;
	gap: var(--jd-space-3);
	border: 1px solid rgb(24 41 94 / .35);
	border-radius: var(--jd-radius-tag);
	padding-block: var(--jd-space-1);
	padding-inline: 9px;
	font-size: 10px;
	font-weight: 500;
	line-height: normal;
	color: var(--jd-navy);
	white-space: nowrap;
}

.jd-portal__count {
	font-size: var(--jd-fs-3xs);
	color: var(--jd-text-muted);
}

.jd-portal__count .jd-mono { font-size: 10px; }

.jd-portal__arrow {
	font-size: var(--jd-fs-2xs);
	color: var(--jd-text-muted);
}

.jd-portal__arrow::before { content: "←"; }
[dir="ltr"] .jd-portal__arrow::before { content: "→"; }

.jd-portal__note {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: center;
	gap: var(--jd-space-7);
	margin-block-start: 34px;
	padding: 13px;
	border-block: var(--jd-border);
	font-size: 12.5px;
	line-height: normal;
	color: var(--jd-text-secondary);
}

.jd-portal + .jd-portal__note { margin-block-start: 30px; }
.jd-portal__note-sep { color: var(--jd-hairline); }

.jd-portal__note-link {
	font-weight: 500;
	color: var(--jd-navy);
	border-block-end: 1px solid transparent;
}

a.jd-portal__note-link:hover {
	color: var(--jd-navy);
	border-block-end-color: var(--jd-navy);
	text-decoration: none;
}

/* ---- Portal empty state (PENDING-DECISIONS #2) ------------------------- */

.jd-portal-empty {
	padding: 52px;
	text-align: center;
	background-color: var(--jd-surface);
	border: var(--jd-border);
	border-radius: var(--jd-radius-card);
}

.jd-portal-empty__title {
	font-size: 24px;
	line-height: normal;
	color: var(--jd-navy);
	margin-block-end: var(--jd-space-4);
}

.jd-portal-empty__body {
	max-inline-size: 460px;
	margin: 0 auto var(--jd-space-10);
	font-size: var(--jd-fs-xs);
	line-height: 2;
	color: var(--jd-text-secondary);
}

.jd-portal-empty__actions {
	display: flex;
	justify-content: center;
	gap: var(--jd-space-5);
	flex-wrap: wrap;
}

.jd-portal-empty__action {
	block-size: 44px;
	padding-inline: var(--jd-space-11);
	font-size: var(--jd-fs-xs);
	font-weight: 600;
}

.jd-portal-empty .jd-btn--primary { border-color: transparent; }
.jd-portal-empty .jd-btn--hairline { background-color: var(--jd-surface); }

.jd-portal-empty .jd-btn--hairline:hover {
	border-color: var(--jd-navy);
	transform: translateY(-1px);
}

.jd-portal-empty__action:disabled { cursor: default; }

/* ---- Compact rows for genuine hierarchy leaves ------------------------ */

.jd-booklist {
	padding: var(--jd-space-2) var(--jd-space-9);
	background-color: var(--jd-surface);
	border: var(--jd-border);
	border-radius: var(--jd-radius-card);
	box-shadow: var(--jd-shadow-card);
}

/*
 * `~`, not `+`: WooCommerce prints an always-present `.woocommerce-notices-wrapper`
 * between the two on the taxonomy archive. It is empty and zero-height, so the page
 * looked like the rule was wrong when it was simply never matching, and the child
 * departments sat flush against the first book row.
 */
.jd-portal ~ .jd-booklist { margin-block-start: var(--jd-space-8); }

/* DERIVED: see PENDING-DECISIONS #67 — the prototype's portal screens do not paginate,
 * so there is no measured row for this gap. Reuses the token the block above it already
 * uses, rather than introducing a number. */
.jd-booklist ~ .woocommerce-pagination { margin-block-start: var(--jd-space-8); }

.jd-booklist__row {
	display: flex;
	align-items: center;
	gap: var(--jd-space-7);
	padding-block: 13px;
	padding-inline: var(--jd-space-2);
	border-block-end: 1px solid var(--jd-paper-deep);
}

.jd-booklist__plate {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 44px;
	inline-size: 44px;
	block-size: 58px;
	padding: 3px;
	background-color: var(--jd-paper);
	border: var(--jd-border);
	border-radius: var(--jd-radius-tag);
}

.jd-booklist__cover {
	max-inline-size: 36px;
	max-block-size: 50px;
	object-fit: contain;
}

.jd-booklist__fallback {
	font-size: 7px;
	line-height: 1.4;
	text-align: center;
	color: var(--jd-text-secondary);
}

.jd-booklist__main {
	flex: 1 1 auto;
	min-inline-size: 0;
}

.jd-booklist__title {
	margin: 0;
	font-family: var(--jd-font-latin);
	font-size: 15px;
	font-weight: 400;
	line-height: 1.4;
	color: var(--jd-ink);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.jd-booklist__title a { color: inherit; }

.jd-booklist__biblio {
	display: flex;
	align-items: baseline;
	gap: var(--jd-space-2);
	margin-block-start: 3px;
	font-size: 10px;
	line-height: normal;
	letter-spacing: .08em;
	color: var(--jd-text-secondary);
}

.jd-booklist__code {
	flex-shrink: 0;
	padding: 3px var(--jd-space-4);
	font-size: 10px;
	line-height: normal;
	letter-spacing: .06em;
	color: var(--jd-text-secondary);
	border: var(--jd-border);
	border-radius: var(--jd-radius-tag);
}

.jd-booklist .jd-tag { flex-shrink: 0; }
.jd-booklist .jd-tag--digital { border-color: rgb(27 94 67 / .4); }
.jd-booklist .jd-tag--print { border-color: rgb(24 41 94 / .3); }

.jd-booklist__price,
.jd-booklist__price .woocommerce-Price-amount {
	flex-shrink: 0;
	margin: 0;
	font-family: var(--jd-font-mono);
	font-size: 14.5px;
	font-weight: 500;
	line-height: normal;
	font-variant-numeric: tabular-nums;
	color: var(--jd-navy);
}

.woocommerce .jd-booklist__row a.jd-btn.jd-btn--primary {
	flex-shrink: 0;
	min-block-size: 36px;
	block-size: 36px;
	padding-inline: var(--jd-space-8);
	font-size: var(--jd-fs-2xs);
	font-weight: 600;
}

.woocommerce .jd-booklist__row a.jd-booklist__portal {
	flex-shrink: 0;
	min-block-size: 36px;
	block-size: 36px;
	padding-inline: var(--jd-space-7);
	border-color: var(--jd-navy);
	background-color: transparent;
	color: var(--jd-navy);
	font-size: var(--jd-fs-2xs);
	font-weight: 600;
}

.woocommerce .jd-booklist__row a.jd-booklist__portal:hover {
	background-color: var(--jd-navy);
	color: var(--jd-on-navy);
	text-decoration: none;
}

/* 260px sidebar + 24px gap + 868px results = 1152, the prototype's exact catalogue row. */
.jd-catalog__layout {
	display: grid;
	grid-template-columns: 260px minmax(0, 1fr);
	gap: var(--jd-space-12);
	align-items: start;
}

@media (max-width: 1080px) {
	.jd-catalog__layout { grid-template-columns: 1fr; }
}

/* ---- Filters ------------------------------------------------------------ */

/* el.41 - 260x595, surface on a hairline, 18px/20px inside, sticky 96 below the header. */
.jd-filters {
	position: sticky;
	inset-block-start: 96px;
	background-color: var(--jd-surface);
	border: var(--jd-border);
	border-radius: var(--jd-radius-card);
	padding: var(--jd-space-9) var(--jd-space-10);
}

/* el.42/43 - no rule under the head; 14px of air is the whole separation. */
.jd-filters__head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	margin-block-end: var(--jd-space-7);
}

/* 14/600 in the UI sans, not the 16/700 Amiri of a section title (el.42). */
.jd-filters__title {
	font-family: var(--jd-font-ui);
	font-size: var(--jd-fs-sm);
	font-weight: 600;
	line-height: normal;
	color: var(--jd-navy);
}

/* el.43 - 11.5/500, on a 1px rule that is TRANSPARENT at rest and navy on hover
   (store.dc.html:384). The reserved border is what stops the row shifting on hover. */
.jd-filters__clear {
	font-size: 11.5px;
	font-weight: 500;
	line-height: normal;
	color: var(--jd-text-secondary);
	border-block-end: 1px solid transparent;
}

.jd-filters__clear:hover {
	color: var(--jd-navy);
	border-block-end-color: var(--jd-navy);
	text-decoration: none;
}

.jd-filters__group {
	border: 0;
	margin: 0;
	padding: 0;
	min-inline-size: 0;
}

/* el.44/52/75 - 10px tracked .14em in the muted grey, over the full column width. A
   <legend> shrink-wraps to its text unless it is told otherwise, which is why «الناشر»
   measured 21px wide where the prototype measures 218. */
.jd-filters__legend {
	display: block;
	inline-size: 100%;
	font-size: 10px;
	letter-spacing: var(--jd-track-label);
	line-height: normal;
	color: var(--jd-text-muted);
	margin-block-end: var(--jd-space-4);
	padding: 0;
}

/* el.55/69 - the two groups whose control is a list, not a row, get 10px. */
.jd-filters__legend--loose { margin-block-end: var(--jd-space-5); }

/* el.51/54/68/74 - 1px of hairline between groups, 16px under it. */
.jd-filters__rule {
	block-size: 1px;
	background-color: var(--jd-hairline);
	margin-block-end: var(--jd-space-8);
}

/* el.53 - 40px, surface, 12.5/500 navy, 10px of inline padding. */
.jd-filters__select {
	inline-size: 100%;
	block-size: 40px;
	font-size: 12.5px;
	font-weight: 500;
	color: var(--jd-navy);
	padding-inline: var(--jd-space-5);
	margin-block-end: var(--jd-space-9);
	background-color: var(--jd-surface);
	border: var(--jd-border);
	border-radius: var(--jd-radius-btn);
	cursor: pointer;
}

.jd-pills {
	display: flex;
	gap: var(--jd-space-3);
	margin-block-end: var(--jd-space-9);
}

.jd-pills--chips { flex-wrap: wrap; margin-block-end: 0; }
.jd-pills--chips .jd-pill { flex: 0 0 auto; }

/* The input stays in the DOM for keyboard and screen-reader use; only its box is
   visually hidden. display:none would remove it from the tab order entirely. */
.jd-pill input {
	position: absolute;
	opacity: 0;
	inline-size: 1px;
	block-size: 1px;
}

.jd-pill {
	flex: 1 1 auto;
	text-align: center;
	cursor: pointer;
}

/* el.45-50 - three equal 69x31 pills: 6px of block padding over 11.5/500, radius 6. The
   old 36px line-height made them 38 tall and the type a size too large. */
.jd-pill span {
	display: block;
	padding-block: var(--jd-space-3);
	font-size: 11.5px;
	font-weight: 500;
	line-height: normal;
	color: var(--jd-text-secondary);
	background-color: var(--jd-surface);
	border: var(--jd-border);
	border-radius: var(--jd-radius-btn);
	transition: background-color var(--jd-transition), color var(--jd-transition);
}

/* el.76-87 - the level chips are a different object: 4/11 padding, radius 4, 10.5px. */
.jd-pills--chips .jd-pill span {
	padding: var(--jd-space-2) 11px;
	font-size: var(--jd-fs-3xs);
	border-radius: var(--jd-radius-tag);
}

.jd-pill.is-active span,
.jd-pill input:checked + span {
	background-color: var(--jd-navy);
	border-color: var(--jd-navy);
	color: var(--jd-on-navy);
}

.jd-pill input:focus-visible + span {
	outline: 2px solid var(--jd-navy);
	outline-offset: 2px;
}

/* el.56-67 - a 9px column, each row 18px tall: box, name, count. */
.jd-checklist {
	display: flex;
	flex-direction: column;
	gap: 9px;
	margin-block-end: var(--jd-space-9);
}

.jd-checklist__row {
	display: flex;
	align-items: center;
	gap: 9px;
	font-size: var(--jd-fs-xs);
	line-height: normal;
	cursor: pointer;
}

/* el.56 - 16x16 on the surface with a 3px radius. The native control renders 13x13 and
   ignores every one of those values. */
.jd-checklist__row input[type="checkbox"] {
	appearance: none;
	flex: 0 0 16px;
	inline-size: 16px;
	block-size: 16px;
	margin: 0;
	display: grid;
	place-items: center;
	background-color: var(--jd-surface);
	border: var(--jd-border);
	border-radius: var(--jd-radius-xs);
	cursor: pointer;
}

.jd-checklist__row input[type="checkbox"]:checked {
	background-color: var(--jd-navy);
	border-color: var(--jd-navy);
}

.jd-checklist__row input[type="checkbox"]:checked::after {
	content: "";
	inline-size: 10px;
	block-size: 10px;
	background-color: var(--jd-on-navy);
	clip-path: polygon(41% 76%, 12% 47%, 21% 38%, 41% 58%, 79% 20%, 88% 29%);
}

.jd-checklist__row input[type="checkbox"]:focus-visible {
	outline: 2px solid var(--jd-navy);
	outline-offset: 2px;
}

/* el.57 - the book face at 14px, the same as the publisher plates on screen 14. */
.jd-checklist__name {
	flex: 1 1 auto;
	font-size: var(--jd-fs-sm);
	line-height: normal;
	color: var(--jd-ink);
}

.jd-checklist__count {
	flex: 0 0 auto;
	font-size: 10px;
	line-height: normal;
	color: var(--jd-text-muted);
}

/* el.70-73 - one range for the ceiling, the two bounds under it: the floor in muted mono,
   the live ceiling in navy mono inside «حتى … ر.س». */
.jd-filters__range {
	display: block;
	inline-size: 100%;
	accent-color: var(--jd-navy);
	cursor: pointer;
}

.jd-filters__pricerow {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	font-size: 11px;
	line-height: normal;
	color: var(--jd-text-secondary);
	margin-block: var(--jd-space-2) var(--jd-space-9);
}

.jd-filters__pricemin { font-size: 10px; }
.jd-filters__pricerow [data-jd-price-out] { color: var(--jd-navy); }

/*
 * el.78 - the sheet's own apply button, and el.30 the toggle that opens it. Both belong
 * to the sub-768 layout only; above it the panel is always on screen and the change
 * handler submits by itself, so neither is rendered at all.
 */
.jd-catalog__filtertoggle,
.jd-filters__apply { display: none; }

/* ---- The catalogue's book card ------------------------------------------
 *
 * The prototype draws TWO sizes of the same card. The homepage rail (store.dc.html:240)
 * is the larger one - 188px of cover, 13/16/16 of body, 16px title, 20px price - and it
 * is what the shared .jd-book rules above carry. The catalogue's (store.dc.html:443) is
 * one step down at every measure, so it is scoped here rather than fought over globally:
 * el.89-103 give 172px of cover, 12/15/15 of body, a 15px title on a 44px floor, a 19px
 * figure and a 42px button. The 20px body padding was what left the CTA 10px narrower
 * than the 247 the prototype measures.
 */

.jd-catalog__results .jd-book__coverlink {
	display: flex;
	align-items: flex-end;
	justify-content: center;
	block-size: 172px;
	min-block-size: 0;
	padding: var(--jd-space-9) var(--jd-space-9) 0;
}

.jd-catalog__results .jd-book__cover { max-block-size: 138px; }

.jd-catalog__results .jd-book__cover--fallback {
	inline-size: 96px;
	block-size: 136px;
	padding: var(--jd-space-5);
	font-size: 11px;
	line-height: 1.5;
}

.jd-catalog__results .jd-book__body {
	gap: 0;
	padding: var(--jd-space-6) 15px 15px;
}

.jd-catalog__results .jd-book__title {
	font-size: 15px;
	line-height: 1.45;
	min-block-size: 44px;
}

.jd-catalog__results .jd-book__biblio {
	font-size: 10px;
	margin-block: 9px;
}

.jd-catalog__results .jd-book__pricerow { margin-block: var(--jd-space-1) 11px; }
.jd-catalog__results .jd-book__pricerow .woocommerce-Price-amount { font-size: 19px; }
.jd-catalog__results .jd-book__terms { font-size: 10px; }

/* ---- Catalogue at 1080 and below ---------------------------------------- */

@media (max-width: 1080px) {
	/* store.dc.html:2635 - the sidebar stacks above the results from 1080 down, but it is
	   still an ordinary card until 768; only the grid changes here. */
	.jd-filters { position: static; }
}

@media (max-width: 768px) {
	/*
	 * el.31 - below 768 the panel is a bottom sheet: fixed, full width, rounded at the
	 * top only, and TRANSLATED off-screen when closed rather than display:none, which is
	 * exactly what the prototype does (transform: translateY(105%)). Hiding it instead
	 * would remove every filter control from the accessibility tree and from the page.
	 */
	.jd-filters {
		position: fixed;
		inset-inline: 0;
		inset-block-end: 0;
		z-index: 80;
		max-block-size: 72vh;
		overflow-y: auto;
		border: 0;
		border-block-start: var(--jd-border);
		border-radius: 12px 12px 0 0;
		box-shadow: 0 -1px 2px rgb(24 41 94 / .08);
		transform: translateY(105%);
		transition: transform .25s ease-out;
	}

	.jd-filters.is-open { transform: translateY(0); }

	/* el.30 - 46px, surface on a hairline, 13/600 navy. */
	.jd-catalog__filtertoggle {
		display: block;
		inline-size: 100%;
		block-size: 46px;
		margin-block-end: var(--jd-space-8);
		font-family: var(--jd-font-ui);
		font-size: var(--jd-fs-xs);
		font-weight: 600;
		line-height: normal;
		color: var(--jd-navy);
		background-color: var(--jd-surface);
		border: var(--jd-border);
		border-radius: var(--jd-radius-btn);
		cursor: pointer;
	}

	/* el.78/79 - 48px navy, 14/600 on 6px of inline padding over a transparent border,
	   the count in mono at 12. .jd-btn--primary's own 24px padding and navy border are
	   the standalone-button values and are too wide for a full-width control. */
	.jd-filters__apply {
		display: flex;
		inline-size: 100%;
		block-size: 48px;
		margin-block-start: var(--jd-space-9);
		font-size: var(--jd-fs-sm);
		line-height: normal;
		padding-inline: var(--jd-space-3);
		border-color: transparent;
	}

	.jd-filters__apply .jd-mono { font-size: var(--jd-fs-2xs); font-weight: 600; }
}

@media (prefers-reduced-motion: reduce) {
	.jd-filters { transition: none; }
}

/* ---- Empty state -------------------------------------------------------- */

.jd-empty {
	padding: var(--jd-space-24) var(--jd-space-12);
	text-align: center;
	border: 1px dashed var(--jd-hairline);
	border-radius: var(--jd-radius-card);
}

.jd-empty__title { font-size: var(--jd-fs-title); margin-block-end: var(--jd-space-6); }
.jd-empty__body { color: var(--jd-text-secondary); margin-block-end: var(--jd-space-10); }

/* ---- Breadcrumb --------------------------------------------------------- */

/* Core emits the trail on woocommerce_before_main_content at priority 20, unwrapped: the
   <nav> ran the full viewport width while everything it labels stops at the 1200px column.
   aljadawel2026_breadcrumb_open()/_close() bracket it at 19/21 - see inc/woocommerce.php.

   Two typographies on one element, and no extra markup to carry them. global/breadcrumb.php
   prints every crumb NAME through esc_html(), so a <span> returned from
   woocommerce_get_breadcrumb would appear on the page as literal angle brackets; only the
   delimiter goes through wp_kses_post(). So the last crumb - a bare text node - takes the
   nav's own font [el.38], and the links override it [el.34/36]. */
.jd-crumbs { padding-block: var(--jd-space-13) 0; }   /* 26px - el.34 sits at y=151 under an 125px header */

.woocommerce .jd-crumbs .woocommerce-breadcrumb {
	margin: 0;
	font-family: var(--jd-font-latin);
	font-size: 13px;
	line-height: normal;
	color: var(--jd-ink);
}

.woocommerce .jd-crumbs .woocommerce-breadcrumb a {
	font-family: var(--jd-font-ui);
	font-size: 12px;
	color: var(--jd-text-secondary);
}

.woocommerce .jd-crumbs .woocommerce-breadcrumb a:hover { color: var(--jd-navy); }

/* 10px, not the 8px step: el.34/35/36 measure 10 and 11 alternating across the four gaps,
   which is one 10.5px margin rounding either way. 10px is the token nearest that. */
.jd-crumbs__sep {
	font-family: var(--jd-font-ui);
	font-size: 12px;
	color: var(--jd-hairline);
	margin-inline: var(--jd-space-5);
}

/* ---- Product page ------------------------------------------------------- */

/* 430px + 1fr, gap 40px - store.dc.html:2622 (`prodGridStyle`). It shipped as
   1fr/1fr, which gave the cover half the page and squeezed the title into three lines
   where the prototype takes two. Neither value is on the spacing scale; the prototype's
   gaps often are not, and the scale follows the prototype rather than the reverse. */
.jd-product__top {
	display: grid;
	grid-template-columns: 430px minmax(0, 1fr);
	gap: 40px;
	padding-block: var(--jd-space-16);
	align-items: start;
}

@media (max-width: 1080px) {
	.jd-product__top { grid-template-columns: 1fr; gap: var(--jd-space-12); }
}

/* The cover sits ON the card's bottom hairline rather than floating in the middle of
   it - store.dc.html:492. min-block-size, not the prototype's fixed height, because
   WooCommerce's gallery carries flexslider and photoswipe markup whose own sizing a
   hard height would fight. */
.jd-product__gallery {
	background-color: var(--jd-surface);
	border: var(--jd-border);
	border-radius: var(--jd-radius-card);
	/* 36px on three sides, and the one shadow this design owns - [el.39]. It shipped at
	   32px with no shadow, which floated the plate off the page by 4px on each side. */
	padding-block: 36px 0;
	padding-inline: 36px;
	box-shadow: var(--jd-shadow-card);
	min-block-size: 430px;
	display: flex;
	align-items: flex-end;
	justify-content: center;
}

/* woocommerce-layout.css floats this box at 48% of whatever contains it
   (`.woocommerce div.product div.images`, 0,3,1 - the gallery also carries the class
   `images`), so `inline-size: 100%` at 0,2,0 never applied and the plate held a 171px
   column: 48% of the 358px inner width. Beat it on specificity rather than drop the
   sheet, which the OTP button still relies on. */
.woocommerce div.product .jd-product__gallery > div.woocommerce-product-gallery {
	float: none;
	inline-size: 100%;
	margin-block-end: 0;
	border-block-end: var(--jd-border);
}

/* The cover stands 330px tall on the plate's hairline instead of rendering at its
   intrinsic size - [el.41: 263x330 @1440 · el.30: 198x330 @390]. The WIDTH is the source
   file's aspect ratio, so it is data, not a value to set. `object-fit` only matters when
   max-inline-size clamps a wide source at 390. Beats
   `.woocommerce div.product div.images img { width: 100% }` (0,3,2). */
.woocommerce div.product .jd-product__gallery .woocommerce-product-gallery__image img {
	/* The prototype DECLARES the cover box, it does not derive it from an image: el.41 is
	   263x330 at 1440 and el.30 is 198x330 at 390 - same height, different aspect (0.797 vs
	   0.600), which no single source file can produce. So the box is the contract and
	   `object-fit: contain` fits whatever the store has into it.

	   Height alone is not enough. With `inline-size: auto` a SQUARE source paints 330x330 and
	   overruns the prototype's 263 by 67px, which is measurable: screen 03 went 16.32% ->
	   16.78% at 1440 on this rule alone. Staging's cover is a 171x171 composite; production's
	   are portrait. For any portrait cover the two forms paint identically - `contain` is
	   height-limited either way - so clamping costs real data nothing and stops the
	   placeholder from inflating both product screens. */
	inline-size: 263px;
	block-size: 330px;
	max-inline-size: 100%;
	margin-inline: auto;
	object-fit: contain;
}

/* The prototype's plate carries no zoom control - el.39/40/41 are the plate, the inner
   box and the cover, and nothing else. */
.woocommerce div.product .jd-product__gallery .woocommerce-product-gallery__trigger {
	display: none;
}

.jd-product__eyebrow {
	display: flex;
	align-items: center;
	gap: var(--jd-space-6);
	font-size: var(--jd-fs-2xs);
	color: var(--jd-text-secondary);
	margin-block-end: var(--jd-space-6);
}

/* [el.43: IBM Plex Sans Arabic 15px #DBCFB8] - the eyebrow's own 12px is for the words. */
.jd-product__eyebrow .jd-product__eyedot {
	font-size: 15px;
	color: var(--jd-hairline);
}

/* The publisher is set two points larger than the tag beside it - [el.42: EB Garamond
   14px/normal #566078]. `.jd-latin` only swaps the family, so without this it inherited
   the eyebrow's own 12px. */
.jd-product__eyebrow .jd-latin {
	font-size: 14px;
	line-height: normal;
}

/* 30px/42px in ink, not the 32px/1.3 navy every h1-h4 inherits from style.css:82
   - [el.46: EB Garamond 30px/42px w500 rgb(28,36,51)]. */
.jd-product__title {
	font-family: var(--jd-font-latin);
	font-size: 30px;
	font-weight: 500;
	line-height: 42px;
	color: var(--jd-ink);
	margin-block-end: var(--jd-space-6);
}

/* Rules above and below, 11px, tracked - store.dc.html:506. The line is the prototype's
   only horizontal division in the summary column; without the rules it reads as another
   paragraph rather than as the bibliographic strip. */
.jd-product__biblio {
	border-block: var(--jd-border);
	padding-block: 7px;
	margin-block-end: var(--jd-space-9);
	font-size: 11px;
	/* el.47 is 33px tall = 17 + 2x7 padding + 2x1 border, so the line box is `normal`
	   (17px at 11px), not the body's 1.7 (18.7px) - [el.48/49]. */
	line-height: normal;
}

/* Label and chips share ONE row - [el.51 «يُعتمد لدى» 40x15 @y329 sits on the same
   baseline band as el.52, the first chip @y323; the 8px between them is the gap]. It read
   as two stacked lines because the label was a block above the list. */
.jd-product__unis {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--jd-space-4);
	margin-block: var(--jd-space-10);
}

.jd-product__unilist {
	display: flex;
	flex-wrap: wrap;
	gap: var(--jd-space-3);
	flex: 1 1 auto;
	min-inline-size: 0;
}

/* Accreditation chips read as navy on the surface tint here, not as the muted
   secondary text the catalogue filter chips use - store.dc.html:508.
   The box is tighter than the shared `.jd-chip` atom, which screens 01/02 signed off at
   6px/12px and 12px - [el.52: padding 4px 12px, 213x27 · el.53: 11.5px w500 #18295E].
   Scoped here so the atom itself is untouched. */
.jd-product__unilist .jd-chip {
	color: var(--jd-navy);
	background-color: var(--jd-surface);
	font-weight: 500;
	padding-block: var(--jd-space-2);
	font-size: 11.5px;
	line-height: normal;
}

.jd-product__terms,
.jd-product__delivery {
	font-size: var(--jd-fs-2xs);
	color: var(--jd-text-muted);
	margin-block-start: var(--jd-space-6);
}

/* ---- Product page: WooCommerce's own summary markup ---------------------
   Everything between .jd-product__unis and .jd-product__terms is emitted by
   woocommerce_single_product_summary, not by this theme: p.price, p.stock, form.cart
   and div.product_meta. None of it was styled, so it rendered in the WooCommerce
   defaults that inc/enqueue.php leaves enqueued - the page's primary call to action
   was #7f54b3 WooCommerce purple with a 3px radius. The book card never exposed this
   because it builds its own .jd-btn markup. Same root cause as the notices in a4ec9de. */

/* Figure, currency and "VAT included" on one baseline - store.dc.html:513. The wrapper is
   opened and closed around WooCommerce's price callback; see
   aljadawel2026_open_price_row(). */
.jd-product__pricerow {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: var(--jd-space-4);
	margin-block: var(--jd-space-8) var(--jd-space-3);
}

.jd-product__vat {
	font-size: 11.5px;
	line-height: normal;   /* [el.61: 11.5px/normal #6E7689, box 59x17] */
	color: var(--jd-text-muted);
}

.jd-product__summary .price {
	display: flex;
	align-items: baseline;
	gap: var(--jd-space-4);
	margin: 0;
}

/* 34px, mono, navy - store.dc.html:513 [el.59: IBM Plex Mono 34px/normal w500 #18295E].
   The riyal glyph is an inline SVG at a fixed pixel size; .riyal-svg in commerce.css
   sizes it in em, so it follows this.

   The selector is NOT `.jd-product__summary > .price` any more. aljadawel2026_open_price_row()
   prints .jd-product__pricerow at priority 9, so WooCommerce's <p class="price"> is a
   grandchild and that child combinator matched nothing - leaving WooCommerce 11.0.1's own
   `.woocommerce:where(body:not(.woocommerce-uses-block-theme)) div.product p.price
   { color:#958e09; font-size:1.25em }` (0,2,2 - :where() adds nothing) to paint the store's
   price olive at 20px. This reads 0,5,0. */
.woocommerce .jd-product__summary .jd-product__pricerow .price .woocommerce-Price-amount {
	font-family: var(--jd-font-mono);
	font-variant-numeric: tabular-nums;
	font-size: 34px;
	font-weight: 500;
	line-height: normal;
	color: var(--jd-navy);
}

/* Same cascade problem, same origin: `.woocommerce … div.product .stock` (0,2,1) beat
   `.jd-product__summary > .stock` (0,2,0) and printed the stock line in #958e09 at .92em.
   The prototype has no stock line on screen 03 at all - see PENDING-DECISIONS #15, which
   hides it for digital books and keeps it for print (screen 04 shares this template). */
.woocommerce .jd-product__summary p.stock {
	font-size: var(--jd-fs-2xs);
	color: var(--jd-text-muted);
	margin-block-end: var(--jd-space-6);
}

.woocommerce .jd-product__summary p.stock.in-stock { color: var(--jd-emerald); }

/* The prototype has no availability line on screen 03 at all, and a code that is generated
   on payment has no shelf to be on. Screen 04 shares this template and a printed book does
   need it, so this hides it for digital only. */
/* DERIVED: see PENDING-DECISIONS #15 */
.woocommerce .jd-product--digital .jd-product__summary p.stock { display: none; }

.jd-product__summary form.cart {
	display: flex;
	align-items: center;
	gap: var(--jd-space-6);
	max-inline-size: 520px;
	margin-block: var(--jd-space-9) var(--jd-space-6);
}

/* WooCommerce clearfixes this form with `form.cart::before/::after { content:" ";
   display:table }`. In a flex container those two pseudo-elements are FLEX ITEMS: the row
   held four items and three 12px gaps, not two items and one, so 24px vanished from the
   two buttons and they measured 280 + 204 against the prototype's 294 + 214. Neutralising
   them yields 294.0 / 214.0 exactly - verified in the live CSSOM before this was written.
   The clearfix itself is redundant here; nothing in the row floats.

   `div.jd-product`, not `.jd-product__summary`: WooCommerce's selector is
   `.woocommerce div.product form.cart::before`, which reads (0,3,2). Going through the
   summary class reads (0,3,1) and LOSES - the first attempt at this rule changed nothing
   on staging for exactly that reason. Matching their `div` with the product root's own
   element+class takes it to (0,3,3). */
.woocommerce div.jd-product form.cart::before,
.woocommerce div.jd-product form.cart::after {
	display: none;
}

/* The quantity input is type=hidden on books that cap at one - WooCommerce's
   global/quantity-input.php prints `type="hidden"` when min === max, but keeps the
   <div class="quantity"> and its <label>. The wrapper therefore stayed a flex item:
   the 520px row was split between THREE items and TWO gaps, so the two buttons measured
   271 + 197 where the prototype has 294 + 214 with one 12px gap [el.70/71]. Both
   selectors, because which one applies depends on the WooCommerce version - 9.x adds
   `.hidden` to the wrapper, 11.0.1 (this store) does not. */
.jd-product__summary form.cart .quantity.hidden,
.jd-product__summary form.cart .quantity:not(:has(input[type="number"])) {
	display: none;
}

.jd-product__summary form.cart .quantity input[type="number"] {
	inline-size: 84px;
	min-block-size: 52px;
	padding-inline: var(--jd-space-4);
	border: var(--jd-border);
	border-radius: var(--jd-radius-btn);
	background-color: var(--jd-surface);
	color: var(--jd-ink);
	font-family: var(--jd-font-mono);
	font-variant-numeric: tabular-nums;
	text-align: center;
}

/* Qualified with .woocommerce and the element, to clear WooCommerce's own rule rather
   than tie with it. Theirs reads
   `.woocommerce:where(body:not(.woocommerce-block-theme-has-button-styles)) button.button.alt`
   - :where() contributes NO specificity, so that computes to 0,3,1 and the obvious
   `.jd-product__summary .single_add_to_cart_button` (0,2,0) loses. This is 0,4,1.
   WooCommerce does offer an opt-out, the body class in that :not(), but it is set only
   from theme.json for block themes and switching it on globally would strip the default
   skin from every WooCommerce button on the site - including cart, checkout and account,
   none of which have been rendered yet. Narrow fix here; the rest when those screens are
   actually looked at. */
.woocommerce .jd-product__summary button.single_add_to_cart_button,
.woocommerce .jd-product__summary a.single_add_to_cart_button {
	flex: 1.4;
	min-block-size: 52px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* [el.70: padding 1px 6px, border 1px solid transparent, line-height normal, 294x52] */
	padding-block: 1px;
	padding-inline: var(--jd-space-3);
	border: 1px solid transparent;
	border-radius: var(--jd-radius-btn);
	background-color: var(--jd-navy);
	color: var(--jd-on-navy);
	font-family: inherit;
	font-size: 15px;
	font-weight: 600;
	line-height: normal;
	cursor: pointer;
	transition: background-color var(--jd-transition), border-color var(--jd-transition);
}

.woocommerce .jd-product__summary button.single_add_to_cart_button:hover,
.woocommerce .jd-product__summary a.single_add_to_cart_button:hover {
	background-color: var(--jd-navy-700);
	border-color: var(--jd-navy-700);
}

.woocommerce .jd-product__summary button.single_add_to_cart_button:disabled,
.woocommerce .jd-product__summary button.single_add_to_cart_button.disabled {
	opacity: .55;
	cursor: not-allowed;
}

/* WooCommerce prints this wrapper whether or not it has anything to say, and on this
   store it is always empty - SKU is hidden and the taxonomies it lists are not shown
   here. Left visible it contributes a stray margin under the button. */
.jd-product__summary > .product_meta:empty { display: none; }

.jd-product-access {
	display: flex;
	align-items: flex-start;
	gap: var(--jd-space-7);
	max-inline-size: 560px;
	margin-block: var(--jd-space-9) var(--jd-space-6);
	padding: var(--jd-space-9);
	background-color: var(--jd-surface);
	border: var(--jd-border);
	border-radius: var(--jd-radius-card);
}

.jd-product-access__icon {
	display: grid;
	place-items: center;
	flex: 0 0 42px;
	inline-size: 42px;
	block-size: 42px;
	border: 1px solid rgb(24 41 94 / .35);
	border-radius: var(--jd-radius-btn);
	color: var(--jd-navy);
}

.jd-product-access__copy { min-inline-size: 0; }

.jd-product-access__copy h2 {
	margin: 0 0 var(--jd-space-3);
	font-family: var(--jd-font-ui);
	font-size: var(--jd-fs-base);
	font-weight: 600;
	line-height: 1.5;
	color: var(--jd-navy);
}

.jd-product-access__copy p {
	margin: 0;
	font-size: var(--jd-fs-2xs);
	line-height: 1.9;
	color: var(--jd-text-secondary);
}

.jd-product-access__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--jd-space-4);
	margin-block-start: var(--jd-space-7);
}

.jd-product-access__actions .jd-btn {
	padding-inline: var(--jd-space-8);
	font-size: var(--jd-fs-2xs);
	font-weight: 600;
}

.jd-product-access__actions .jd-btn--primary { border-color: transparent; }
.jd-product-access__actions .jd-btn--hairline { background-color: transparent; }

/* Buy now - transparent on a navy hairline, filling on hover, at flex:1 against the
   primary button's 1.4 (store.dc.html:546). It is a second submit inside WooCommerce's
   own form, so the add runs through every validation rule the primary button does. */
.woocommerce .jd-product__summary .jd-product__buynow,
.woocommerce-page .jd-product__summary .jd-product__buynow {
	flex: 1;
	min-block-size: 52px;
	/* [el.71: padding 1px 6px, 1px solid #18295E, line-height normal, 214x52] */
	padding-block: 1px;
	padding-inline: var(--jd-space-3);
	border: 1px solid var(--jd-navy);
	border-radius: var(--jd-radius-btn);
	background-color: transparent;
	color: var(--jd-navy);
	font-family: inherit;
	font-size: 14px;
	font-weight: 600;
	line-height: normal;
	cursor: pointer;
	transition: background-color var(--jd-transition), color var(--jd-transition);
}

.woocommerce .jd-product__summary .jd-product__buynow:hover,
.woocommerce-page .jd-product__summary .jd-product__buynow:hover {
	background-color: var(--jd-navy);
	color: var(--jd-on-navy);
}

/* Delivery perks - store.dc.html:539. Chips rather than a sentence: three short promises
   scan at a glance where one line of prose does not. */
.jd-product__perks {
	display: flex;
	flex-wrap: wrap;
	gap: var(--jd-space-4);
	list-style: none;
	margin-block: 0 var(--jd-space-11);
	padding: 0;
	max-inline-size: 560px;
}

/* The chip's 27px is 17 + 2x4 padding + 2x1 border [el.64/65]. It measured 30 because
   the body's 1.7 gave the 11.5px text a 19.55px line box. */
.jd-product__perk {
	padding-block: var(--jd-space-2);
	padding-inline: var(--jd-space-6);
	border: var(--jd-border);
	border-radius: var(--jd-radius-tag);
	background-color: var(--jd-surface);
	font-size: 11.5px;
	line-height: normal;
	color: var(--jd-text-secondary);
}

/* Six labels on the product page measure 10px / normal / 1.4px / #6E7689 - el.51
   «يُعتمد لدى», el.76, el.89, el.132, el.177, el.211. The shared .jd-label atom is
   10.5px/1.7/#566078 and is signed off by screens 01/02, so this scopes rather than
   edits it. .14em x 10px = the 1.4px measured. */
.jd-product .jd-label {
	font-size: 10px;
	line-height: normal;
	color: var(--jd-text-muted);
}

/* An invitation, not a filter - so dashed, where the accreditation chips are solid. */
.jd-chip--ask {
	border-style: dashed;
	color: var(--jd-text-secondary);
	background-color: transparent;
	font-weight: 400;
}

.jd-chip--ask:hover {
	border-color: var(--jd-navy);
	color: var(--jd-navy);
}

.jd-product__assurance {
	margin-block-start: var(--jd-space-3);
	font-size: 11px;
	color: var(--jd-text-muted);
}

.jd-product__detail { padding-block-end: var(--jd-space-16); }

/* No top border and no block padding: the prototype separates product sections with the
   head's own hairline rule (below), not with a full-width rule across the column. 32px is
   the measured gap between one block's bottom and the next head's top - includes card ends
   1809, data-card head starts 1841; data card ends 2413, outcomes head starts 2446. */
.jd-product__section {
	padding-block: 0;
	border-block-start: 0;
	margin-block-start: var(--jd-space-16);
}

/* The section head: title, a 1px rule that eats the rest of the row, and an optional
   trailing label. [structure: div 1152x36 [flex row gap:18px]; 105 + 18 + 974 + 18 + 37
   = 1152 on the data card, and the same arithmetic at 390: 105 + 18 + 164 + 18 + 37 = 342] */
.jd-product__sectionhead {
	display: flex;
	align-items: center;
	gap: var(--jd-space-9);              /* 18px */
	block-size: 36px;
	margin-block-end: var(--jd-space-8); /* 16px - el.132 head bottom 1877 to el.133 card top 1893 */
}

/* Scoped, never the shared atom: .jd-section__title is 28px/42px and is signed off by
   screens 01 and 02. On the product page it is Amiri 24px/36px [el.103/114/130/166/175/180/195]. */
.jd-product__sectionhead .jd-section__title {
	font-size: 24px;
	line-height: 36px;
	flex: 0 0 auto;
}

.jd-product__sectionhead .jd-label { flex: 0 0 auto; }

.jd-product__sectionrule {
	flex: 1 1 auto;
	block-size: 1px;
	background-color: var(--jd-hairline);   /* [el.131: 974x1 #DBCFB8] */
}

.jd-prose { line-height: var(--jd-lh-body); max-inline-size: 68ch; }

/* The static policy paragraph under a section head. It had no rule at all, so it fell back
   to the body's 16px/1.7 ink across the full 1152px column —
   [el.127 @1440: 13px/27.3px #566078, box 720x55] · [el.116 @390: same type, box 342x82,
   where the 720 never binds]. */
.jd-product__prose {
	font-size: 13px;
	line-height: 27.3px;
	color: var(--jd-text-secondary);
	max-inline-size: 720px;
}

/* ---- "Is this your book?" - the edition-verification card ----------------
   This block had NO stylesheet at all: the markup shipped in single-product.php and every
   rule below was missing, so the card rendered as a bare list on paper. */
.jd-verify {
	background-color: var(--jd-surface);
	border: 1px solid rgb(24 41 94 / .35);                            /* [el.73] */
	border-radius: var(--jd-radius-card);
	padding-block: var(--jd-space-9) var(--jd-space-6);               /* 18px / 12px [el.73] */
	padding-inline: var(--jd-space-11);                               /* 22px        [el.73] */
	margin-block-start: 34px;                                         /* [el.73 margin-top] */
	box-shadow: none;                                                 /* [el.73] */
}

/* Same three-part head as a section head, but 16px apart and 35px tall - the title is
   20px Amiri here, not 24px. [structure: div 1106x35 [flex row gap:16px]] */
.jd-verify__head {
	display: flex;
	align-items: center;
	gap: var(--jd-space-8);
	block-size: 35px;
	margin-block-end: var(--jd-space-2);   /* 4px - el.74 bottom 750 to el.77 top 754 */
}

.jd-verify__head .jd-section__title {
	font-size: 20px;                        /* [el.74: Amiri 20px w700 #18295E] */
	line-height: normal;
	flex: 0 0 auto;
}

.jd-verify__head .jd-label { flex: 0 0 auto; }

.jd-verify__foot {
	display: flex;
	align-items: center;
	gap: var(--jd-space-7);                 /* 14px [structure: div 1106x53 [flex row gap:14px]] */
}

.jd-verify__foot p {
	font-size: 12px;
	line-height: 22.8px;                    /* [el.84] */
	color: var(--jd-text-secondary);
}

.jd-verify__foot .jd-btn--hairline {
	flex: 0 0 auto;
	min-block-size: 36px;                   /* [el.85: 150x36] */
	padding-inline: var(--jd-space-8);      /* 16px [el.85] */
	font-size: 12px;
	background-color: var(--jd-surface);
}

/* ---- Curated two-book bundle -------------------------------------------
   The card is conditional on an eligible sibling product. Its compact purchase column
   remains 154px at both widths; the surrounding layout is what changes at 390px. */
.jd-bundle {
	min-block-size: 168px;
	margin-block-start: var(--jd-space-8);
	padding-block: var(--jd-space-8);
	padding-inline: var(--jd-space-10);
	background-color: var(--jd-surface);
	border: var(--jd-border);
	border-radius: var(--jd-radius-card);
	box-shadow: var(--jd-shadow-card);
}

.jd-bundle__head {
	display: flex;
	align-items: center;
	gap: var(--jd-space-8);
	min-block-size: 29px;
	margin-block-end: 11px;
}

.jd-bundle__head .jd-section__title {
	flex: 0 0 auto;
	font-size: 19px;
	line-height: normal;
}

.jd-bundle__head .jd-label { flex: 0 0 auto; }

.jd-bundle__body {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr) 154px;
	align-items: center;
	gap: var(--jd-space-8);
}

.jd-bundle__covers {
	display: flex;
	align-items: center;
	gap: var(--jd-space-5);
}

.jd-bundle__cover {
	display: flex;
	align-items: center;
	justify-content: center;
	inline-size: 58px;
	block-size: 76px;
	padding: var(--jd-space-2);
	overflow: hidden;
	background-color: var(--jd-paper);
	border: var(--jd-border);
	border-radius: var(--jd-radius-tag);
}

.jd-bundle__cover img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: contain;
}

.jd-bundle__cover--fallback {
	background-color: var(--jd-navy);
	color: var(--jd-on-navy);
	font-size: var(--jd-fs-3xs);
	line-height: 1.35;
	overflow-wrap: anywhere;
	text-align: center;
}

.jd-bundle__plus {
	font-family: var(--jd-font-mono);
	font-size: 15px;
	line-height: normal;
	color: var(--jd-text-muted);
}

.jd-bundle__copy { min-inline-size: 0; }

.jd-bundle__title {
	margin: 0;
	font-size: 13.5px;
	line-height: 21.6px;
	color: var(--jd-ink);
}

.jd-bundle__title a { color: inherit; }

.jd-bundle__caption {
	margin-block: var(--jd-space-1) 0;
	font-size: 10.5px;
	line-height: normal;
	color: var(--jd-text-muted);
}

.jd-bundle__purchase { inline-size: 154px; }

.jd-bundle__price {
	font-family: var(--jd-font-mono);
	font-size: 19px;
	font-weight: 500;
	line-height: normal;
	color: var(--jd-navy);
}

.jd-bundle__price .woocommerce-Price-amount { color: inherit; }

.jd-bundle__tax {
	margin: 0;
	font-size: 10.5px;
	line-height: normal;
	color: var(--jd-text-muted);
}

.woocommerce div.jd-product form.jd-bundle__form {
	margin: var(--jd-space-4) 0 0;
}

.woocommerce div.jd-product form.jd-bundle__form::before,
.woocommerce div.jd-product form.jd-bundle__form::after {
	display: none;
}

.jd-bundle__button {
	inline-size: 154px;
	min-block-size: 42px;
	padding-inline: var(--jd-space-10);
	font-size: 12.5px;
	font-weight: 600;
	line-height: normal;
}

/* ---- About/features and sample ----------------------------------------- */
.jd-product__about .jd-prose {
	max-inline-size: 820px;
	font-size: 14px;
	line-height: 30.8px;
	color: var(--jd-text-secondary);
}

.jd-features {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--jd-space-5) var(--jd-space-12);
	max-inline-size: 720px;
	margin-block-start: var(--jd-space-8);
}

.jd-features__item {
	display: flex;
	align-items: center;
	gap: 9px;
	padding-block-end: var(--jd-space-4);
	border-block-end: 1px solid var(--jd-paper-deep);
	font-size: 12.5px;
	line-height: normal;
	color: var(--jd-ink);
}

.jd-features__item::before {
	content: "\2713";
	flex: 0 0 auto;
	color: var(--jd-emerald);
}

.jd-sample__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-block-size: 44px;
	padding-inline: var(--jd-space-11);
	background-color: var(--jd-surface);
	font-size: 13px;
	font-weight: 600;
	line-height: normal;
}

@media (max-width: 768px) {
	.jd-product__sectionhead {
		block-size: auto;
		min-block-size: 36px;
	}

	.jd-product__sectionhead .jd-section__title {
		flex: 0 1 auto;
		min-inline-size: 0;
		overflow-wrap: anywhere;
	}

	.jd-product__sectionhead .jd-product__sectionrule {
		min-inline-size: 5px;
	}

	.jd-product__sectionhead .jd-label {
		flex: 0 1 auto;
		max-inline-size: 125px;
		white-space: normal;
		overflow-wrap: anywhere;
	}

	.jd-bundle {
		min-block-size: 381px;
	}

	.jd-bundle__head {
		gap: var(--jd-space-2);
	}

	.jd-bundle__head .jd-section__title {
		flex: 0 1 auto;
		min-inline-size: 0;
		max-inline-size: 145px;
		overflow-wrap: anywhere;
	}

	.jd-bundle__head .jd-label {
		flex: 0 1 auto;
		max-inline-size: 125px;
		white-space: normal;
		overflow-wrap: anywhere;
	}

	.jd-bundle__head .jd-product__sectionrule {
		flex: 0 1 5px;
		min-inline-size: 5px;
	}

	.jd-bundle__body {
		grid-template-columns: minmax(0, 1fr);
		align-items: start;
		gap: var(--jd-space-5);
	}

	.jd-bundle__purchase {
		justify-self: start;
	}
}

/* ---- Data card ----------------------------------------------------------
   The card itself was never built - the rows sat straight on the page, which is the whole
   of the «الناشر» background mismatch (#fcf9f1 expected against #f6f1e6 measured). */
.jd-datacard {
	display: grid;
	gap: 0;
	background-color: var(--jd-surface);
	border: var(--jd-border);
	border-radius: var(--jd-radius-card);
	padding-block: var(--jd-space-2);       /* 4px  [el.133 / el.122@390] */
	padding-inline: var(--jd-space-11);     /* 22px [el.133] */
	box-shadow: var(--jd-shadow-card);
}

/* store.dc.html:2215 - 11px rows on the second-tier divider, not the hairline. The
   hairline is the border of the card itself; using it again for every internal row makes
   the table read as eleven stacked boxes. Last row drops its rule.

   The key column is 170px, not 200 [structure: span 170x19 inside div 1106x46 gap:24px],
   and it stays two columns at 390 - el.123@390 is the same flex row, key 54 wide at x=289
   with the value wrapping in the 102px that is left. */
.jd-datacard__row {
	display: grid;
	grid-template-columns: 170px minmax(0, 1fr);
	gap: var(--jd-space-12);
	align-items: baseline;
	padding-block: 11px;
	border-block-end: 1px solid var(--jd-paper-deep);
}

.jd-datacard__row:last-child { border-block-end: 0; }

/* [el.135/138/141/144/147/150/153/156/159/162/164 - eleven keys, all identical] */
.jd-datacard__key {
	font-size: 10px;
	line-height: 19px;
	letter-spacing: var(--jd-track-label);   /* .14em x 10px = the 1.4px measured */
	color: var(--jd-text-muted);
}

/* The value cell is a wrapper and the text is an inner span, exactly as the prototype
   nests them [structure: span 912x23 containing span 441x19]. That nesting is what keeps
   a Latin value aligned to the PAGE's start: el.136/151/154/157 are LTR-isolated runs
   that still sit at the RTL row's start. Putting .jd-latin on the block instead gives it
   `direction: ltr` AND `text-align: start`, and start under ltr resolves the opposite way
   - which threw every Latin and mono value to the far end of the card. On an inline span
   the isolation still applies and the block keeps the row's direction, so it mirrors
   correctly in English too. */
.jd-datacard__val { margin: 0; }

/* Three faces, chosen by what the value IS rather than by which row it is. */
.jd-datacard__valtext {
	font-size: 13px;
	line-height: 24.7px;
	font-weight: 500;
	color: var(--jd-ink);                    /* [el.142/145/160/163/165] */
}

.jd-datacard__valtext.jd-latin {
	font-size: 14.5px;
	line-height: 23.2px;
	font-weight: 400;                        /* [el.136/139/148/151/157] */
}

.jd-datacard__valtext.jd-mono {
	font-size: 12.5px;
	line-height: normal;
	letter-spacing: .5px;
	font-weight: 400;                        /* [el.154] */
}

/* ---- Related / up-sell / cross-sell rails -------------------------------
 *
 * These four selectors are WooCommerce's own class names, not the theme's. The rails are
 * emitted by single-product/related.php, up-sells.php and cart/cross-sells.php - core
 * templates this theme does NOT override, because overriding them would mean maintaining
 * three near-identical copies to change two class names. Styling the core markup is the
 * smaller commitment; only woocommerce/content-product.php is ours, and it exists so each
 * item renders a book card instead of an empty <li>.
 *
 * The heading is <h2> with no class, so it is matched structurally.
 */

.related.products,
.up-sells.products,
.cross-sells {
	padding-block: var(--jd-space-14);
	border-block-start: var(--jd-border);
}

.related.products > h2,
.up-sells.products > h2,
.cross-sells > h2 {
	font-size: var(--jd-fs-title);
	margin-block-end: var(--jd-space-12);
}

/* [03 el.217-218] Core emits only an h2, so its pseudo-element carries the
   measured in-row rule without replacing the WooCommerce template. */
.up-sells.products {
	padding-block: 0;
	border-block-start: 0;
}

.up-sells.products > h2 {
	display: flex;
	align-items: center;
	gap: 18px;
	margin-block: 40px 20px;
	font-family: var(--jd-font-display);
	font-size: 24px;
	font-weight: 700;
	line-height: 36px;
}

.up-sells.products > h2::after {
	content: "";
	flex: 1 1 auto;
	min-inline-size: 5px;
	block-size: 1px;
	background-color: var(--jd-hairline);
}

ul.products {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--jd-space-8);
	margin: 0;
	padding: 0;
	list-style: none;
}

.up-sells.products ul.products {
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--jd-space-8);
}

.up-sells.products ul.products::before,
.up-sells.products ul.products::after {
	display: none;
}

@media (max-width: 1080px) {
	ul.products,
	.up-sells.products ul.products {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 768px) {
	ul.products,
	.up-sells.products ul.products {
		grid-template-columns: 1fr;
	}
}

/*
 * Cross-sells render inside the cart's summary column, which is a single narrow track —
 * a 3-up grid there would produce cards about 90px wide.
 */
.cross-sells ul.products { grid-template-columns: 1fr; }

/* The <li> is a pure grid cell; the card inside it carries all the visual treatment. */
.up-sells.products ul.products li.product.jd-rail__item {
	display: flex;
	float: none;
	inline-size: 100%;
	margin: 0;
}
.jd-rail__item > .jd-book { inline-size: 100%; }

/* ---- Section scaffolding ------------------------------------------------ */

.jd-section { padding-block: var(--jd-space-24); }

/*
 * Grid, not wrapped flex. The prototype stacks the kicker directly over the title in ONE
 * column and measures both at the title's width (el.105/106 are both 209px wide at the same
 * x). Wrapped flex gave the kicker `flex-basis: 100%`, so its box spanned the full 1152px
 * container - visually identical in RTL, but the wrong box, and it makes the head impossible
 * to align against the measured spec. `auto 1fr auto` sizes column 1 to the wider of the two.
 */
.jd-section__head {
	display: grid;
	grid-template-columns: auto 1fr auto;
	align-items: baseline;
	column-gap: var(--jd-space-8);
	margin-block-end: var(--jd-space-12);
}

/* The prototype's title block is separated from the trailing route by a 1px hairline. */
.jd-section__head::after {
	content: "";
	grid-column: 2;
	grid-row: 2;
	align-self: center;
	block-size: 1px;
	background-color: var(--jd-hairline);
}

/* .16em at 10.5px = the 1.68px measured on el.105/229/247/267 - the section kicker tracks
 * slightly wider than the 10px hero/footer labels, which sit at .14em and .18em. */
.jd-section__kicker {
	grid-column: 1;
	grid-row: 1;
	letter-spacing: .16em;
	line-height: normal;
}

.jd-section__title {
	grid-column: 1;
	grid-row: 2;
	font-size: var(--jd-fs-section);
}

/* Pushed to the far end of the flex head, so it reads as the section's "see all". */
.jd-section__more {
	grid-column: 3;
	grid-row: 2;
	font-size: 12.5px;
	font-weight: 500;
	color: var(--jd-navy);
	border-block-end: 1px solid var(--jd-hairline);
	padding-block-end: 2px;
}

.jd-section__more:hover {
	border-block-end-color: var(--jd-navy);
	text-decoration: none;
}

.jd-section__more { grid-column: 3; grid-row: 2; }

/* ---- Trust strip --------------------------------------------------------
 * A ruled band of its own between the hero and the catalogue, not a row inside the hero.
 * The separators are real elements rather than ::before pseudo-elements, because the
 * design spaces them symmetrically - a pseudo-element would sit inside one item's box
 * and land 14px from one neighbour and 18px from the other.
 */

/* No background of its own - the prototype's band is transparent, so it sits on
   whatever ground the page has and cannot seam against it. */
.jd-trust {
	border-block: 1px solid var(--jd-hairline);
}

.jd-trust__inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: var(--jd-space-2) 14px;
	min-block-size: 48px;
	padding-block: var(--jd-space-3);
	font-size: 12.5px;
	color: var(--jd-text-secondary);
	text-align: center;
}

.jd-trust__sep { color: var(--jd-hairline); }

/* .03em at 12.5px = the 0.375px tracking measured on every trust item (el.98-104). */
.jd-trust__item { line-height: normal; letter-spacing: .03em; }

/* Brass on paper - the tint that belongs on light grounds, not the on-navy one.
 * The award line is the one item set at 500; the rest stay at 400 (el.102). */
.jd-trust__item--award { color: var(--jd-brass); font-weight: 500; }

/* ---- Hero --------------------------------------------------------------- */

.jd-hero {
	background-color: var(--jd-navy);
	color: var(--jd-on-navy);
	background-image: url("../img/pattern-navy.svg");
	background-repeat: repeat;
	background-size: 240px;
}

/*
 * The prototype's own authored value, read off the element rather than off the resolved
 * computed style - getComputedStyle reports grid columns in px, so measuring the rendered
 * hero gives "608px 520px" and hides the fact that both tracks are CAPPED, not fixed.
 * They shrink together below 1152px of inner width, which is what keeps the headline
 * column and the card column in proportion between 1080px and full width.
 *
 * The 24px inline padding is the hero's own, wider than .jd-container's 20px gutter.
 */
.jd-hero__inner {
	display: grid;
	grid-template-columns: minmax(0, 620px) minmax(0, 520px);
	justify-content: space-between;
	gap: var(--jd-space-12);
	padding-block: 60px 36px;
	padding-inline: var(--jd-space-12);
	min-block-size: 574px;
	align-items: start;
}

/*
 * The no-wrap university marquee contributes its full track to this grid item's automatic
 * minimum, so without this the 390px page stretches to several thousand pixels and the
 * whole site scrolls sideways on a phone.
 *
 * This was scoped to `.jd-ltr` on the grounds that the RTL capture was an established
 * parity floor. That protected a screenshot at the cost of the Arabic phone layout, which
 * is the primary language: measured on staging at 390, Arabic overflowed by 5167px while
 * English was clean. A page that scrolls sideways is a defect, not a baseline, so the
 * constraint now applies in both directions.
 *
 * Both grid children need it, not just the intro. Below 1080 the two collapse into one
 * `1fr` column, and a `1fr` track takes an automatic minimum from the LARGEST min-content
 * among the items in it - so constraining the intro alone still left the carousel holding
 * the column open at 618px inside a 390px page.
 *
 * The screen-01 Arabic 390 capture floor moves as a result - see PENDING-DECISIONS #68.
 */
.jd-hero__intro,
.jd-hero__carousel { min-inline-size: 0; }

@media (max-width: 1080px) {
	.jd-hero__inner {
		grid-template-columns: 1fr;
		gap: var(--jd-space-16);
		padding-block: var(--jd-space-16);
		min-block-size: 0;
	}
}

/* Screen 01's 390px prototype measures a 20px hero inset. Keep the established RTL
 * capture untouched while giving the English mirror the same physical content width. */
@media (max-width: 768px) {
	.jd-ltr .jd-hero__inner { padding-inline: var(--jd-space-10); }
}

/*
 * The kicker opens with a 26px brass rule. It is the one brass mark above the fold and
 * the reason the eye starts at the headline rather than the middle of the navy field.
 * Decorative, so it is a pseudo-element and never reaches the accessibility tree.
 */
.jd-hero__kicker {
	display: flex;
	align-items: center;
	gap: var(--jd-space-6);
	color: rgb(255 255 255 / .55);
	font-size: 10.5px;
	letter-spacing: .22em;
	margin-block: 0;
}

.jd-hero__kicker::before {
	content: "";
	inline-size: 26px;
	block-size: 1px;
	background-color: var(--jd-brass);
	flex-shrink: 0;
}

/*
 * The vertical rhythm below is measured off the prototype and is applied as a whole:
 * kicker → 18 → h1 → 12 → sub → 38 → search → 18 → quick links → 16 → chips. Applying
 * only some of these still reads as "not matching", because the eye tracks the intervals
 * between the rows rather than any single gap.
 */
.jd-hero__title {
	font-size: var(--jd-fs-hero);
	line-height: var(--jd-lh-hero);
	color: var(--jd-on-navy);
	margin-block: var(--jd-space-9) var(--jd-space-6);
}

/*
 * 480px, not a ch measure. The sub-headline wraps to exactly two lines in the design and
 * a ch unit is relative to the FONT - it lands differently in Arabic and in English, so
 * the same rule would break the line in two different places per language.
 */
.jd-hero__sub {
	color: rgb(255 255 255 / .72);
	font-size: 15px;
	line-height: 2.05;
	max-inline-size: 480px;
	margin-block: 0;
}

/*
 * The hero field is 56px, against the header's 44px - this is the page's primary action
 * and the prototype sizes it accordingly. Brass on focus rather than navy, because navy
 * on navy would be invisible.
 */
/*
 * The hero field is NOT the header field on a dark ground. The prototype makes it a solid
 * CREAM card with dark text and its own drop shadow, sitting on the navy - the page's one
 * primary action, and the only element above the fold that looks like paper. An earlier
 * pass had it as a translucent white pane, which is a different control entirely.
 *
 * The wrapper carries no border of its own here: the field and the button are two
 * separate objects with a 10px gap, not one composite control.
 */
.jd-search--hero {
	display: flex;
	align-items: stretch;
	gap: var(--jd-space-5);
	block-size: 56px;
	min-inline-size: 0;
	max-inline-size: 540px;
	margin-block-start: 38px;
	padding: 0;
	border: 0;
	background: none;
}

.jd-search--hero .jd-search__field {
	flex: 1 1 auto;
	min-inline-size: 0;
	padding-inline: var(--jd-space-9);
	border: 1px solid var(--jd-surface);
	border-radius: var(--jd-radius-btn);
	background-color: var(--jd-surface);
	color: var(--jd-ink);
	font-size: 14px;
	box-shadow: 0 1px 2px rgb(0 0 0 / .18);
	transition: border-color .18s ease-out;
}

/* Brass, because navy on a navy hero would be invisible. */
.jd-search--hero .jd-search__field:focus {
	outline: none;
	border-color: var(--jd-brass);
}

.jd-search--hero .jd-search__field::placeholder { color: var(--jd-text-muted); }

.jd-search__go {
	flex-shrink: 0;
	padding-inline: 34px;
	border: 0;
	border-radius: var(--jd-radius-btn);
	background-color: var(--jd-on-navy);
	color: var(--jd-navy);
	font-family: var(--jd-font-ui);
	font-size: 14.5px;
	font-weight: 600;
	cursor: pointer;
	transition: background-color .18s ease-out;
}

.jd-search__go:hover { background-color: var(--jd-paper-deep); }

/* ---- Hero university chips (38s, distinct from the 36s announcement bar) -- */

.jd-chips {
	margin-block-start: var(--jd-space-8);
	flex-shrink: 0;
	font-size: var(--jd-fs-2xs);
	color: rgb(255 255 255 / .55);
	line-height: 2.1;
	white-space: nowrap;
	overflow: hidden;
	max-inline-size: 100%;
	display: flex;
	/*
	 * Both ends fade rather than cutting off mid-word. The mask is the prototype's; it is
	 * also what makes a looping row read as continuous instead of clipped.
	 */
	-webkit-mask-image: linear-gradient(to left, transparent, #000 7%, #000 93%, transparent);
	mask-image: linear-gradient(to left, transparent, #000 7%, #000 93%, transparent);
}

.jd-chips__track {
	display: inline-flex;
	align-items: baseline;
	flex: 0 0 auto;
	animation: jd-marquee var(--jd-marquee-chips) linear infinite;
	will-change: transform;
}

.jd-rtl .jd-chips__track { animation-name: jd-marquee-rtl; }

.jd-chips:hover .jd-chips__track,
.jd-chips:focus-within .jd-chips__track {
	animation-play-state: paused;
}

.jd-chips__item {
	color: rgb(255 255 255 / .75);
	border-block-end: 1px solid transparent;
	transition: color .18s ease-out, border-color .18s ease-out;
}

.jd-chips__item:hover {
	color: var(--jd-on-navy);
	border-block-end-color: rgb(255 255 255 / .5);
	text-decoration: none;
}

/* Interpunct between chips, never before the first of a track. */
.jd-chips__item + .jd-chips__item::before {
	content: "·";
	margin-inline: 9px;
	color: rgb(255 255 255 / .3);
}

/*
 * These are UNDERLINED TITLES, not chips. The port drew bordered tag-pills; the prototype
 * sets each one in EB Garamond with a single hairline underline, so the row reads as a
 * list of book titles someone searched for rather than as a filter bar. Baseline-aligned
 * against the 10px label, because the sizes differ and the underlines must still line up.
 */
/*
 * One line, never two. The design gives this row 18px of height; real catalogue titles
 * run to sixty characters, so the row is set nowrap and clipped rather than allowed to
 * wrap - a wrapped "most searched" row pushes the chips marquee into the card and the
 * whole column loses its rhythm. The titles themselves are trimmed in the template.
 */
.jd-hero__quick {
	display: flex;
	flex-wrap: nowrap;
	align-items: baseline;
	gap: var(--jd-space-6);
	margin-block-start: var(--jd-space-9);
	font-size: 11.5px;
	color: rgb(255 255 255 / .55);
	overflow: hidden;
}

/* .jd-label's secondary grey is a paper colour; this label sits on the navy hero. */
.jd-hero__quicklabel {
	font-size: 10px;
	letter-spacing: var(--jd-track-label);
	color: rgb(255 255 255 / .55);
}

.jd-hero__quicklink {
	font-family: var(--jd-font-latin);
	font-size: 13.5px;
	color: rgb(255 255 255 / .85);
	border-block-end: 1px solid rgb(255 255 255 / .3);
	white-space: nowrap;
	transition: color .18s ease-out, border-color .18s ease-out;
}

.jd-hero__quicklink:hover {
	color: var(--jd-on-navy);
	border-block-end-color: var(--jd-on-navy);
	text-decoration: none;
}

/*
 * The card column. The prototype insets it 44px from the headline column on the inline
 * start side and drops it 16px, which is what stops the two columns reading as one block.
 */
.jd-hero__carousel {
	padding-block-start: var(--jd-space-8);
	padding-inline-start: 44px;
}

/*
 * A fixed 420px slide. The height is declared rather than left to the cover, because the
 * carousel swaps slides and covers differ in aspect ratio - without it the dots and the
 * caption below jump every five seconds.
 */
.jd-hero__slide {
	block-size: 420px;
	background-color: var(--jd-navy-700);
	border: 1px solid rgb(255 255 255 / .18);
	border-radius: var(--jd-radius-card);
	overflow: hidden;
}

/*
 * `hidden` must beat the display below. An attribute selector and a class have the same
 * weight in the cascade, and the UA sheet's `[hidden] { display: none }` loses to ANY
 * author rule that sets display - so without this the carousel renders all five slides
 * stacked. The cart toast shipped with exactly this bug and was visible on every page.
 */
.jd-hero__slide[hidden] { display: none; }

.jd-hero__slidelink {
	display: flex;
	flex-direction: column;
	block-size: 100%;
	color: inherit;
}

.jd-hero__slidelink:hover { text-decoration: none; }

.jd-hero__coverwrap {
	flex: 1 1 0;
	display: flex;
	align-items: center;
	justify-content: center;
	min-block-size: 0;
	margin-block: var(--jd-space-10) var(--jd-space-5);
	margin-inline: var(--jd-space-10);
}

/* `contain`, so a cover is never cropped - book art carries the title. */
.jd-hero__cover {
	max-inline-size: 100%;
	max-block-size: 100%;
	inline-size: auto;
	block-size: auto;
	object-fit: contain;
}

/*
 * Fallback plate, for the large part of this catalogue that has no cover art. Same idea
 * as the book card's: the Latin book face on navy reads as a binding, where a broken
 * image icon would read as a fault.
 */
.jd-hero__cover--fallback {
	display: flex;
	align-items: center;
	justify-content: center;
	inline-size: 100%;
	block-size: 100%;
	padding: var(--jd-space-12);
	border: 1px solid rgb(255 255 255 / .14);
	border-radius: var(--jd-radius-btn);
	background-color: rgb(0 0 0 / .12);
	color: rgb(255 255 255 / .85);
	font-size: 1.25rem;
	line-height: 1.5;
	text-align: center;
}

.jd-hero__slidefoot {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--jd-space-6);
	padding-block: var(--jd-space-6);
	padding-inline: var(--jd-space-8);
	border-block-start: 1px solid rgb(255 255 255 / .16);
	background-color: rgb(24 41 94 / .35);
}

.jd-hero__slideid { min-inline-size: 0; }

.jd-hero__slidetitle {
	display: block;
	font-family: var(--jd-font-latin);
	font-size: 14.5px;
	line-height: 1.25;
	color: var(--jd-on-navy);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.jd-hero__slidemeta {
	display: block;
	margin-block-start: var(--jd-space-2);
	font-size: 10px;
	color: rgb(255 255 255 / .55);
}

.jd-hero__slidebuy {
	flex-shrink: 0;
	display: flex;
	align-items: baseline;
	gap: var(--jd-space-5);
}

/*
 * The tag is re-tinted for the navy footer. `.jd-tag` was designed as a pill on the
 * paper-ground book card - secondary grey on a light field - and inherited straight onto
 * navy it measured about 1.9:1, effectively invisible. The prototype's on-navy variant is
 * a white-tinted outline, and these are its values.
 */
.jd-hero__slidebuy .jd-tag {
	border: 1px solid rgb(255 255 255 / .35);
	border-radius: 4px;
	background-color: transparent;
	color: rgb(255 255 255 / .8);
	font-size: 10px;
	font-weight: 500;
	padding-block: 2px;
	padding-inline: 9px;
}

.jd-hero__slideprice {
	font-family: var(--jd-font-mono);
	font-size: var(--jd-fs-sm);
	font-weight: 500;
	color: var(--jd-on-navy);
	white-space: nowrap;
}

/* The riyal glyph is an inline SVG using currentColor, so it follows the price's white. */
.jd-hero__slideprice .riyal-svg { vertical-align: -.125em; }

/*
 * Bars, not dots. The prototype draws 2px rules - 8px wide when idle, 26px when active —
 * so the control reads as a progress track rather than as five buttons.
 */
.jd-hero__dots {
	display: flex;
	justify-content: center;
	align-items: center;
	gap: 7px;
	block-size: 16px;
	margin-block-start: var(--jd-space-6);
}

.jd-hero__dot {
	inline-size: 8px;
	block-size: 2px;
	padding: 0;
	border: 0;
	border-radius: 1px;
	background-color: rgb(255 255 255 / .35);
	cursor: pointer;
	transition: inline-size .25s ease-out, background-color .25s ease-out;
}

/* The one place gold sits on navy, so it uses the contrast tint. */
.jd-hero__dot[aria-selected="true"] {
	inline-size: 26px;
	background-color: var(--jd-brass-on-navy);
}

.jd-hero__caption {
	margin-block: var(--jd-space-3) 0;
	font-size: 10px;
	line-height: 1.6;
	text-align: center;
	color: rgb(255 255 255 / .45);
}

@media (max-width: 1080px) {
	.jd-hero__carousel { padding-inline-start: 0; }
	.jd-hero__slide { block-size: 360px; }
}

/*
 * The biblio row is the exception to .jd-latin: the prototype keeps "Cambridge" and
 * "Pearson" in the UI sans here so the publisher sits on the same 10.5px baseline as the
 * ISBN and the level beside it (el.114/132/150). Everywhere else Latin runs get EB Garamond.
 */
.jd-book__biblio .jd-latin,
.jd-hero__slidemeta .jd-latin { font-family: inherit; letter-spacing: inherit; }

/* ---- Universities marquee ----------------------------------------------
 * SCOPED to the homepage strip on purpose. `.jd-unis__link` and `.jd-unis__name` are also
 * defined by pages.css for screen 05's index list, and pages.css loads after this file, so
 * the unscoped rules below lost to screen 05's on the front page - that is why the chips
 * rendered as bare underlined rows instead of pills. `.jd-section.jd-unis` (0,3,0) beats
 * `.jd-unis__link` (0,1,0) without touching screen 05.
 */

.jd-unis__viewport { display: flex; overflow: hidden; }

.jd-unis__track {
	display: flex;
	flex: 0 0 auto;
	gap: var(--jd-space-12);
	padding-inline-end: var(--jd-space-12);
	animation: jd-marquee var(--jd-marquee-chips) linear infinite;
}

.jd-rtl .jd-unis__track { animation-name: jd-marquee-rtl; }

.jd-unis__viewport:hover .jd-unis__track,
.jd-unis__viewport:focus-within .jd-unis__track { animation-play-state: paused; }

.jd-section.jd-unis .jd-unis__link {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--jd-space-5);
	white-space: nowrap;
	/* 4px 16px and a 40px pill - el.234/236/238 */
	padding: 4px 16px;
	min-block-size: 40px;
	border: var(--jd-border);
	border-radius: var(--jd-radius-btn);
	border-block-end: var(--jd-border);
	background-color: var(--jd-surface);
	color: var(--jd-navy);
}

.jd-section.jd-unis .jd-unis__link::after { content: none; }

.jd-section.jd-unis .jd-unis__link:hover {
	border-color: var(--jd-hairline-strong);
	background-color: var(--jd-surface);
	color: var(--jd-navy);
	text-decoration: none;
}

.jd-section.jd-unis .jd-unis__name {
	font-size: 12.5px;
	font-weight: 500;
	color: var(--jd-navy);
}

.jd-unis__logo { max-block-size: 24px; inline-size: auto; }

/*
 * The row's own label and its route to the full index. The prototype puts both INSIDE the
 * chips row rather than in the section head (el.233 and el.246), so the head carries only
 * the kicker and the title.
 */
.jd-unis__strip {
	display: flex;
	align-items: center;
	gap: var(--jd-space-8);
	padding-block: var(--jd-space-8);
	border-block: 1px solid var(--jd-hairline);
}

.jd-unis__striplabel {
	flex: 0 0 auto;
	font-size: 10px;
	letter-spacing: var(--jd-track-label);
	color: var(--jd-text-muted);
}

.jd-unis__all {
	flex: 0 0 auto;
	font-size: 11px;
	font-weight: 500;
	color: var(--jd-navy);
	border-block-end: 1px solid var(--jd-navy);
}

.jd-unis__all:hover { text-decoration: none; }

/* ---- Steps -------------------------------------------------------------- */

.jd-steps__list {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--jd-space-14);
}

@media (max-width: 768px) {
	/* el.30 @390: the cover box narrows to 198x330 while the height holds. */
	.woocommerce div.product .jd-product__gallery .woocommerce-product-gallery__image img {
		inline-size: 198px;
	}
}

@media (max-width: 768px) { .jd-steps__list { grid-template-columns: 1fr; } }  /* gridSteps is mob-only */

.jd-steps__item {
	padding-inline-end: var(--jd-space-14);
	border-inline-end: var(--jd-border);
}

.jd-steps__item:last-child {
	padding-inline-end: 0;
	border-inline-end: 0;
}

.jd-steps__num {
	display: block;
	font-family: var(--jd-font-display);
	font-size: 46px;
	line-height: 1.15;
	color: var(--jd-navy);
}

/*
 * The step titles are the one place on this page where an h-element is NOT the display
 * face: the prototype sets them in the UI sans at 15/600 in ink, so they read as labels
 * over the big Amiri numeral rather than competing with it (el.252/256/259).
 */
.jd-steps__title {
	font-family: var(--jd-font-ui);
	font-size: 15px;
	font-weight: 600;
	line-height: normal;
	color: var(--jd-ink);
	margin-block: var(--jd-space-4) var(--jd-space-3);
}

.jd-steps__body {
	font-size: var(--jd-fs-xs);
	line-height: 25px;
	color: var(--jd-text-secondary);
}

/* ---- Quote -------------------------------------------------------------- */

.jd-quote__figure {
	max-inline-size: 680px;
	margin: 30px auto 46px;
	text-align: center;
}

.jd-quote__figure::before {
	content: "";
	display: block;
	inline-size: 26px;
	block-size: 1px;
	margin: 0 auto var(--jd-space-9);
	background-color: var(--jd-brass);
}

.jd-quote__text {
	font-family: var(--jd-font-display);
	font-size: 27px;
	line-height: 1.9;
	color: var(--jd-navy);
	margin: 0;
}

.jd-quote__author {
	margin-block-start: var(--jd-space-7);
	font-size: 11.5px;
	letter-spacing: var(--jd-track-label);
	color: var(--jd-text-muted);
}

/* ---- Publishers --------------------------------------------------------- */

/*
 * Navy plates carrying the publisher's name in the Latin book face. The prototype's strip
 * has no images in it at all - this was drawn as an outlined pill holding a logo, and
 * since no term carries logo artwork the row rendered empty under a live heading.
 */
.jd-pubs__strip {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--jd-space-5) var(--jd-space-6);
}

.jd-pubs__note {
	margin: 0;
	font-size: 10px;
	letter-spacing: var(--jd-track-label);
	color: var(--jd-text-muted);
}

.jd-pubs__list {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--jd-space-5) var(--jd-space-6);
	margin: 0;
	padding: 0;
	list-style: none;
}

.jd-pubs__item { flex: 0 0 auto; }

.jd-pubs__link {
	display: flex;
	align-items: center;
	justify-content: center;
	inline-size: 132px;
	block-size: 60px;
	padding: var(--jd-space-5);
	border-radius: var(--jd-radius-card);
	background-color: var(--jd-navy);
	color: var(--jd-on-navy);
	font-family: var(--jd-font-latin);
	font-size: 11.5px;
	line-height: 1.35;
	text-align: center;
	transition: background-color .18s ease-out;
}

a.jd-pubs__link:hover {
	background-color: var(--jd-navy-700);
	color: var(--jd-on-navy);
	text-decoration: none;
}

.jd-pubs__all {
	flex: 0 0 auto;
	font-size: 11px;
	color: var(--jd-navy);
}

/* ---- Screen 01 measured corrections (Session 30) -------------------------
 * See the note in layout.css: `line-height: normal` is the prototype's default for small
 * text, and --jd-lh-body pushes every one of these over the tolerance.
 */
.jd-section__more,
.jd-hero__caption,
.jd-hero__quicklabel,
.jd-unis__striplabel,
.jd-unis__all,
.jd-pubs__all,
.jd-search__go,
.jd-search .jd-input {
	line-height: normal;
}

/* el.94: the caption is spaced off the carousel by its own padding, and tracks at .14em. */
.jd-hero__caption {
	letter-spacing: var(--jd-track-label);
	padding-block-start: var(--jd-space-5);
}

/* el.108: the rule under "see all" is navy, the same ink as the label above it. */
.jd-section__more {
	padding-block-end: 0;
	border-block-end-color: var(--jd-navy);
}

/* el.288/246: both "all" links are 500, like every other inline route in the design. */
.jd-pubs__all,
.jd-unis__all { font-weight: 500; }

/* el.125: 6px of inline padding, not the 8px space token. */
.jd-book__add { padding-inline: 6px; }

/*
 * Book-list row on a phone.
 *
 * DERIVED: see PENDING-DECISIONS #70 — as with screen 05, the prototype's own 390 capture
 * overflows: docs/design/07-portal-ksu--390.json puts the "أضف إلى السلة" button at x=-88
 * and the untruncated titles 263px past the right edge. The theme already fares better
 * (it ellipsises the title, which the prototype does not), but every child except the title
 * is flex-shrink:0, so the fixed items alone exceed 390 by 35px however far the title shrinks.
 *
 * Giving the title column the whole line minus the cover plate pushes the course code, the
 * delivery tag, the price and the button onto a second line, where they wrap among themselves.
 */
@media (max-width: 768px) {
	.jd-booklist__row { flex-wrap: wrap; }

	.jd-booklist__main { flex: 1 1 calc(100% - 44px - var(--jd-space-7)); }
}
