/* =====================================================================
 * Learning v3 — course and workshop detail, and the catalogues.
 *
 * Ported from Claude outputs/design-system-v3/css/learning.css, which is the reference
 * implementation of the pattern book's learning specimens, plus the page-level layout the
 * reference leaves to the host page (the two-column detail grid, the cover frame, the workshop
 * schedule, the preview band and the participants' voices) — those are carried over from
 * content.css, where every `.learning-*` rule used to live, and re-cut on the v3 tokens.
 *
 * Loaded only where it is used: a course or workshop page, the course archive, the workshops page
 * and the assessments catalogue. Depends on kit.css for the tokens, the rail, the meter and the
 * status pill.
 * ===================================================================== */

/* ------------------------------------------------------------- page layout
 * Restructured 2026-09-26 on the article page's model (decisions.md): a full-width head band, one
 * white box of sections beside a side column that stays with the reader, then full-width coloured
 * bands. `.learning-wrap` is the page's own 1120px measure (one of the site's four container
 * widths, tokens.css) — kept rather than switched to `.public-wrap`'s 1200px, because widening the
 * container was not asked for and the head/box/bands all still need to agree on one width. */
.learning-page { padding-bottom: var(--space-band); }
.learning-wrap { width: var(--chrome-width); margin-inline: auto; }
.learning-layout { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: var(--space-block); align-items: start; padding-block: var(--space-block) var(--space-section); }
/* The thirteen in-column sections (about, outline, fit, outcome, agenda, requirements, preview,
 * voices, teacher, facts…) used a flat 28–40px gap regardless of section length — measured as 40px
 * at 1280 in the 2026-09-27 census. `--space-section` is the token this program names for exactly
 * this rhythm; `.learning-sec`'s own heading-to-content gap already matched `--space-head` (16px)
 * by coincidence, so it now references the token instead of repeating its value. */
.learning-main { display: grid; gap: var(--space-section); min-width: 0; padding: var(--pad-card); border: 1px solid var(--iz-line-soft); border-radius: var(--iz-r-lg); background: #fff; box-shadow: var(--iz-shadow-3); }
.learning-sec { display: grid; gap: var(--space-head); }
.learning-sec > .iz-h2 { margin: 0; }
/* Stretched, not `start`: the sticky wrapper inside can only travel as far as this column is tall —
 * the article page's own lesson (article.css). */
.learning-side { align-self: stretch; min-width: 0; }
.learning-side__stick { position: sticky; top: 20px; display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-block); }
@media (max-width: 900px) { .learning-layout { grid-template-columns: 1fr; gap: var(--space-block); } .learning-side__stick { position: static; } }

/* ------------------------------------------------------------- the head: a full-width band
 * `.learning-head` is the kit page head with its card taken off and a real picture in its media
 * column — the same move `.article-head` makes for the article page. */
.learning-band { padding-bottom: var(--space-block); border-bottom: 1px solid var(--iz-line-soft); background: #fff; }
.learning-band .iz-pagestack { gap: var(--space-head); padding-block-start: var(--space-head); }
.learning-band .iz-crumbs { margin-bottom: 0; }
.learning-head.iz-pagehead { grid-template-columns: minmax(280px, 1fr) minmax(0, 2fr); grid-template-areas: "media copy"; gap: var(--space-6); align-items: center; padding: 0; overflow: visible; border: 0; border-radius: 0; background: none; }
.learning-head.iz-pagehead > div { grid-area: copy; }
.learning-head .iz-pagehead__media { grid-area: media; }
.learning-head.iz-pagehead::after { display: none; }
.learning-head .iz-pagehead__eyebrow { font-size: var(--text-eyebrow-size); }
.learning-head .iz-pagehead__eyebrow svg { width: 15px; height: 15px; }
.learning-head h1 { margin-top: var(--gap-title); }
.learning-head .iz-pagehead__summary { max-width: 62ch; margin-top: var(--gap-title); font: 400 15px / 2 var(--font-body); }
.learning-head .iz-pagehead__media { aspect-ratio: 16 / 9; box-shadow: none; padding: 0; background: linear-gradient(165deg, #edf5f7, #d7e6e9); }

/* Duration, session/chapter counts, the instructor, the workshop date and hour — one line of
 * captions under the title, the same move the article page made for its own meta row. */
.learning-meta { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; margin: var(--space-head) 0 0; padding: 0; overflow: hidden; border: 1px solid var(--iz-line-soft); border-radius: var(--iz-r); }
.learning-meta div { display: grid; grid-template-columns: 20px minmax(0, 1fr); gap: 0 var(--gap-inline); align-content: center; min-width: 0; min-height: 76px; padding: var(--space-2) var(--space-3); border-inline-start: 1px solid var(--iz-line-soft); }
.learning-meta div:first-child { border-inline-start: 0; }
.learning-meta i { color: var(--iz-ink-soft); font-size: var(--text-body-s-size); }
.learning-meta i { grid-row: span 2; align-self: center; }
.learning-meta dt { color: var(--iz-ink-soft); font: 500 var(--text-micro-size) / 2 var(--font-body); }
.learning-meta dd { margin: 0; color: var(--iz-ink); font: 600 var(--text-caption-size) / 2 var(--font-body); }
/* Workshop only: whether registration is open, said beside the title instead of only inside the
 * sticky box — which on a phone sits below everything the pill is meant to qualify. */
.learning-state { margin: var(--space-stack) 0 0; }

/* the cover, in the pagehead's own media frame */
.learning-cover { position: relative; isolation: isolate; display: grid; place-items: center; width: 100%; height: 100%; color: var(--primary-700); font-size: calc(var(--text-number-l-size) * 2); }
.learning-cover img { width: 100%; height: 100%; object-fit: cover; }
.learning-cover .art { width: 62%; height: 62%; }
.learning-cover__voice { position: absolute; inset-inline: var(--space-2); bottom: var(--space-2); }
/* No backdrop-filter here: on this wide a box (the caption spans almost the full cover), Chromium's
 * software compositor (headless, and some low-power/no-GPU real browsers) rasterises the blur as a
 * solid smudge instead of blurring the image behind it — reproduced at 768px, 2026-09-27. A flat,
 * slightly more opaque tint reads the same and never depends on GPU compositing. */
.iz-audio--onDark.learning-cover__voice { background: rgb(20 46 55 / .9); border-color: rgb(255 255 255 / .16); }
.learning-cover__voice b { display: block; color: #fff; font: 600 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
.learning-cover__voice small { display: block; overflow: hidden; color: rgb(255 255 255 / .72); font: 400 var(--text-micro-size)/var(--text-micro-lh) var(--font-body); text-overflow: ellipsis; white-space: nowrap; }

@media (max-width: 1024px) {
	.learning-meta { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.learning-meta div:nth-child(odd) { border-inline-start: 0; }
	.learning-meta div:nth-child(n + 3) { border-block-start: 1px solid var(--iz-line-soft); }
}
@media (max-width: 860px) {
	/* The kit stacks the head here and puts the picture first — the same breakpoint the article
	 * page's head stacks at. */
	.learning-head .iz-pagehead__media { aspect-ratio: 16 / 9; border-radius: 18px 6px 18px 6px; }
	.learning-head.iz-pagehead { grid-template-columns: minmax(0, 1fr); grid-template-areas: "media" "copy"; gap: var(--space-head); }
}
@media (max-width: 520px) {
	.learning-main { border-radius: var(--iz-r); }
}

/* the body of a course description, as the editor wrote it */
.learning-rich-text { color: var(--iz-text); font: 400 15px / 2 var(--font-body); }
.learning-rich-text > :first-child { margin-top: 0; }
.learning-rich-text > :last-child { margin-bottom: 0; }
.learning-rich-text a { color: var(--primary-700); }

/* Structured course copy entered in the editor. The palette stays local to this body so it cannot
 * recolour the shared course page or any other learning view. */
.isa-course-body {
	--isa-ink: #31463b;
	--isa-moss: #63735e;
	--isa-clay: #b77a55;
	--isa-sand: #f8f1e6;
	--isa-paper: #fffdf9;
	color: var(--isa-ink);
	direction: rtl;
	font-family: inherit;
	line-height: 2;
}
.isa-course-body * { box-sizing: border-box; }
.isa-course-body h2,
.isa-course-body h3 { color: var(--isa-ink); line-height: 1.55; }
.isa-course-body h2 { margin: 0 0 .5rem; font-size: clamp(1.45rem, 3vw, 2.15rem); }
.isa-course-body h3 { margin: 0 0 .6rem; font-size: 1.25rem; }
.isa-course-body p { margin: 0 0 1rem; }
.isa-course-body .isa-course-intro {
	margin: 0 0 1.5rem;
	padding: clamp(1.25rem, 3vw, 2.25rem);
	border: 1px solid #eadbc7;
	border-right: 5px solid var(--isa-clay);
	border-radius: 18px;
	background: linear-gradient(135deg, var(--isa-sand), #fffaf3);
}
.isa-course-body .isa-course-kicker { margin-bottom: .35rem; color: var(--isa-clay); font-weight: 700; }
.isa-course-body .isa-course-visual { margin: 1.75rem 0; }
.isa-course-body .isa-course-visual img { display: block; width: 100%; height: auto; border-radius: 18px; }
.isa-course-body .isa-course-visual figcaption { margin-top: .6rem; color: #667169; font-size: .9rem; }
.isa-course-body .isa-course-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; margin: 1.5rem 0; }
.isa-course-body .isa-course-card { padding: 1.15rem; border: 1px solid #e9dfd2; border-radius: 14px; background: var(--isa-paper); }
.isa-course-body .isa-course-card strong { display: block; margin-bottom: .35rem; color: var(--isa-clay); }
.isa-course-body .isa-course-table-wrap { margin: 1.25rem 0 1.75rem; overflow-x: auto; }
.isa-course-body table { width: 100%; min-width: 560px; border-collapse: collapse; background: var(--isa-paper); }
.isa-course-body th,
.isa-course-body td { padding: .8rem 1rem; border: 1px solid #eadfce; text-align: right; vertical-align: top; }
.isa-course-body th { background: var(--isa-ink); color: #fff; font-weight: 700; }
.isa-course-body tr:nth-child(even) td { background: #fcf7ef; }
.isa-course-body .isa-course-note { margin: 1.5rem 0; padding: 1rem 1.2rem; border-radius: 12px; background: #edf1ea; }
.isa-course-body ul { margin: .5rem 0 1.25rem; padding-right: 1.25rem; }
.isa-course-body li { margin-bottom: .4rem; }
@media (max-width: 700px) {
	.isa-course-body .isa-course-grid { grid-template-columns: 1fr; }
}

/* Course, workshop and assessment reading uses the owner's requested open leading throughout.
 * Compact controls keep their own line box so touch targets do not become oversized. */
.learning-page :is(h1, h2, h3, h4, p, li, dt, dd),
.test-detail :is(h1, h2, h3, h4, p, li, dt, dd) { line-height: 2; }

/* The first reading pass begins with roughly two paragraphs, then gently fades. The native
 * disclosure still exposes the entire description without JavaScript. */
.learning-readmore { display: grid; gap: var(--space-head); }
.learning-readmore__content { position: relative; min-width: 0; max-block-size: 14rem; overflow: hidden; }
.learning-readmore__content::after { position: absolute; inset-inline: 0; inset-block-end: 0; height: 5rem; background: linear-gradient(to bottom, rgb(255 255 255 / 0), #fff); content: ""; pointer-events: none; }
.learning-readmore__toggle { display: inline-flex; align-items: center; justify-self: center; gap: var(--gap-inline); min-height: 44px; padding: 0; border: 0; border-radius: 0; background: transparent; color: var(--primary-700); font: var(--text-button); cursor: pointer; }
.learning-readmore__toggle i { transition: rotate .2s var(--iz-ease-out); }
.learning-readmore.is-expanded .learning-readmore__content { max-block-size: none; overflow: visible; }
.learning-readmore.is-expanded .learning-readmore__content::after { display: none; }
.learning-readmore.is-expanded .learning-readmore__toggle i { rotate: 180deg; }
.learning-readmore__less { display: none; }
.learning-readmore.is-expanded .learning-readmore__more { display: none; }
.learning-readmore.is-expanded .learning-readmore__less { display: inline; }
.learning-readmore__toggle:focus-visible { outline: none; box-shadow: var(--iz-focus); }
@media (hover: hover) and (pointer: fine) { .learning-readmore__toggle:hover { color: var(--primary-900); } }

/* workshop: when and where
 * The day, the hour, how long, how it is held and how much room is left are the facts a workshop is
 * chosen by, so this block is the most legible thing on the page: the value at 17px, and the label
 * at the caption tier rather than the 12px floor it used to sit at. */
.learning-schedule { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); margin: 0; }
.learning-schedule div { display: grid; gap: var(--gap-title); padding: var(--space-2) var(--pad-row); border: 1px solid var(--iz-line-soft); border-radius: 14px; background: #fff; }
.learning-schedule dt { color: var(--iz-ink-soft); font: 500 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
/* `anywhere`, because one of these values is an online workshop's entry link: an unbroken URL in a
 * 168px cell is the one string here that can push a phone sideways. */
.learning-schedule dd { margin: 0; color: var(--iz-ink); font: 600 var(--text-subtitle-size)/var(--text-subtitle-lh) var(--font-body); overflow-wrap: anywhere; }
.learning-schedule dd.iz-ltr { text-align: start; }
/* One cell holds a sentence rather than a fact — «پس از تکمیل ثبت‌نام نمایش داده می‌شود.» in place of
 * an entry link that is not this visitor's yet. It reads as the note it is, not as another 17px
 * datum three lines deep. */
.learning-schedule dd.is-note { font: var(--text-body-s); color: var(--iz-ink-soft); }
/* The seats cell is the only value that changes meaning as it changes: coral once the room is
 * nearly gone, and once it is gone. Calm ink while there is room — a number that is always red
 * says nothing. */
.learning-schedule .is-few dd, .learning-schedule .is-full dd { color: var(--accent-700); }
.learning-schedule .is-full { border-color: var(--accent-200); background: var(--surface-accent); }

/* workshop: what to bring, what to expect */
.learning-requirements { display: grid; gap: var(--gap-list); margin: 0; padding: 0; list-style: none; }
.learning-requirements li { display: grid; grid-template-columns: 20px minmax(0, 1fr); gap: var(--gap-inline); align-items: start; color: var(--iz-text); font: var(--text-body-s); }
.learning-requirements i { margin-top: var(--space-0); color: var(--secondary-600); font-size: var(--text-body-size); }

/* a real recorded minute of the course, on the one dark band the page allows itself */
.learning-preview { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-4); align-items: center; padding: var(--pad-card); border-radius: var(--iz-r-lg); background: linear-gradient(150deg, var(--primary-700), var(--primary-900)); color: rgb(255 255 255 / .84); }
.learning-preview .art { width: 104px; height: 104px; }
.learning-preview h3 { margin: 0 0 var(--gap-title); color: #fff; font: var(--text-h3); }
.learning-preview p { margin: 0 0 var(--space-stack); font: var(--text-body-s); }
@media (max-width: 560px) { .learning-preview { grid-template-columns: 1fr; } .learning-preview .art { display: none; } }

/* participants, in their own words — empty unless a consented recording exists */
.learning-voices { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--gap-grid); }
/* Grey, not the blue tint this card used to carry: the 2026-09-19 direction reserves colour for
 * full-width bands and the one thing a page wants noticed, and a page can show several of these
 * cards at once. */
.learning-voice { display: grid; gap: var(--space-stack); align-content: start; padding: var(--pad-card); border-radius: var(--iz-r-lg); background: var(--iz-sunk); }
/* Who is speaking (2026-09-29): their picture or a person glyph, their name, their own stars. */
.learning-voice__who { display: grid; grid-template-columns: 48px minmax(0, 1fr); gap: var(--space-2); align-items: center; }
.learning-voice__avatar { display: grid; place-items: center; width: 48px; height: 48px; overflow: hidden; border-radius: 50%; background: #fff; box-shadow: inset 0 0 0 1px var(--iz-line-soft); color: var(--primary-500); font-size: var(--text-h2-size); }
.learning-voice__avatar img { width: 100%; height: 100%; object-fit: cover; }
.learning-voice__id { display: grid; gap: 2px; min-width: 0; }
.learning-voice__name { margin: 0; overflow: hidden; color: var(--iz-ink); font: 600 var(--text-body-s-size)/var(--text-body-s-lh) var(--font-body); text-overflow: ellipsis; white-space: nowrap; }
/* No name entered: the old kicker line stands in, in the kicker's own quieter voice. */
.learning-voice__name.is-generic { color: var(--secondary-700); font: 600 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
/* Amber drawn as a graphic, not text: the stars' meaning is in the element's label, so the colour
 * only has to read as "earned" beside the pale unearned star (3:1 against the grey card). */
.learning-voice__stars { --iz-star: #b97800; display: flex; gap: 2px; margin: 0; line-height: 1; }
.learning-voice__stars span { display: flex; }
.learning-voice__stars i { font-size: var(--text-body-s-size); color: var(--iz-ink-soft); opacity: .3; }
.learning-voice__stars .is-on i { color: var(--iz-star); opacity: 1; }
.learning-voice__topic { display: flex; align-items: center; gap: var(--gap-inline); margin: 0; color: var(--iz-ink); font: 600 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
.learning-voice__topic i { color: var(--primary-500); font-size: var(--text-subtitle-size); }
.learning-voice blockquote { margin: 0; color: var(--iz-text); font: var(--text-body-s); }

/* The voice as a row of bars that fill as it plays (audio-player.js, `data-iz-audio-wave`). The
 * shell and the play button are kit.css's `.iz-audio`; only the timeline differs. Two identical rows
 * of bars stacked: the played row is clipped to `--played`, which the player sets on the shell from
 * the audio's own time — so the fill is the recording's real position, not an animation guessed
 * alongside it. The range input every player has lies transparently over the bars; it is what a
 * keyboard moves and what a screen reader reads, and its focus ring is drawn on the bars. The
 * timeline runs left to right like every other player on the site (decisions.md 2026-09-19). */
/* 2026-09-29 (owner: «remove voice white background»): the player sits directly on the grey voice
 * card — no white box, no inset padding — so the card's own padding is the only frame. On that grey
 * (--iz-sunk) the old pale bars were 1.2:1; the unplayed bars are now --primary-400 (3.43:1 against
 * the card) and the played ones --primary-800 (3.17:1 against the unplayed), so both the track and
 * how much of it has played clear 3:1. The play button (--secondary-500) is 4.5:1 on the card. */
.iz-audio--wave { padding: 0; border: 0; border-radius: 0; background: none; }
.iz-audio--wave .iz-audio__ui { grid-template-columns: 40px minmax(0, 1fr) auto; gap: var(--space-2); }
.iz-audio--wave .iz-audio__play { width: 40px; height: 40px; font-size: var(--text-body-size); }
.iz-audio__wave { position: relative; height: 36px; border-radius: 8px; }
.iz-audio__bars { position: absolute; inset: 0; display: flex; align-items: center; justify-content: space-between; gap: 2px; pointer-events: none; }
.iz-audio__bars i { flex: 1 1 0; max-width: 4px; min-height: 3px; height: var(--h); border-radius: 2px; background: var(--primary-400); }
.iz-audio__bars--played { clip-path: inset(0 calc(100% - var(--played, 0%)) 0 0); transition: clip-path .26s linear; }
.iz-audio__bars--played i { background: var(--primary-800); }
/* While it plays, the played bars breathe very slightly — the one sign, beyond the moving edge,
 * that sound is coming out. Transform only; reduced motion drops it (below). */
.iz-audio--wave.is-playing .iz-audio__bars--played i { animation: iz-wave-breathe 1.1s var(--iz-ease) infinite alternate; }
.iz-audio--wave.is-playing .iz-audio__bars--played i:nth-child(3n) { animation-delay: -.4s; }
.iz-audio--wave.is-playing .iz-audio__bars--played i:nth-child(3n+1) { animation-delay: -.8s; }
@keyframes iz-wave-breathe { to { transform: scaleY(.72); } }
.iz-audio--wave .iz-audio__seek { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.iz-audio__wave:has(.iz-audio__seek:focus-visible) { box-shadow: 0 0 0 3px var(--color-focus-ring); }
@media (prefers-reduced-motion: reduce) {
	.iz-audio__bars--played { transition: none; }
	.iz-audio--wave.is-playing .iz-audio__bars--played i { animation: none; }
}

/* ------------------------------------------------------------- the two bands after the box
 * This is where the page spends its colour, the same move article.css makes: the questions and the
 * related offerings are each a different kind of thing from the sections above them, and a band
 * says so at a glance. The owner asked for the FAQ band here by name (2026-09-19 plan;
 * decisions.md 2026-09-26). */
.learning-faq-band { padding-block: var(--space-band); background: var(--surface-blue); }
.learning-related-band { padding-block: var(--space-band); background: #f5f5f5; }
.learning-related-band__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px var(--space-3); margin-bottom: var(--space-head); }
.learning-related-band__head .iz-h2 { margin: 0; }
.learning-related-band__head .iz-link { margin-inline-start: auto; }
/* No gap between the layout and the first band: the layout's own bottom padding is the gap. */
.learning-page:has(.learning-faq-band, .learning-related-band) .learning-layout { padding-bottom: var(--space-band); }

/* related offerings — the offer card does the work, this only spaces them. A ceiling as well as a
 * floor, the same fix `.catalog-grid` already needed: with `1fr` a single related result
 * stretched across the whole band and its cover became a 1100px poster. `justify-content: start`
 * keeps the row on the reading side rather than centred once it is short a card or two. */
.learning-related { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 360px)); justify-content: start; gap: var(--gap-grid); }
@media (max-width: 620px) { .learning-related { grid-template-columns: minmax(0, 1fr); } }
/* The stacked workshop layout (date beside title) used to be duplicated here by hand. The
 * `home-offer` container query that now drives it (offer-card.css) has to measure one card, not
 * the row: a related row can hold two or three cards, so the row itself is often well past 459px
 * even while each card in it is narrow. `.offer-grid__item` below — the per-card wrapper
 * page-workshops.php and single-courses.php put around every offer-card call — is the container;
 * this grid just spaces the wrappers. decisions.md, offer-card v3 run 3. */
/* The shared per-card container: named `home-offer` so offer-card.css's own `@container home-offer
 * (max-width: 459px)` rule matches it, on both grids that call the offer card (this one and
 * `.catalog-grid--pairs` below). `min-width: 0` because a grid item defaults to `auto`, which would
 * refuse to shrink the container — and so the card inside it — below its content's natural width. */
.offer-grid__item { container: home-offer / inline-size; min-width: 0; }

/* =====================================================================
 * Learning v3 — course & workshop detail: stat strip, outline (TOC),
 * fit, outcome, agenda, buy box, teacher, audio, FAQ.
 * ===================================================================== */

/* ------------------------------------------------------------- stat strip */
.learning-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); gap: var(--space-2); margin: var(--space-4) 0 0; padding: 0; list-style: none; }
.learning-stats li { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 2px var(--space-2); align-items: center; padding: var(--space-2) var(--pad-row); border: 1px solid var(--iz-line-soft); border-radius: 14px; background: #fff; }
.learning-stats i { grid-row: span 2; display: grid; place-items: center; width: 38px; height: 38px; border-radius: 11px; background: var(--primary-50); color: var(--primary-600); font-size: var(--text-number-m-size); }
.learning-stats span { color: var(--iz-ink-soft); font: var(--text-micro); }
.learning-stats b { color: var(--iz-ink); font: var(--text-number-s); }

/* ------------------------------------------------------------- outline (course table of contents) */
.learning-outline { --node: 44px; display: grid; gap: var(--space-head); }
.learning-outline__head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3); justify-content: space-between; }
.learning-outline__sum { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); margin: 0; margin-inline-start: auto; padding: 0; padding-inline-end: 2px; list-style: none; }
.learning-outline__sum li { display: inline-flex; align-items: center; gap: var(--gap-inline); color: var(--iz-ink); font: 600 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
.learning-outline__sum i { color: var(--iz-ink); font-size: var(--text-body-size); }
@media (hover: hover) and (pointer: fine) { 
.learning-outline__list { position: relative; display: grid; gap: var(--gap-list); }
.learning-outline__list::before { /* the vine: dashed, then solid for what is done */
	content: ""; position: absolute; inset-block: 30px; inset-inline-start: calc(var(--pad-row) + var(--node) / 2 - 1px); width: 2px;
	background: repeating-linear-gradient(180deg, var(--secondary-200) 0 6px, transparent 6px 11px);
}
.learning-module { position: relative; border: 1px solid var(--iz-line-soft); border-radius: 20px; background: #fff; transition: border-color .2s var(--iz-ease), box-shadow .24s var(--iz-ease); interpolate-size: allow-keywords; }
.learning-module[open] { border-color: var(--primary-100); box-shadow: var(--iz-shadow-2); }
.learning-module > summary { display: grid; grid-template-columns: var(--node) minmax(0, 1fr) auto; gap: var(--space-2); align-items: center; padding: var(--space-2) var(--pad-row); cursor: pointer; list-style: none; border-radius: 20px; }
.learning-module > summary::-webkit-details-marker { display: none; }
.learning-module > summary:focus-visible { outline: none; box-shadow: var(--iz-focus); }
.learning-module__index { position: relative; z-index: 1; display: grid; place-items: center; width: var(--node); height: var(--node); border-radius: 50%; background: #fff; border: 2px solid var(--secondary-200); color: var(--secondary-700); font: 700 var(--text-number-s-size)/var(--text-number-lh) var(--font-body); transition: background-color .2s var(--iz-ease), border-color .2s var(--iz-ease), color .2s var(--iz-ease); }
.learning-module[open] .learning-module__index { border-color: var(--secondary-500); box-shadow: 0 0 0 5px var(--secondary-50); }
.learning-module.is-done .learning-module__index { background: var(--secondary-500); border-color: var(--secondary-500); color: #fff; }
.learning-module__title { display: grid; gap: 2px; min-width: 0; }
/* A chapter title reads as a real heading now — a course's chapters are the one list on this page a
 * screen-reader user would want to navigate by heading, and it already rendered at --text-h4; a
 * `<b>` only looked like a heading. `margin: 0` because `h4` otherwise carries the UA default. */
.learning-module__title h4 { margin: 0; color: var(--iz-ink); font: var(--text-h4); text-wrap: balance; }
.learning-module__meta { display: flex; flex-wrap: wrap; gap: var(--space-0) var(--space-2); color: var(--iz-ink-soft); font: 500 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
.learning-module__meta span { display: inline-flex; align-items: center; gap: var(--space-0); }
.learning-module__meta .is-free { color: var(--secondary-700); font-weight: 600; }
.learning-module__progress { display: block; width: min(220px, 100%); margin-top: var(--space-1); }
.learning-module__caret { display: grid; place-items: center; width: 36px; height: 36px; border-radius: 10px; background: var(--iz-sunk); color: var(--iz-text); font-size: var(--text-body-size); transition: rotate .3s var(--iz-ease-out), background-color .2s var(--iz-ease); }
.learning-module[open] .learning-module__caret { rotate: 180deg; background: var(--primary-50); color: var(--primary-700); }

.learning-module::details-content { block-size: 0; overflow: clip; transition: block-size .34s var(--iz-ease-out), content-visibility .34s allow-discrete; }
.learning-module[open]::details-content { block-size: auto; }
.learning-module__sessions { display: grid; gap: 2px; margin: 0 0 var(--space-1); padding: var(--space-0) 0; border-top: 1px solid var(--iz-line-soft); border-radius: 0; list-style: none; }

.learning-session { position: relative; display: grid; grid-template-columns: 30px minmax(0, 1fr) auto auto; gap: var(--space-2); align-items: center; min-height: 52px; padding: var(--space-1) var(--pad-row); border-radius: 12px; color: var(--iz-text); font: 400 var(--text-body-s-size)/var(--text-body-s-lh) var(--font-body); transition: background-color .16s var(--iz-ease); }
.learning-session + .learning-session::before { content: ""; position: absolute; top: -1px; inset-inline: var(--space-2); height: 1px; background: var(--iz-line-soft); }
.learning-session__index { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 9px; background: var(--primary-50); color: var(--primary-600); font: 700 var(--text-micro-size)/1 var(--font-body); font-variant-numeric: tabular-nums; }
.learning-session__index--quiz { background: var(--accent-50); color: var(--accent-600); }
.learning-session__name { min-width: 0; color: var(--iz-ink); font-weight: 500; }
.learning-session__time { display: inline-flex; align-items: center; gap: var(--space-0); color: var(--iz-ink-soft); font: 500 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); font-variant-numeric: tabular-nums; white-space: nowrap; }
.learning-session__access { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-0); min-width: 88px; min-height: 30px; padding: 0 var(--pad-chip-x); border-radius: 999px; font: 600 var(--text-micro-size)/var(--text-micro-lh) var(--font-body); white-space: nowrap; }
.learning-session__access.is-locked { min-width: 0; padding: 0; color: var(--iz-ink-soft); }
/* The lock says it on its own; the word stays for screen readers only (owner, 2026-10-01). */
.learning-session__access.is-locked span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.learning-session__access.is-open { background: var(--secondary-50); color: var(--secondary-700); }
.learning-session__access.is-done { color: var(--secondary-600); }
.learning-session__access.is-free { position: relative; z-index: 2; background: var(--secondary-500); color: #fff; text-decoration: none; transition: background-color .16s var(--iz-ease), transform .16s var(--iz-ease-out); }
.learning-session__access.is-free:active { transform: scale(var(--iz-press)); }
.learning-session__access.is-free:focus-visible { outline: none; box-shadow: var(--iz-focus); }
.learning-session.is-current { background: var(--secondary-50); }
.learning-session.is-done .learning-session__name { color: var(--iz-text); }
@media (hover: hover) and (pointer: fine) {
	.learning-session:hover { background: var(--iz-sunk); }
	.learning-session__access.is-free:hover { background: var(--secondary-600); }
	.learning-module > summary:hover .learning-module__caret { background: var(--primary-50); }
}
@media (max-width: 640px) {
	.learning-outline__list::before { inset-inline-start: calc(var(--space-2) + var(--node) / 2 - 1px); }
	.learning-outline { --node: 36px; }
	.learning-module > summary { padding: var(--space-2); gap: var(--space-1); }
	.learning-module__sessions { margin: 0 0 var(--space-0); padding: 0; }
	.learning-session { grid-template-columns: 30px minmax(0, 1fr) auto auto; grid-template-areas: "index name time access"; gap: var(--space-2); padding: var(--space-1) var(--pad-row); }
	.learning-session__index { grid-area: index; }
	.learning-session__name { grid-area: name; }
	.learning-session__time { grid-area: time; }
	.learning-session__access { grid-area: access; min-width: 0; }
	.learning-session__access.is-locked span, .learning-session__access.is-done span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
}

/* ------------------------------------------------------------- fit + outcome */
.learning-fit { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-grid); }
/* Both cards white with the same quiet border — the 2026-09-19 direction reserves colour for
 * full-width bands and the one thing a page wants noticed, and a tinted «for» card beside a white
 * «not for» card also disagreed with itself: two halves of one comparison should carry the same
 * weight. The check/× icon colour is what tells them apart, same as everywhere else on this page. */
.learning-fit__card { padding: var(--pad-card); border-radius: var(--iz-r-lg); background: #fff; border: 1px solid var(--iz-line-soft); }
.learning-fit__card h3 { display: flex; align-items: center; gap: var(--gap-inline); margin: 0 0 var(--space-head); color: var(--iz-ink); font: var(--text-h4); }
.learning-fit__card ul { display: grid; gap: var(--space-stack); margin: 0; padding: 0; list-style: none; }
.learning-fit__card li { display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: var(--gap-inline); color: var(--iz-text); font: 400 var(--text-body-s-size)/var(--text-body-s-lh) var(--font-body); }
.learning-fit__card li i { margin-top: var(--space-0); font-size: var(--text-number-m-size); color: var(--secondary-600); }
.learning-fit__card--not li i { color: var(--accent-500); }
.learning-fit__card:only-child { grid-column: 1 / -1; }
@media (max-width: 720px) { .learning-fit { grid-template-columns: 1fr; } }

/* Quiet grey, not the dark teal this box used to carry: the 2026-09-19 plan keeps the dark gradient
 * for the preview alone, the one thing the page still wants noticed — decisions.md 2026-09-26. */
.learning-outcome { display: grid; gap: var(--space-3); padding: var(--pad-card); border-radius: var(--iz-r-lg); background: var(--iz-sunk); color: var(--iz-ink); }
.learning-outcome__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding-block-end: var(--space-3); border-block-end: 1px solid var(--iz-line-soft); }
.learning-outcome__head h3 { order: 1; margin: 0; color: var(--iz-ink); font: var(--text-h4); }
.learning-outcome__art { order: 2; flex: none; width: 72px; color: var(--secondary-500); }
.learning-outcome__art .art { display: block; width: 100%; height: 68px; }
.learning-outcome p { margin: 0; color: var(--iz-text); font: var(--text-body-s); }
@media (max-width: 560px) { .learning-outcome__art { width: 60px; } .learning-outcome__art .art { height: 56px; } }

/* ------------------------------------------------------------- agenda (workshop) — reuses the rail */
.learning-agenda li { display: grid; grid-template-columns: 44px minmax(0, 1fr); gap: var(--space-3); align-items: start; }
.learning-agenda__copy { padding: var(--space-1) 0 var(--space-0); }
/* Not promoted to a heading like the chapter titles above: these are rows of one ordered list under
 * one real `h2` («مسیر برگزاری»), not sections of their own a reader would navigate to by name — so
 * the fix here is the face rule (3.1), not a new heading. `var(--text-h4)` on a `<b>` put Pinar on
 * copy the 2026-09-27 census correctly reads as "not a headline"; IRANSans 600 keeps the same visual
 * weight against the caption text under it. */
.learning-agenda__copy b { display: block; color: var(--iz-ink); font: 600 var(--text-body-s-size)/var(--text-body-s-lh) var(--font-body); }
.learning-agenda__copy span { color: var(--iz-ink-soft); font: 400 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }

/* ------------------------------------------------------------- buy box
 * No longer sticky itself — `.learning-side__stick` (above) does that, the same split the article
 * page's side column uses, so the box can share the wrapper with anything else the side column
 * ever needs to hold.
 * Rebuilt 2026-09-29 (template-parts/learning/buy-panel.php says what and why): head, price box,
 * action, figures, ✓ list. */
.learning-buy { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-3); padding: var(--pad-card); border: 1px solid var(--iz-line-soft); border-radius: var(--iz-r-lg); background: #fff; box-shadow: var(--iz-shadow-3); }
/* The cover and the name of what is being bought. Not a heading: the page's h1 is the same words. */
.learning-buy__head { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: var(--space-2); align-items: center; }
.learning-buy__thumb { display: grid; place-items: center; width: 96px; aspect-ratio: 16 / 9; overflow: hidden; border-radius: 12px; background: var(--primary-50); color: var(--primary-600); font-size: var(--text-number-l-size); }
.learning-buy__thumb img { width: 100%; height: 100%; object-fit: cover; }
.learning-buy__title { display: -webkit-box; margin: 0; overflow: hidden; color: var(--iz-ink); font: 760 var(--text-body-s-size) / 2 var(--font-display); text-wrap: balance; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
.learning-buy__status { margin: 0; }
.learning-buy__progress { display: grid; gap: var(--space-1); }
.learning-buy__progress p { display: flex; justify-content: space-between; gap: var(--gap-inline); margin: 0; color: var(--iz-ink-soft); font: 500 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
.learning-buy__progress b { color: var(--iz-ink); font-variant-numeric: tabular-nums; }
.learning-buy__progress small { color: var(--iz-ink-soft); font: 500 var(--text-micro-size)/var(--text-micro-lh) var(--font-body); }

/* The price box: grey, the label on the reading side and the figure on the left (owner,
 * 2026-09-29: «price box aligned left»). `isazadeh_price_html()` (functions.php) is the one place a
 * price is built; `.price--lg` already carries the figure's size. Here it is only laid out: the
 * current price on its own line, the struck old price and the percentage under it, all packed to
 * the left. The percentage is the solid pill the offer card uses, so a sale reads the same on the
 * card and in the box. */
.learning-buy__pricebox { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-0) var(--space-2); align-items: center; padding: var(--space-2) var(--pad-row); border-radius: var(--iz-r); background: var(--iz-sunk); }
.learning-buy__pricelabel { align-self: start; padding-top: var(--space-0); color: var(--iz-ink-soft); font: 500 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
.learning-buy__price { grid-column: 2; justify-self: end; margin: 0; color: var(--iz-ink); text-align: end; }
.learning-buy__pricebox > :only-child, .learning-buy__pricebox:not(:has(.learning-buy__pricelabel)) .learning-buy__price { grid-column: 1 / -1; }
.learning-buy__price .price { display: grid; grid-template-columns: max-content max-content; justify-content: end; justify-items: end; align-items: center; gap: 2px var(--gap-inline); }
.learning-buy__price .price__now { grid-column: 1 / -1; line-height: var(--text-number-lh); }
.learning-buy__price .price--free { display: inline; }
.learning-buy__price .price__off { padding: 1px var(--space-1); border-radius: 6px; background: var(--error); color: #fff; font-weight: 700; }
.learning-buy__pricebox .learning-sale { grid-column: 1 / -1; margin-top: var(--space-1); padding-top: var(--space-1); border-top: 1px dashed var(--iz-line); }

/* A running sale's end and its countdown (template-parts/learning/sale-clock.php). Coral text, not a
 * coral box: the box is already the one grey thing in the panel, and the figure is what matters. */
.learning-sale { display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--gap-inline); margin: 0; color: var(--accent-700); font: 500 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
.learning-sale > .fa-solid { font-size: var(--text-body-size); }
.learning-sale__left { display: inline-flex; flex-wrap: wrap; gap: 0 var(--space-0); margin-inline-start: auto; font-weight: 700; }
.learning-sale__left bdi { font-variant-numeric: tabular-nums; }
.learning-sale.is-over { color: var(--iz-ink-soft); }
.learning-sale__reload { display: inline-flex; align-items: center; min-height: 32px; margin-inline-start: auto; padding: 0 var(--space-2); border: 0; border-radius: 8px; background: #fff; color: var(--primary-700); font: var(--text-button-s); cursor: pointer; }
.learning-sale__reload:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--color-focus-ring); }

/* The figures: two tiles a row, a long value (a date with its time, the rating) across both. */
.learning-buy__facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); margin: 0; padding: 0; list-style: none; }
.learning-buy__facts li { display: grid; grid-template-columns: 20px minmax(0, 1fr); gap: 0 var(--gap-inline); align-items: center; min-width: 0; padding: var(--space-2) var(--space-3); border: 1px solid var(--iz-line-soft); border-radius: 12px; }
.learning-buy__facts li.is-wide { grid-column: 1 / -1; }
.learning-buy__facts li.is-last-single { grid-column: 1 / -1; }
.learning-buy__facts i { grid-row: span 2; color: var(--primary-500); font-size: var(--text-h3-size); }
.learning-buy__facts span { color: var(--iz-ink-soft); font: 600 var(--text-micro-size) / 2 var(--font-body); }
.learning-buy__facts b { overflow-wrap: anywhere; color: var(--iz-ink); font: 500 var(--text-caption-size) / 2 var(--font-body); font-variant-numeric: tabular-nums; }
/* Workshop only (a course has no seats): the count beside the bar, both saying how much room is
 * left. Coral is kept for when that has started to matter, so it still means something when it
 * appears. */
.learning-buy__seats { display: grid; gap: var(--space-1); }
.learning-buy__seats p { display: flex; justify-content: space-between; gap: var(--gap-inline); margin: 0; color: var(--iz-ink-soft); font: 500 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
.learning-buy__seats b { color: var(--iz-ink); }
.learning-buy__seats.is-few b, .learning-buy__seats.is-full b { color: var(--accent-700); }
.learning-buy .iz-btn { width: 100%; justify-content: center; }
.learning-buy__note { margin: 0; color: var(--iz-ink-soft); font: var(--text-caption); text-align: center; }
.learning-buy__features { display: grid; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }
.learning-buy__features li { display: grid; grid-template-columns: 18px minmax(0, 1fr); gap: var(--gap-inline); align-items: start; color: var(--iz-text); font: 400 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
.learning-buy__features i { margin-top: var(--space-0); color: var(--secondary-600); font-size: var(--text-body-s-size); }
.learning-buy .iz-notice { margin: 0; }
/* The way out of a closed workshop is a real target, not a 25px line of text: kit.css gives
 * `.iz-notice a` its colour and weight and no box, which is fine beside a wide notice and not
 * beside this one, where it is the only thing left to click. */
.learning-buy .iz-notice a { display: inline-flex; align-items: center; min-height: 44px; }

/* The phone bar. Its motion rules (the drawer curve, the reduced-motion cut) are kit.css's; only
 * its layout is here. */
.learning-buybar { position: fixed; inset-inline: 0; bottom: 0; z-index: 40; display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding: var(--space-1) var(--space-3) calc(var(--space-1) + env(safe-area-inset-bottom)); background: rgb(255 255 255 / .94); backdrop-filter: blur(12px); border-top: 1px solid var(--iz-line-soft); translate: 0 110%; transition: translate .38s var(--iz-ease-drawer); }
.learning-buybar.is-shown { translate: 0 0; }
.learning-buybar__copy { display: grid; gap: 2px; min-width: 0; }
.learning-buybar b { display: block; color: var(--iz-ink); font: var(--text-number-m); }
/* buy-bar.php passes `isazadeh_price_html(..., 'sm', true)`, whose `.price--sm` (content.css) sets
 * its own font-size on the price's own element — a single class beats the size this `<b>` tries to
 * hand down by inheritance. Two classes on the price element outrank `.price--sm` alone without
 * touching content.css, which other pages' `--sm` calls still rely on. The compact percentage is
 * the offer card's solid pill, and the old price stays on the same line as the new one. */
.learning-buybar b .price.price--sm { flex-wrap: nowrap; align-items: center; gap: var(--gap-inline); font-size: var(--text-number-m-size); }
.learning-buybar b .price__was { font-size: var(--text-micro-size); }
.learning-buybar b .price__off { padding: 0 var(--space-0); border-radius: 5px; background: var(--error); color: #fff; font: 700 var(--text-micro-size)/var(--text-micro-lh) var(--font-body); }
/* The state line under the price. Only the copy's own direct span: a bare `.learning-buybar span`
 * (this rule until 2026-09-29) also reached every span inside the price and the countdown. */
.learning-buybar__copy > span { overflow: hidden; color: var(--iz-ink-soft); font: 500 var(--text-micro-size)/var(--text-micro-lh) var(--font-body); text-overflow: ellipsis; white-space: nowrap; }
.learning-buybar .learning-sale { gap: 0 var(--space-0); font-size: var(--text-micro-size); line-height: var(--text-micro-lh); }
.learning-buybar .learning-sale > .fa-solid { font-size: var(--text-caption-size); }
.learning-buybar .learning-sale__left { margin-inline-start: 0; }
/* The one action a phone thumb reaches for in this bar, so it gets the same touch-comfort bump
 * `.site-footer__support .iz-btn` already gets — not a change to `.iz-btn--small` itself, which
 * stays 40px everywhere else it is used. Measured: 74×40px before, under the 44px floor. */
.learning-buybar .iz-btn { flex: none; justify-content: center; min-inline-size: clamp(120px, 36vw, 160px); min-height: 44px; }
/* Above the phone the sticky box is always in reach, so the bar has no job. Off the page entirely
 * rather than translated out of sight: a fixed element in an RTL document still counts toward the
 * scroll width, which is how it put 90px of horizontal scroll on a 375px screen. */
@media (min-width: 861px) { .learning-buybar { display: none; } }
/* Room for the bar, the same treatment article.css gives its own fixed voice bar: without it the
 * footer's last row — the copyright line and the back-to-top button — sits under the bar forever
 * once a phone visitor reaches the true bottom of the page, with no further scroll to clear it.
 * Measured: the bar is 74px tall at 375px wide; `:has()` reserves the space whenever the bar
 * exists in the DOM, whatever its current `is-shown` state, so the footer never has to guess. */
@media (max-width: 860px) {
	body:has(.learning-buybar) { padding-bottom: calc(90px + env(safe-area-inset-bottom)); }
	body:has(.learning-buybar) .to-top { bottom: calc(102px + env(safe-area-inset-bottom)); }
}

/* The conversation becomes the page's final content block, directly before the shared footer. */
.learning-comments-band { padding-block: var(--space-section); border-top: 1px solid var(--iz-line-soft); background: #fff; }
.learning-comments-band .comments :is(.comments__invite, .comments__note, .comment__text) { line-height: 2; }

/* ------------------------------------------------------------- teacher */
/* Grey, not the blue tint this card used to carry — same reasoning as the voice card above; the
 * white stat tile inside it (`.learning-teacher__grid div`) still needs to read as a distinct
 * chip, which it does against grey the same as it did against the tint. */
.learning-teacher { display: grid; grid-template-columns: 148px minmax(0, 1fr); gap: var(--space-3) var(--space-4); align-items: center; padding: var(--pad-card); border-radius: var(--iz-r-lg); background: var(--iz-sunk); }
.learning-teacher__portrait { grid-row: span 2; align-self: start; aspect-ratio: 4 / 5; border-radius: var(--iz-leaf); background: linear-gradient(165deg, #edf5f7, #ccdccf); overflow: hidden; display: grid; place-items: center; color: var(--secondary-500); font-size: calc(var(--text-number-l-size) * 1.75); }
.learning-teacher__portrait img { width: 100%; height: 100%; object-fit: cover; }
.learning-teacher__name { margin: 0; color: var(--iz-ink); font: 600 var(--text-body-s-size)/var(--text-body-s-lh) var(--font-body); }
.learning-teacher__role { margin: 2px 0 0; color: var(--secondary-700); font: 600 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
.learning-teacher__grid { display: flex; flex-wrap: wrap; gap: var(--gap-inline); margin: var(--space-stack) 0 0; }
.learning-teacher__grid div { display: grid; padding: var(--space-1) var(--space-2); border-radius: 12px; background: #fff; }
.learning-teacher__grid span { color: var(--iz-ink-soft); font: 500 var(--text-micro-size)/var(--text-micro-lh) var(--font-body); }
.learning-teacher__grid strong { color: var(--iz-ink); font: 700 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
.learning-teacher__bio { grid-column: 2; margin: 0; color: var(--iz-text); font: var(--text-body-s); }
@media (max-width: 560px) { .learning-teacher { grid-template-columns: 96px minmax(0, 1fr); gap: var(--space-3); } .learning-teacher__portrait { grid-row: auto; } .learning-teacher__bio { grid-column: 1 / -1; margin: 0; } }

/* ------------------------------------------------------------- audio
 * The player shell (`.iz-audio`) moved to kit.css on 2026-09-19: an article can carry a voice too,
 * and an article never loads this file. Only the cover dock's own placement stays here, above.
 */

/* =====================================================================
 * Catalogues — the course archive (archive-courses.php) and the workshops page (page-workshops.php).
 *
 * Rebuilt 2026-09-26 (decisions.md) on the model the article and course pages already open with: a
 * full-width head band — crumbs, the page head with its card taken off, and the toolbar — on white
 * above a hairline, then the results on the canvas. The band is also where the page's one pattern
 * goes: kit.css's sprigs, quiet where the heading starts and present only in the room it leaves.
 * Both catalogues use `.public-wrap`, so their content starts on the header's line at every width
 * (the workshops page used to sit on its own 1120px measure, 40px inside the header at 1280).
 * ===================================================================== */
.catalog { padding-bottom: var(--space-band); }

/* ------------------------------------------------------------- the head band */
.catalog-band { padding-bottom: var(--space-block); border-bottom: 1px solid var(--iz-line-soft); background: #fff; }
.catalog-band .iz-pagestack { gap: var(--space-head); padding-block-start: var(--space-head); }
.catalog-band .iz-crumbs { margin-bottom: 0; }
/* The kit page head without its card, as `.learning-head` and `.article-head` take it: the band is
 * the ground now, and a tinted box inside a band is the nested colour the 2026-09-19 direction asks
 * to lose. No art column — see the template. */
.catalog-head.iz-pagehead { grid-template-columns: minmax(0, 1fr); padding: 0; overflow: visible; border: 0; border-radius: 0; background: none; }
.catalog-head.iz-pagehead::after { display: none; }
.catalog-head .iz-pagehead__eyebrow { font-size: var(--text-eyebrow-size); }
.catalog-head .iz-pagehead__eyebrow svg { width: 15px; height: 15px; }
.catalog-head h1 { margin-top: var(--gap-title); }
.catalog-head .iz-pagehead__summary { max-width: 62ch; margin-top: var(--gap-title); }

/* ------------------------------------------------------------- toolbar */
.catalog-tools { margin-top: var(--space-1); }
/* Bases small enough that the search, both selects, the button and «پاک‌کردن» share one row from
 * 721px up (160 + 140 + 140 + the button's 128 + the link's ~75 + gaps = 683px, inside the 689px
 * container at 721); the search takes whatever is left over. kit.css's 260/200 bases broke the row at
 * 768 and left «نمایش نتیجه» alone on a second line. A third select (course categories, once the
 * owner creates any) still wraps below 1024. */
.catalog-tools .iz-search { flex: 1 1 160px; }
.catalog-tools .iz-select { flex: 0 1 140px; }
@media (min-width: 1024px) { .catalog-tools .iz-select { flex-basis: 180px; } }
.catalog-tools__clear { gap: var(--space-0); padding-inline: var(--space-0); color: var(--iz-ink-soft); transition: color .16s var(--iz-ease), transform .16s var(--iz-ease-out); }
.catalog-tools__clear .fa-solid { font-size: var(--text-body-s-size); }
.catalog-tools__clear:active { transform: scale(var(--iz-press)); }
@media (hover: hover) and (pointer: fine) { .catalog-tools__clear:hover { color: var(--iz-ink); } }
@media (max-width: 720px) {
	/* Below 720px kit.css folds the selects into the sheet. What is left of this form is the search
	 * (the keyboard's search key submits it) — or on the workshops page nothing at all — so the
	 * «نمایش نتیجه» button would only repeat that key, or submit an empty form. The search and the
	 * «فیلترها» button then share one row: 160px is the floor below which the search takes a row of
	 * its own. */
	.catalog-tools__go { display: none; }
	.catalog-tools .iz-search { flex: 1 1 160px; }
}

/* ------------------------------------------------------------- the phone filter sheet
 * A native popover (the template says why), drawn as a bottom sheet: it rises from the edge the
 * thumb is already at, on the drawer curve, and leaves faster than it came. @starting-style gives
 * the entry without a line of script; `overlay` and `display` are discrete so the exit can finish
 * before the popover leaves the top layer. Reduced motion is the global rule in tokens.css. */
.catalog-sheet {
	position: fixed; inset: auto 0 0; width: min(100%, 560px); max-height: min(88dvh, 640px); margin: 0 auto; padding: 0;
	overflow: auto; overscroll-behavior: contain;
	border: 0; border-radius: var(--iz-r-lg) var(--iz-r-lg) 0 0; background: #fff; color: var(--iz-text);
	box-shadow: 0 -12px 40px rgb(20 46 55 / .16);
	transform: translateY(100%);
	transition: transform .22s var(--iz-ease-out), overlay .22s allow-discrete, display .22s allow-discrete;
}
/* Two rules, not one list: a browser without :popover-open drops the whole rule it appears in. */
.catalog-sheet:popover-open { transform: none; transition-duration: .4s; transition-timing-function: var(--iz-ease-drawer); }
@starting-style { .catalog-sheet:popover-open { transform: translateY(100%); } }
.catalog-sheet::backdrop { background: rgb(20 46 55 / 0); transition: background-color .22s var(--iz-ease-out), overlay .22s allow-discrete, display .22s allow-discrete; }
.catalog-sheet:popover-open::backdrop { background: rgb(20 46 55 / .36); transition-duration: .32s; }
@starting-style { .catalog-sheet:popover-open::backdrop { background: rgb(20 46 55 / 0); } }
.catalog-sheet__form { display: grid; gap: var(--gap-form); padding: var(--space-3) var(--space-3) calc(var(--space-3) + env(safe-area-inset-bottom)); }
.catalog-sheet__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); margin-inline-end: -6px; }
.catalog-sheet__head .iz-h2 { margin: 0; }
/* The heading takes focus when the sheet opens so a screen reader starts at its name; it is not a
 * control, so it draws no ring. */
.catalog-sheet__head .iz-h2:focus { outline: none; }
.catalog-sheet__head .iz-iconbtn { border-color: transparent; }
.catalog-sheet .iz-select { width: 100%; }
.catalog-sheet__foot { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--gap-inline); }
.catalog-sheet__foot > :only-child { grid-column: 1 / -1; }

/* ------------------------------------------------------------- results */
.catalog-results { padding-top: var(--space-block); }
.catalog-results__head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-0) var(--space-3); margin-bottom: var(--space-head); }
.catalog-count { margin: 0; color: var(--iz-ink-soft); font: 500 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
.catalog-count b { color: var(--iz-ink); font-weight: 700; }

/* The grid: three a row from 1024px, two from 640px, one below. Fixed counts rather than auto-fill
 * so a short list keeps a card's width and leaves the rest of the row empty instead of stretching
 * one card across the page. The two-up track stops at 444px, the native width of the card art
 * (card-course.webp), so between 969 and 1023px a fallback cover is never drawn wider than its
 * pixels; below that the tracks are narrower anyway. Rows stretch, so cards in a row match heights. */
.catalog-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--gap-grid); }
@media (min-width: 640px) { .catalog-grid { grid-template-columns: repeat(2, minmax(0, 444px)); } }
/* `--gap-grid` is 24px from 1280: three tracks of a 1200px container are 384px, whole pixels,
 * so card edges and cover images are not resampled across a half pixel. */
@media (min-width: 1024px) { .catalog-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.catalog-grid > .iz-empty { grid-column: 1 / -1; }
/* The workshops page: two a row at every width from 640px. A workshop card is a horizontal ticket
 * — the date tile beside the details — and in a third of the row (388px, 308px at 1024) its title
 * broke onto two lines and its three chips onto two or three rows; at half the row (591px, 471px)
 * each is one line and the card is 62px shorter. The wireframe's own work grid is two columns. No
 * 444px cap: these cards carry no cover art. */
@media (min-width: 640px) { .catalog-grid--pairs { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Below 640px this is one column, and from 640px it is exactly two — a workshop card here is
 * roughly half this grid's own inline size at every width the grid ever reaches. Naming the *grid*
 * `home-offer` (the first attempt) used that grid width as the query's input, which is wrong at
 * exactly the width that matters: two-up at 768px puts each card at ~340px, well under the 459px
 * stacking threshold, but the 768px-wide grid itself sailed straight past it and never stacked. The
 * card needs its own container — `.offer-grid__item` above wraps every offer-card call in the
 * `upcoming` list (this grid's other caller, the `past` list, uses its own row markup, not the offer
 * card, so it needs no wrapper). decisions.md, offer-card v3 run 3. */

/* ------------------------------------------------------------- workshops: the two lists */
.catalog-sec { padding-top: var(--space-block); }
.catalog-sec + .catalog-sec { padding-top: var(--space-section); }
.catalog-sec__head { display: grid; gap: 0; margin-bottom: var(--space-head); }
.catalog-sec__head .iz-h2 { margin: 0; }
/* The count belongs to the heading it counts. kit.css pushes `.iz-h2 small` to the far end of the
 * row, which at 1280 put «۱ کارگاه» 1,000px away from «کارگاه‌های پیش‌رو». */
.catalog-sec__head .iz-h2 small { margin-inline-start: var(--space-0); }
.catalog-sec__note { margin: 0; color: var(--iz-ink-soft); font: var(--text-caption); }

/* Past workshops: a quieter row than the offer card — no price, no action, a grey date — laid on
 * the same columns as the upcoming cards so the two lists share one grid. The whole row is the
 * title's link (kit `.iz-stretch`), so the row answers the press; `scale` rather than `transform`
 * because nothing here owns transform, and so it never fights a future hover lift. */
.catalog-past__row { display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: var(--space-2); align-items: start; padding: var(--pad-row); border: 1px solid var(--iz-line-soft); border-radius: var(--iz-r); background: #fff; transition: border-color .2s var(--iz-ease), box-shadow .2s var(--iz-ease), scale .16s var(--iz-ease-out); }
.catalog-past__row:has(.iz-stretch:active) { scale: var(--iz-press-lg); }
.catalog-past__copy { display: grid; gap: var(--gap-title); min-width: 0; }
.catalog-past__row h3 { display: -webkit-box; margin: 0; overflow: hidden; color: var(--iz-ink); font: var(--text-h4); -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
.catalog-past__row h3 a { color: inherit; text-decoration: none; }
.catalog-past__row p { display: -webkit-box; margin: 0; overflow: hidden; color: var(--iz-text); font: 400 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
.catalog-past__when { color: var(--iz-ink-soft); font: 500 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
@media (hover: hover) and (pointer: fine) { .catalog-past__row:hover { border-color: var(--primary-100); box-shadow: var(--iz-shadow-1); } }
/* Workshop venue: its own section under the schedule (2026-09-30). */
.learning-venue__address { display: flex; gap: var(--space-1); align-items: start; margin: 0; color: var(--iz-text); font: var(--text-body-s); }
.learning-venue__address .fa-solid { flex: none; margin-top: .45em; color: var(--iz-ink-soft); }
.learning-venue .iz-venue-map { max-height: 320px; margin-top: var(--space-2); }
.learning-venue__go { justify-self: start; width: fit-content; margin-top: var(--space-2); transition: transform 160ms var(--iz-ease-out); }
.learning-venue__go:active { transform: scale(.97); }
@media (max-width: 600px) { .learning-venue__go { justify-self: stretch; width: 100%; justify-content: center; } }

/* The teacher's intro voice, a light card in the content column (it was a dark overlay on the cover). */
.learning-voice b { display: block; color: var(--iz-ink); font: 600 var(--text-caption-size)/var(--text-caption-lh) var(--font-body); }
.learning-voice small { display: block; color: var(--iz-ink-soft); font: 400 var(--text-micro-size)/var(--text-micro-lh) var(--font-body); }
