/* Lore — reusable components: cards, rows, modals, sheets, skeletons, comments. */

/* Story card */
.lore-card {
	display: block; width: 152px; flex: none; text-decoration: none;
	border-radius: var(--radius-md); overflow: hidden;
}
/* R5 token parity (spec/R5_wattpad_measure.md §B.8/§C.4/§C.5): Wattpad
   hard-pins the cover BOX to 0.64:1 (5:8) and its radius to 4px, with no
   card box-shadow anywhere. Our real covers measure 0.626-0.777 (not a
   uniform 0.64), so the box is fixed and the image uses object-fit:contain
   against the wrap's own neutral --paper-alt fill instead of `cover` — this
   letterboxes off-ratio covers instead of cropping/distorting real art. */
.lore-card__cover-wrap { position: relative; aspect-ratio: 0.64; border-radius: 4px; overflow: hidden; background: var(--paper-alt); box-shadow: none; }
.lore-card__cover { width: 100%; height: 100%; object-fit: contain; background: var(--paper-alt); }
.lore-card__ribbon {
	position: absolute; top: 8px; left: 8px; background: var(--teal); color: #fff;
	font-size: .75rem; font-weight: 700; padding: 3px 8px; border-radius: var(--radius-pill);
}
.lore-card__mature { position: absolute; top: 8px; right: 8px; background: rgba(29,29,31,.75); color: #fff; font-size: .75rem; font-weight: 700; padding: 3px 6px; border-radius: 4px; }
/* R5 token parity (spec §C.2): Wattpad card titles are weight 600, not 700
   — ours read heavier than the reference. Size kept (our cards are narrower
   than Wattpad's own 232px library card; 16px would wrap too aggressively
   at the new ~120-150px shelf width below). */
.lore-card__title { margin: var(--space-2) 0 2px; font-size: .875rem; font-weight: 600; line-height: 1.3; color: var(--ink); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.lore-card__author { font-size: .75rem; color: var(--ink-faint); margin-bottom: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lore-card__tags { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 4px; }
/* R5 (qa/r5/CSS_PARITY_R5.md, mobile-hero defect #2): same Indic-descender
   line-height risk as .lore-btn — checked directly, this tag pill shares
   the fault (default line-height, no room for stacked Bengali/Tamil
   conjuncts), fixed the same way. */
.lore-card__tag { font-size: .75rem; font-weight: 600; line-height: 1.6; color: var(--ink-soft); background: var(--paper-alt); border-radius: var(--radius-pill); padding: 2px 8px; white-space: nowrap; }
.lore-card__excerpt { font-size: .75rem; color: var(--ink-soft); line-height: 1.4; margin: 2px 0 6px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.lore-card__stats { display: flex; gap: var(--space-3); font-size: .75rem; color: var(--ink-faint); }
.lore-card__stats span { display: inline-flex; align-items: center; gap: 3px; }
.lore-card__stats .lore-icon { width: 13px; height: 13px; }
.lore-card--grid { width: 100%; }
.lore-card--wide { width: 100%; }

/* Rows / rails (R5: `.lore-row` itself is on base.css's shared boxed-
   container allow-list now — max-width/centring/gutter come from there, so
   this rule keeps ONLY its own vertical rhythm, longhand margin-top/bottom
   so it never clobbers the shared rule's margin-left/right:auto centring.
   `.lore-row__head` and `.lore-row__track` are plain in-flow children of
   that box now (no box/padding of their own) — this is what keeps the
   shelf heading and its horizontally-scrolling card rail sharing one edge
   instead of the heading being boxed while the track ran full-bleed
   (qa/r5/LORE_LAYOUT_DEFECTS.md D1/D3/D4). The track is still clipped
   exactly at the row's own content edge (overflow-x:auto on a 100%-width
   child of the padded box), Wattpad's own technique — no negative margins,
   no full-bleed escape. */
/* R5 vertical rhythm (spec §A.5/A.4, qa/r5/CSS_PARITY_R5.md): Wattpad's
   shelf wrapper uses PADDING `8px 0 14px`, not margin — two adjacent
   shelves' 24px/24px margins were rendering ~40-48px apart (margin
   collapsing between siblings is inconsistent depending on DOM structure;
   this is exactly what produced the "ours reads ~40px" defect). Padding
   never collapses, so two adjacent .lore-row sections always sum to a flat
   22px (14 + 8) regardless of markup, matching Wattpad at every width. */
.lore-row { padding-top: 8px; padding-bottom: 14px; margin: 0; }
.lore-row__head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 6px; }
/* R5 section-heading type target (spec/R5_LAYOUT_TARGET.md §4): 20px/28px/700,
   Wattpad's rgb(18,18,18) is effectively identical to --ink (#1d1d1f) in light
   mode — using the token instead of the literal keeps this legible in dark mode
   too (rgb(18,18,18) would be near-invisible against the dark-mode --paper).
   Heading->row gap: 6px (Wattpad's own h3 margin-bottom, spec §A.4), was 12px. */
.lore-row__head h2 { margin: 0; font-size: 1.25rem; line-height: 1.4; font-weight: 700; color: var(--ink); }
/* R4 responsive audit (item 10): "See all" is baseline-aligned next to the
   row's <h2> (19px tall) — invisible-hit-area expansion instead of
   min-height so the visual baseline alignment with the heading is
   untouched. */
.lore-row__head a { position: relative; font-size: .8rem; color: var(--ember-text); font-weight: 600; }
.lore-row__head a::after { content: ''; position: absolute; top: -12px; right: -8px; bottom: -12px; left: -8px; }
.lore-row__track {
	display: flex; gap: 8px; overflow-x: auto;
	/* R5: 4px top padding gives a keyboard-focused card's outline (2px +
	   2-3px offset) room so it isn't clipped by the track's own box edge —
	   overflow-x:auto on a box with no top inset otherwise clips the ring
	   flush against the card, confirmed live by tabbing through a shelf. */
	padding: 4px 0 var(--space-2);
	scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
	/* R5 (spec §A.3, qa/r5/CSS_PARITY_R5.md item 9): Wattpad shows no
	   scrollbar chrome at all (it moves the list via transform, not native
	   scroll) — every Lore shelf showed a permanent grey scrollbar. Native
	   overflow scrolling is kept (better on touch, a deliberate choice), just
	   its chrome is hidden; reachability stays intact via the arrows below
	   (unchanged visibility logic, still keyboard-focusable whenever shown)
	   and native focus-into-view scrolling for Tab. */
	scrollbar-width: none;
}
.lore-row__track::-webkit-scrollbar { display: none; }
.lore-row__track > * { scroll-snap-align: start; }

/* R5 token parity (spec §B.1/§B.6): shelf card sized as a PERCENTAGE of the
   track, not our old fixed 152px (which only fit ~7 cards across the 1152px
   desktop track vs Wattpad's measured 9 at 1440). Reproduces the
   *behaviour* Wattpad uses (calc(11.11% - 7.11px), JS-driven) — not its
   literal 92px cover-only number, since our card still carries
   title/author/tags text that a bare cover doesn't need room for; tuned
   instead against Wattpad's own text-forward "Continue reading" card
   (120.9px at 1440, spec §B.1), which this now matches almost exactly at
   the same width (--shelf-cards:9 here -> ~121px). --shelf-cards is a
   cards-visible-per-screen target, one card count per breakpoint tier. */
.lore-row__track > .lore-card {
	--shelf-cards: 2.4;
	width: calc((100% - (var(--shelf-cards) - 1) * 8px) / var(--shelf-cards));
	flex: 0 0 auto;
}
@media (min-width: 560px) { .lore-row__track > .lore-card { --shelf-cards: 3.4; } }
@media (min-width: 768px) { .lore-row__track > .lore-card { --shelf-cards: 4.5; } }
@media (min-width: 1024px) { .lore-row__track > .lore-card { --shelf-cards: 6.5; } }
@media (min-width: 1280px) { .lore-row__track > .lore-card { --shelf-cards: 8; } }
@media (min-width: 1440px) { .lore-row__track > .lore-card { --shelf-cards: 9; } }

/* Desktop row arrow-nav (round 2 task 5 — "You may also like" carousel) */
.lore-row--has-arrows { position: relative; }
.lore-row__arrow {
	display: none; position: absolute; top: 50%; transform: translateY(-50%); z-index: var(--z-arrow);
	width: 36px; height: 36px; border-radius: 50%; border: 1px solid var(--line); background: var(--paper);
	box-shadow: var(--shadow-sm); align-items: center; justify-content: center; cursor: pointer; color: var(--ink);
}
.lore-row__arrow .lore-icon { width: 18px; height: 18px; }
.lore-row__arrow--prev { left: var(--space-2); }
.lore-row__arrow--next { right: var(--space-2); }
/* Arrows only make sense with a mouse/pointer and room to place them —
   hidden on touch/narrow viewports where swipe already works (mobile web =
   the app: no hover-only affordances required here since it's opt-in extra
   chrome, not the only way to scroll the row). Unlike the hero (below),
   these stay unconditionally visible (not opacity-hover-gated) whenever
   they qualify — a safe superset of Wattpad's own hover-reveal pattern:
   always reachable by keyboard Tab and never depends on a mouse first
   hovering the shelf to become focusable at all. */
@media (min-width: 900px) and (hover: hover) and (pointer: fine) {
	.lore-row__arrow { display: flex; }
}

/* Community reading-list card (round 2 task 1 — home shelf) */
.lore-list-card {
	display: block; width: 200px; flex: none;
	border: 1px solid var(--line); border-radius: var(--radius-md); padding: var(--space-3);
	background: var(--paper);
}
.lore-list-card > a { display: block; text-decoration: none; color: var(--ink); }
.lore-list-card__covers { display: flex; gap: 2px; height: 72px; border-radius: var(--radius-sm); overflow: hidden; margin-bottom: var(--space-2); background: var(--paper-alt); }
.lore-list-card__cover { flex: 1; background-size: cover; background-position: center; background-color: var(--paper-alt); }
.lore-list-card__title { font-size: .875rem; font-weight: 700; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.lore-list-card__meta { font-size: .75rem; color: var(--ink-faint); margin-top: 2px; }
.lore-list-card__save { width: 100%; margin-top: var(--space-2); min-height: 44px; }
.lore-list-card__save[data-saved="1"] { color: var(--ember-text); border-color: var(--ember); }

/* Grid (browse, genre, search, profile works) */
/* R5 token parity (spec §B.3): Wattpad's genre-grid gap is a uniform 20px
   (CSS `gap:20px` shorthand), ours was 16px. */
.lore-grid {
	display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-5);
}
@media (min-width: 560px) { .lore-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 820px) { .lore-grid { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 1100px) { .lore-grid { grid-template-columns: repeat(5, 1fr); } }
/* R4 responsive audit (item 7): a CSS grid item's default min-width is
   `auto`, i.e. its own max-content size — a nowrap/ellipsis child (card
   title/author) can then force its grid column wider than the 1fr track,
   pushing .lore-grid (and the whole page, on /search/ with the filter
   sidebar) past the viewport into real horizontal scroll. min-width:0 lets
   the column shrink to the track width so overflow:hidden/ellipsis on the
   card's own children can do their job instead. */
.lore-grid .lore-card { width: 100%; min-width: 0; }

/* Skeletons */
.lore-skel { background: linear-gradient(90deg, var(--paper-alt) 25%, var(--line) 37%, var(--paper-alt) 63%); background-size: 400% 100%; animation: lore-shimmer 1.4s ease infinite; border-radius: var(--radius-sm); }
@keyframes lore-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
.lore-skel--cover { aspect-ratio: 2/3; border-radius: var(--radius-md); margin-bottom: var(--space-2); }
.lore-skel--line { height: 12px; margin-bottom: 6px; }
.lore-skel--short { width: 60%; }
.lore-card--skeleton { pointer-events: none; }

/* Empty states */
.lore-empty { text-align: center; padding: var(--space-10) var(--space-4); max-width: 360px; margin: 0 auto; color: var(--ink-soft); }
.lore-empty__icon { width: 56px; height: 56px; margin: 0 auto var(--space-3); color: var(--ink-faint); }
.lore-empty__icon .lore-icon { width: 100%; height: 100%; }
.lore-empty__title { font-weight: 700; font-size: 1.05rem; color: var(--ink); margin-bottom: 4px; }
.lore-empty__body { font-size: .875rem; margin-bottom: var(--space-4); }

/* Load more */
.lore-loadmore { display: flex; justify-content: center; padding: var(--space-6) var(--space-4); }

/* Tabs */
.lore-tabs { display: flex; gap: var(--space-2); border-bottom: 1px solid var(--line); overflow-x: auto; }
.lore-tabs__item {
	position: relative;
	background: none; border: 0; padding: var(--space-3) var(--space-3); font-weight: 600; font-size: .9rem;
	color: var(--ink-faint); border-bottom: 2px solid transparent; white-space: nowrap; cursor: pointer;
}
/* R4 responsive audit (item 10): a short one-word tab ("All") is only 40px
   wide — invisible-hit-area expansion; .lore-tabs' own 8px gap between tabs
   comfortably absorbs a 4px reach each side with no overlap between
   neighbours. Height is already >=48px (padding + line-height), untouched. */
.lore-tabs__item::after { content: ''; position: absolute; top: 0; bottom: 0; left: -4px; right: -4px; }
.lore-tabs__item.is-active, .lore-tabs__item[aria-selected="true"] { color: var(--ember-text); border-color: var(--ember); }

/* Filter bar */
.lore-filterbar { display: flex; flex-wrap: wrap; gap: var(--space-2); padding-top: var(--space-4); padding-bottom: var(--space-4); align-items: center; }
/* R4 responsive audit (item 10): was min-height:38px, under the 44px floor
   (measured 38px live on the genre-archive filter bar's sort dropdown). */
.lore-filterbar select, .lore-filterbar .lore-select { width: auto; min-height: 44px; padding: 6px 12px; font-size: .85rem; }
.lore-filterbar__toggle { display: inline-flex; align-items: center; gap: 6px; font-size: .85rem; background: var(--paper-alt); border: 1px solid var(--line); border-radius: var(--radius-pill); padding: 6px 12px; min-height: 44px; cursor: pointer; }
.lore-filterbar__toggle[aria-pressed="true"] { background: var(--ember); color: #fff; border-color: var(--ember); }

/* Modal */
.lore-modal-overlay {
	position: fixed; inset: 0; background: rgba(29,29,31,.5); z-index: var(--z-overlay);
	display: flex; align-items: center; justify-content: center; padding: var(--space-4);
}
.lore-modal-overlay[hidden] { display: none; }
.lore-modal {
	background: var(--white); border-radius: var(--radius-lg); max-width: 440px; width: 100%;
	max-height: 86vh; overflow-y: auto; padding: var(--space-6); box-shadow: var(--shadow-lg);
}
.lore-modal__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-4); }
.lore-modal__close { background: none; border: 0; cursor: pointer; min-width: 44px; min-height: 44px; padding: 4px; }

/* Bottom sheet (mobile) / side drawer (desktop) — shared for paragraph comments */
.lore-sheet-overlay {
	position: fixed; inset: 0; background: rgba(29,29,31,.4); z-index: var(--z-overlay);
}
.lore-sheet-overlay[hidden] { display: none; }
.lore-sheet[hidden] { display: none; }
.lore-sheet {
	position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-sheet);
	background: var(--white); border-radius: 18px 18px 0 0; box-shadow: var(--shadow-lg);
	max-height: 80vh; display: flex; flex-direction: column;
	animation: lore-sheet-up .2s ease;
}
@keyframes lore-sheet-up { from { transform: translateY(100%); } to { transform: translateY(0); } }
.lore-sheet__grabber { width: 40px; height: 4px; background: var(--line); border-radius: 2px; margin: 10px auto; flex: none; }
.lore-sheet__head { display: flex; align-items: center; justify-content: space-between; padding: 0 var(--space-4) var(--space-3); border-bottom: 1px solid var(--line); flex: none; }
.lore-sheet__body { overflow-y: auto; padding: var(--space-4); flex: 1; }
.lore-sheet__footer { padding: var(--space-3) var(--space-4); border-top: 1px solid var(--line); flex: none; }
/* Paragraph-comment panel (round 2 task 6): quoted paragraph text + the
   comment input sit ABOVE the thread, Wattpad-style, instead of the input
   pinned to the bottom — so footer--top gets a bottom divider instead of a
   top one (it's no longer at the visual bottom of the sheet). */
.lore-sheet__quote {
	margin: 0; padding: var(--space-3) var(--space-4); border-left: 3px solid var(--ember);
	background: var(--paper-alt); font-style: italic; font-size: .85rem; color: var(--ink-soft);
	flex: none; max-height: 5.6em; overflow: hidden;
}
.lore-sheet__quote:empty { display: none; }
.lore-sheet__footer--top { border-top: 0; border-bottom: 1px solid var(--line); }

@media (min-width: 900px) {
	.lore-sheet {
		left: auto; right: 0; top: 0; bottom: 0; width: 400px;
		border-radius: 0; animation: lore-drawer-in .2s ease;
	}
	@keyframes lore-drawer-in { from { transform: translateX(100%); } to { transform: translateX(0); } }
	.lore-sheet__grabber { display: none; }
}

/* Comment item */
.lore-comment { display: flex; gap: var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--line); }
.lore-comment:last-child { border-bottom: 0; }
.lore-comment__avatar { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; flex: none; }
.lore-comment__body { flex: 1; min-width: 0; }
.lore-comment__meta { display: flex; align-items: center; gap: 6px; font-size: .8rem; margin-bottom: 2px; }
.lore-comment__author { font-weight: 700; }
.lore-comment__time { color: var(--ink-faint); }
.lore-comment__text { font-size: .9rem; word-wrap: break-word; margin-bottom: 4px; }
.lore-comment__actions { display: flex; gap: var(--space-4); font-size: .78rem; color: var(--ink-faint); }
/* R5 tap-target fix: this was padding:4px 0 with no min-height — measured
   well under the 44px floor on touch. Invisible-hit-area expansion (same
   pattern as .lore-row__head a::after above) instead of growing the visible
   button, which would look oversized in a tight comment-actions row. */
.lore-comment__actions button { position: relative; background: none; border: 0; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; color: inherit; padding: 4px 0; }
.lore-comment__actions button::after { content: ''; position: absolute; top: -12px; bottom: -12px; left: -6px; right: -6px; }
.lore-comment__actions button.is-liked { color: var(--ember-text); }
.lore-comment__actions .lore-icon { width: 14px; height: 14px; }
.lore-comment__replies { margin-left: var(--space-6); margin-top: var(--space-2); }
.lore-comment-form { display: flex; gap: var(--space-2); align-items: flex-start; margin-top: var(--space-3); }
.lore-comment-form textarea { flex: 1; min-height: 40px; }

/* Interstitial (mature gate) */
.lore-interstitial { display: flex; align-items: center; justify-content: center; min-height: 60vh; padding: var(--space-4); }
.lore-interstitial__box { text-align: center; max-width: 380px; }
.lore-interstitial__box .lore-icon { width: 48px; height: 48px; color: var(--ember); margin: 0 auto var(--space-3); }
.lore-interstitial__actions { display: flex; gap: var(--space-3); justify-content: center; margin-top: var(--space-4); }

/* Progress bar (reading %, in library rows) */
.lore-progress { height: 6px; border-radius: 3px; background: var(--line); overflow: hidden; }
.lore-progress > span { display: block; height: 100%; background: var(--ember); border-radius: 3px; }

/* Follow / library icon buttons general */
.lore-btn--toggled { background: var(--ember-light); color: var(--ember-dark); border-color: transparent; }
.lore-btn--toggled.lore-btn--teal-toggled { background: rgba(27,153,139,.14); color: var(--teal-dark); }

/* Drag handle for reorderable parts list */
.lore-draghandle { cursor: grab; color: var(--ink-faint); touch-action: none; padding: 8px; }
.lore-draggable.is-dragging { opacity: .5; }

/* Generic action-sheet items (used by bottom-sheet.php for the story "more" menu) */
.lore-sheet-action { display: flex; align-items: center; gap: var(--space-3); width: 100%; padding: var(--space-3) var(--space-2); background: none; border: 0; text-align: left; font-size: .95rem; cursor: pointer; border-radius: var(--radius-md); }
.lore-sheet-action:hover { background: var(--paper-alt); }

/* Avatar sizes */
.lore-avatar-64 { width: 64px; height: 64px; border-radius: 50%; object-fit: cover; }
.lore-avatar-96 { width: 96px; height: 96px; border-radius: 50%; object-fit: cover; }
.lore-avatar-128 { width: 128px; height: 128px; border-radius: 50%; object-fit: cover; border: 4px solid var(--white); }

/* Language switcher (round 2 i18n) — header.php, reachable on every viewport. */
.lore-lang-btn { width: auto; min-width: 44px; padding: 0 var(--space-2); border-radius: var(--radius-full, 999px); }
.lore-lang-btn__code { font-size: .78rem; font-weight: 700; letter-spacing: .02em; }
.lore-dropdown--lang { min-width: 160px; }
.lore-dropdown--lang a { font-family: var(--lore-font-ui); font-size: 1rem; min-height: 44px; display: flex; align-items: center; }
.lore-dropdown--lang a.is-active { color: var(--ember-text); font-weight: 600; background: var(--paper-alt); }

/* Mobile web IS the app (no native app) — below 900px the language picker
   becomes a proper touch-friendly bottom sheet (same slide-up mechanics as
   .lore-sheet elsewhere) instead of a small anchored dropdown, so it never
   relies on hover and its tap targets are full-width/44px+. Scoped to this
   one modifier class (not the shared .lore-sheet breakpoint, which turns
   into a 400px side DRAWER on desktop — appropriate for the paragraph-
   comments panel, far too heavy for a 4-item language list here). */
@media (max-width: 899px) {
	.lore-dropdown--lang[id] {
		position: fixed; left: 0; right: 0; bottom: 0; top: auto; z-index: var(--z-sheet);
		width: auto; min-width: 0; max-width: none;
		border-radius: 18px 18px 0 0; box-shadow: var(--shadow-lg);
		padding: 10px var(--space-4) calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
		max-height: 60vh; overflow-y: auto;
		animation: lore-sheet-up .2s ease;
	}
	.lore-dropdown--lang[id]::before {
		content: ''; display: block; width: 40px; height: 4px; background: var(--line);
		border-radius: 2px; margin: 0 auto var(--space-3);
	}
	.lore-dropdown--lang a { font-size: 1.05rem; padding: var(--space-3) var(--space-2); }
}

/* Story-card language chip (round 2 i18n) — shown when a card's language
   differs from the current UI language, e.g. a profile's Works tab or a
   cross-language search result, so it's clear what you're about to open. */
.lore-card__lang-chip {
	position: absolute; top: var(--space-2); left: var(--space-2);
	background: rgba(29,29,31,.72); color: #fff; font-size: .75rem; font-weight: 600;
	padding: 2px 8px; border-radius: var(--radius-full, 999px); letter-spacing: .02em;
}
