/* ===========================================================================
   lg.library — "All texts", grouped four ways
   ---------------------------------------------------------------------------
   The sibling of lg.topics.css. The head, the segmented switch and the group
   headings are NEAR-COPIES of that file's, deliberately and visibly:

       .lg-library
         input.lg-library__switch  ×4       (radios, visually hidden)
         .lg-library__head
           .lg-library__intro              title + lead
           .lg-library__views              the pills
           .lg-library__jump  ×2          jump buttons, over "level"/"group"
         .lg-library__view--level          groups: Level A1, Level A2 …
         .lg-library__view--group          groups: Everyday life, School …
         .lg-library__view--new            groups: September 2026, August …
         .lg-library__view--popular        one unheaded group
           .lg-library__group
             .lg-library__group-head       name + "8 texts"
             .lg-library__grid
               a.lg-card  ×n               (lg.suggestions.css owns the card)

   WHY NEAR-COPIES AND NOT SHARED RULES

   The two switches are keyed by radio id - #lg-topics-level:checked ~ … -
   because that is the only way CSS can reach a control's state, and two
   switches on two pages cannot share an id. Renaming the grammar block to
   something generic would mean editing the page this site ships today to suit
   one that is still being drawn. Where a rule here matches one there, they are
   meant to stay in step; lg.exercise-text.css says the same thing about
   lg.exercise-mc.css for the same reason.

   THE CARDS ARE NOT STYLED HERE. They are lg_suggestion_card()'s, and the page
   wraps this section in .lg-texts so they get the reading treatment - no head,
   the facts and the bar on one line, the teaser clamped. See lg.texts.css.
   =========================================================================== */

.lg-library {
	padding: 1rem 0 1rem;
}

/* --- Head: title + view switch ------------------------------------------ */
.lg-library__head {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	margin-bottom: 1.75rem;
}

/* min-width:0 so a long lead wraps instead of pushing the pills off the row. */
.lg-library__intro {
	flex: 1 1 18rem;
	min-width: 0;
}

.lg-library__title {
	margin: 0;
	color: var(--lg-text);
	font-family: var(--lg-font-heading);
	font-size: clamp(1.35rem, 1.1rem + 0.8vw, 1.7rem);
	font-weight: 700;
	line-height: 1.2;
	letter-spacing: -0.01em;
}

.lg-library__lead {
	margin: 0.4rem 0 0;
	max-width: 82ch;
	color: var(--lg-text-muted);
	font-family: var(--lg-font);
	font-size: 1rem;
	line-height: 1.5;
}

/* The edge-fade widths of the swiped track (see the narrow block). Registered
   so a transition can animate them; unregistered custom properties snap. */
@property --lg-fade-start {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

@property --lg-fade-end {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

/* One pill-shaped track holding the labels, like a segmented control. */
.lg-library__views {
	display: inline-flex;
	align-items: center;
	flex-wrap: wrap;
	padding: 0.4rem;
	border: 1px solid var(--lg-border);
	border-radius: 999px;
	background-color: var(--lg-surface);
}

.lg-library__view-label {
	display: inline-flex;
	align-items: center;
	padding: 0.6rem 1.1rem;
	border-radius: 999px;
	color: var(--lg-text-muted);
	font-family: var(--lg-font);
	font-size: 0.95rem;
	font-weight: 600;
	line-height: 1.2;
	white-space: nowrap;
	cursor: pointer;
	user-select: none;
	transition: background-color 0.15s ease, color 0.15s ease;
}

.lg-library__view-label:hover {
	color: var(--lg-text);
}

.lg-library__switch {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
}

/* The selected pill. Written out per view rather than generated, because a
   radio can only be reached by an id-specific sibling selector. */
#lg-library-level:checked   ~ .lg-library__head .lg-library__view-label[for="lg-library-level"],
#lg-library-group:checked   ~ .lg-library__head .lg-library__view-label[for="lg-library-group"],
#lg-library-new:checked     ~ .lg-library__head .lg-library__view-label[for="lg-library-new"],
#lg-library-popular:checked ~ .lg-library__head .lg-library__view-label[for="lg-library-popular"] {
	background-color: var(--lg-red);
	color: var(--lg-text-inverse);
	text-shadow: 1px 1px 1px #94332f;
}

/* A <label> is not focusable; the ring comes from the radio it drives. */
#lg-library-level:focus-visible   ~ .lg-library__head .lg-library__view-label[for="lg-library-level"],
#lg-library-group:focus-visible   ~ .lg-library__head .lg-library__view-label[for="lg-library-group"],
#lg-library-new:focus-visible     ~ .lg-library__head .lg-library__view-label[for="lg-library-new"],
#lg-library-popular:focus-visible ~ .lg-library__head .lg-library__view-label[for="lg-library-popular"] {
	outline: 2px solid var(--lg-red);
	outline-offset: 2px;
}

/* --- The category jump bar ----------------------------------------------- */
/* A table of contents for the category view, not a filter: every button lands
   on a heading that is already on the page. That is why it can be plain
   anchors and needs no script - and why the buttons say a count, which is the
   one thing the heading below cannot tell you before you get there.

   Drawn only over the category view. The radios sit before .lg-library__head,
   so the same sibling trick that colours the chosen pill reaches this too. */
.lg-library__jump {
	display: none;

	/* .lg-library__head is a flex row with space-between, so without this the
	   bar would line up BESIDE the pills and be pushed to the far edge. A
	   full-width basis drops it onto its own line under them, which is where
	   it belongs - it is about the view the pills choose, not a peer of them.
	   The line's spacing comes from the head's own gap; a margin here would be
	   added to that rather than replacing it. */
	flex: 0 0 100%;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
}

/* Each bar belongs to one view and is hidden with it. Written out per view
   for the same reason the pill rules above are: a radio can only be reached
   by an id-specific sibling selector. */
#lg-library-level:checked ~ .lg-library__head .lg-library__jump--level,
#lg-library-group:checked ~ .lg-library__head .lg-library__jump--group {
	display: flex;
}

.lg-library__jump-link,
.lg-library__jump-more {
	display: inline-flex;
	align-items: center;
	gap: 0.45rem;
	padding: 0.45rem 0.9rem;
	border: 1px solid var(--lg-border);
	border-radius: 999px;
	background-color: var(--lg-surface);
	color: var(--lg-text);
	font-family: var(--lg-font);
	font-size: 0.9rem;
	line-height: 1.2;
	white-space: nowrap;
	text-decoration: none;
	cursor: pointer;
	user-select: none;
	transition: border-color 0.15s ease, color 0.15s ease;
}

.lg-library__jump-link:hover,
.lg-library__jump-more:hover {
	border-color: var(--lg-text-muted);
	color: var(--lg-text);
	text-decoration: none;
}

.lg-library__jump-link:focus-visible {
	outline: 2px solid var(--lg-red);
	outline-offset: 2px;
}

/* Lighter and smaller than the name it follows: it is a quantity, not a
   label, and at equal weight the two read as one long name. */
.lg-library__jump-count {
	color: var(--lg-text-muted);
	font-size: 0.8rem;
	font-weight: 500;
}

/* Dashed, as in the drawing. The solid ones take you somewhere; this one only
   unfolds the rest of the row, and the border says which kind it is before it
   is pressed. */
.lg-library__jump-more {
	border-style: dashed;
	color: var(--lg-text-muted);
}

.lg-library__jump-switch {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
}

.lg-library__jump-switch:not(:checked) ~ .lg-library__jump-link--extra {
	display: none;
}

/* One way. Once the row is open there is nothing to collapse back to - the
   button that would do it has just been replaced by the categories it was
   hiding, and a row that can fold itself away again invites hunting for a
   category that is there but out of sight. */
.lg-library__jump-switch:checked ~ .lg-library__jump-more {
	display: none;
}

/* A <label> is not focusable; the ring comes from the checkbox it drives. */
.lg-library__jump-switch:focus-visible ~ .lg-library__jump-more {
	outline: 2px solid var(--lg-red);
	outline-offset: 2px;
}

/* --- Which view is showing ---------------------------------------------- */
.lg-library__view {
	display: none;
}

#lg-library-level:checked   ~ .lg-library__view--level,
#lg-library-group:checked   ~ .lg-library__view--group,
#lg-library-new:checked     ~ .lg-library__view--new,
#lg-library-popular:checked ~ .lg-library__view--popular {
	display: block;
}

/* The level view hides the level pill on its own cards: every card under
   "Level A1" is A1, and repeating it turns a label into noise. The pill is
   still emitted, so the same card markup serves all four views - the same
   trade lg.topics.css makes with its tags. */
#lg-library-level:checked ~ .lg-library__view--level .lg-card__level {
	display: none;
}

/* And the popularity view hides the flame, for the same reason one step on:
   there the whole list IS the ranking, the top thirty are the first thirty
   cards, and a mark saying "popular" beside a number saying 4 is the same
   fact twice. lg.topics.css:153 makes exactly this trade for the grammar
   topics. */
.lg-library__view--popular .lg-badge--popular {
	display: none;
}

/* --- A deferred view, before it has loaded ------------------------------
   See DEFERRED VIEWS in _components/lg-library.php. Without the script the
   shell shows its link, which opens the page on that view. With it
   (.lg-library--js) the link gives way to a spinner while loading, and comes
   back - with the reason beside it - if the load fails. */
.lg-library__pending {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 0.6rem;
	min-height: 8rem;
	padding: 2rem 0;
}

.lg-library__fallback {
	display: inline-flex;
	align-items: center;
	padding: 0.6rem 1.1rem;
	border: 1px solid var(--lg-border);
	border-radius: 999px;
	background-color: var(--lg-surface);
	color: var(--lg-text);
	font-family: var(--lg-font);
	font-size: 0.95rem;
	font-weight: 600;
	text-decoration: none;
}

.lg-library__fallback:hover {
	border-color: var(--lg-red);
}

.lg-library__spinner {
	display: none;
	width: 1.75rem;
	height: 1.75rem;
	border: 3px solid var(--lg-border);
	border-top-color: var(--lg-red);
	border-radius: 50%;
	animation: lg-library-spin 0.8s linear infinite;
}

@keyframes lg-library-spin {
	to { transform: rotate(360deg); }
}

.lg-library__error {
	flex-basis: 100%;
	color: var(--lg-text-muted);
	font-family: var(--lg-font);
	font-size: 0.85rem;
	text-align: center;
}

.lg-library--js .lg-library__spinner {
	display: block;
}

.lg-library--js .lg-library__fallback {
	display: none;
}

.lg-library--js [data-lg-library-state="failed"] .lg-library__spinner {
	display: none;
}

.lg-library--js [data-lg-library-state="failed"] .lg-library__fallback {
	display: inline-flex;
}

/* --- A group ------------------------------------------------------------ */
/* NOT DRAWN UNTIL NEAR THE SCREEN. A level group can hold a hundred cards;
   content-visibility:auto lets the browser skip layout and paint for every
   group out of view, which is most of them on a long shelf. The cards are
   still in the page - find-in-page, links and screen readers all reach them.

   contain-intrinsic-size is the stand-in height for a group not drawn yet;
   "auto" makes the browser remember the real one once it has been, so the
   scrollbar settles instead of jumping each time. 40rem is a mid-sized
   group - too small for a big level, too big for a month, and only ever a
   placeholder. Browsers without it simply draw everything, as before.

   THE PADDING IS FOR THE HOVER SHADOW. content-visibility clips painting to
   the group's box, and a hovered card's shadow (lg.suggestions.css,
   a.lg-card:hover: 0 10px 24px) reaches about 2rem below the last row and
   1.5rem to the sides. The padding makes that room inside the box; the
   negative margin takes it back out, so the cards stay where they were. 1rem
   at the sides, not 1.5rem: on a phone .content's side padding is 1rem, and
   more would push the page wider than the screen - the faint outer edge of
   the shadow is the part that gets cut. The 2rem at the foot comes off the
   gap to the next group below, which keeps the 2.5rem between them. */
.lg-library__group {
	content-visibility: auto;
	contain-intrinsic-size: auto 40rem;
	margin-right: -1rem;
	margin-left: -1rem;
	padding: 0 1rem 2rem;
}

/* NO scroll-margin-top here, deliberately. Every group is a jump target and
   does need to clear the fixed header, but lg.core.css:82 already reserves
   that space for the whole site with

     html { scroll-padding-top: calc(var(--lg-header-offset) + 1rem) }

   and scroll-padding on the scroller ADDS to scroll-margin on the target. A
   rule here landed each heading about two header-heights down the screen.
   Anything this layer wants to be jumped to is covered by the core; if a
   target ever needs more, it wants the difference, not the whole offset. */
.lg-library__group + .lg-library__group {
	margin-top: 0.5rem;   /* + the 2rem padding above it = 2.5rem */
}

.lg-library__group-head {
	display: flex;
	align-items: baseline;
	gap: 0.6rem;
	margin-bottom: 0.9rem;
}

.lg-library__group-name {
	margin: 0;
	color: var(--lg-text);
	font-family: var(--lg-font-heading);
	font-size: 1.2rem;
	font-weight: 700;
	line-height: 1.25;
}

.lg-library__group-meta {
	color: var(--lg-text-muted);
	font-family: var(--lg-font);
	font-size: 0.95rem;
	line-height: 1.3;
}

/* Under the heading, above the cards. Only the category view has one — a
   level and a month describe themselves. */
.lg-library__group-desc {
	margin: -0.5rem 0 0.9rem;
	max-width: 70ch;
	color: var(--lg-text-muted);
	font-family: var(--lg-font);
	font-size: 0.95rem;
	line-height: 1.5;
}

/* --- The grid ----------------------------------------------------------- */
/* The same floor as the suggestion grid in lg.texts.css, and for the same
   reason: these cards carry a sentence of the text, which at 275px wraps to
   four or five words a line. */
.lg-library__grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
	gap: 0.7rem;
}

@media (max-width: 420px) {

	.lg-library__grid {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* --- The premium reveal -------------------------------------------------- */
/* Locked texts sit in the same grid, after the free ones, hidden until the
   button is pressed. A checkbox and a <label>, like the "show more" in
   lg.suggestions.css: it works before any script has loaded, cannot be broken
   by a JS error elsewhere, and is still keyboard-operable.

   The switch is INSIDE the grid, immediately before the locked cards, so ~
   reaches them and reaches nothing in any other group. The free cards are
   before it and are never touched. */
.lg-library__more-switch {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
}

.lg-library__more-switch:not(:checked) ~ .lg-card--locked {
	display: none;
}

/* Once they are open the button has nothing left to say. There is no "show
   less": nobody asks to re-hide what they came to look at. */
.lg-library__more-switch:checked ~ .lg-library__more {
	display: none;
}

/* Its own row under the cards rather than a cell in the grid: it is about the
   group, not one more text in it. */
.lg-library__more {
	grid-column: 1 / -1;
	justify-self: start;
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	padding: 0.6rem 1.15rem;
	border: 1px solid var(--lg-border);
	border-radius: 999px;
	background-color: var(--lg-surface);
	color: var(--lg-text);
	font-family: var(--lg-font);
	font-size: 0.95rem;
	font-weight: 600;
	line-height: 1.2;
	cursor: pointer;
	user-select: none;
	transition: border-color 0.15s ease, background-color 0.15s ease;
}

.lg-library__more:hover {
	border-color: var(--lg-border-strong);
	background-color: var(--lg-bg);
}

/* The deferred reveal is a link (see DEFERRED VIEWS in lg-library.php); it
   has to look like the label it replaces. */
a.lg-library__more,
a.lg-library__more:hover {
	color: var(--lg-text);
	text-decoration: none;
}

a.lg-library__more:focus-visible {
	outline: 2px solid var(--lg-red);
	outline-offset: 2px;
}

/* Fetching: the padlock turns into the spinner's ring for the second or so
   it takes. */
a.lg-library__more[data-lg-library-state="loading"] {
	cursor: progress;
}

a.lg-library__more[data-lg-library-state="loading"] .lg-library__more-icon {
	border: 2px solid var(--lg-border);
	border-top-color: var(--lg-red);
	border-radius: 50%;
	stroke: none;
	animation: lg-library-spin 0.8s linear infinite;
}

/* The reason a reveal failed, on its own row in the grid under the button. */
.lg-library__grid > .lg-library__error {
	grid-column: 1 / -1;
	text-align: left;
}

.lg-library__more-switch:focus-visible ~ .lg-library__more {
	outline: 2px solid var(--lg-red);
	outline-offset: 2px;
}

.lg-library__more-icon {
	flex: 0 0 auto;
	width: 1.05rem;
	height: 1.05rem;
	color: var(--lg-text-muted);
}

/* --- Narrow -------------------------------------------------------------- */
@media (max-width: 620px) {

	/* The switch drops under the title rather than squeezing beside it: four
	   pills and a heading do not share a phone's width. */
	.lg-library__head {
		flex-direction: column;
		align-items: flex-start;
	}

	/* Same trap as the jump bar below: in a column, the intro's 18rem
	   flex-basis is a HEIGHT, and a two-line title and lead sat in an 18rem
	   box with the gap under them. Sized by its content again, full width. */
	.lg-library__intro {
		flex: 0 0 auto;
		width: 100%;
	}

	/* ONE LINE, SWIPED. Four labels in German or French do not fit a phone,
	   and wrapped onto two rows the 999px radius turns the track into a
	   lozenge that no longer reads as one control. So the track keeps its
	   single row and scrolls sideways, as .lg-topics__views does on grammar.
	   The pill cut off at the right edge is the hint that there is more.

	   The scrollbar is hidden rather than thinned: under a pill track it is a
	   grey line that looks like a rendering fault, and touch users swipe
	   without it. overscroll-behavior stops a swipe at the end of the track
	   from turning into the browser's back gesture. */
	.lg-library__views {
		max-width: 100%;
		flex-wrap: nowrap;
		overflow-x: auto;
		overscroll-behavior-x: contain;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
	}

	.lg-library__views::-webkit-scrollbar {
		display: none;
	}

	/* EDGE FADES. Pills ran hard into the track's edge; now the side that
	   has more to swipe to fades out. A mask on the track itself, so the
	   fade stays put while the pills scroll under it, and the track's own
	   border fades with them - which is the "it carries on" hint.

	   Which side fades is the scroll position, and CSS cannot read that
	   everywhere yet, so main2025.js (initViewTrackFades) sets is-fade-start
	   and is-fade-end. Without the script there are simply no fades. The
	   widths are registered with @property (top of file) so they animate in
	   rather than snapping. */
	.lg-library__views {
		-webkit-mask-image: linear-gradient(to right, transparent, #000 var(--lg-fade-start), #000 calc(100% - var(--lg-fade-end)), transparent);
		        mask-image: linear-gradient(to right, transparent, #000 var(--lg-fade-start), #000 calc(100% - var(--lg-fade-end)), transparent);
		transition: --lg-fade-start 0.2s ease, --lg-fade-end 0.2s ease;
	}

	.lg-library__views.is-fade-start {
		--lg-fade-start: 2.5rem;
	}

	.lg-library__views.is-fade-end {
		--lg-fade-end: 2.5rem;
	}

	/* A scroll container sizes to its content; without this a pill would be
	   squeezed instead of the track scrolling. */
	.lg-library__view-label {
		flex: 0 0 auto;
	}

	.lg-library__view-label {
		padding: 0.45rem 0.85rem;
		font-size: 0.9rem;
	}

	/* The head is a column at this width, which makes flex-basis a HEIGHT -
	   the 100% basis the bar carries in the row layout would set its height to
	   the whole head. Back to sizing itself, and full width the ordinary way;
	   align-items:flex-start above would otherwise shrink it to its buttons. */
	.lg-library__jump {
		flex: 0 0 auto;
		width: 100%;
	}

	/* The same trim the view labels take, so the two rows stay one family. */
	.lg-library__jump-link,
	.lg-library__jump-more {
		padding: 0.4rem 0.75rem;
		font-size: 0.85rem;
	}
}
