Template:UI/upcoming events featured/styles.css

From Miniscope
Jump to: navigation, search
/* TemplateStyles for {{UI/upcoming_events_featured}}.
 *
 * Visual idiom mirrors {{UI/hero}}'s background variant — image fills
 * the card, dark gradient overlays the bottom for text legibility, and
 * the body (eyebrow + title + tagline + buttons) sits on top.
 *
 * Stacking inside the card (z-index back to front):
 *   0. .wiki-events-featured-card background — fallback gradient that
 *      shows through when no image is set (or image fails to load)
 *   1. .wiki-events-featured-image       — the [[File:...]] image,
 *      object-fit: cover, fills the card
 *   2. .wiki-events-featured-card::before — readability overlay
 *      (dark gradient fading bottom-to-top so body text stays legible
 *      regardless of underlying image content)
 *   3. .wiki-events-featured-body        — eyebrow + title + tagline +
 *      buttons, anchored to the bottom of the card
 *
 * 4:3 aspect locked via the padding-bottom hack on the card itself
 * (height: 0 + padding-bottom: 75%). 4:3 gives the body comfortable
 * room over the image without the card feeling square/poster-like,
 * and leaves enough vertical real estate next to it for ~5 rows in
 * the right-rail list at a typical desktop column width. The modern
 * `aspect-ratio` property would be cleaner but MW 1.44.5 /
 * css-sanitizer 5.5.0 rejects it as unrecognized (lands in 5.6+).
 *
 * Theme tokens via var(--labki-*, literal). MW 1.44.5 / css-sanitizer
 * 5.5.0 accepts var() in `background`, `color`, and `border` shorthand,
 * but rejects it in `border-radius`, `border-color` longhand,
 * `box-shadow`, `padding`, `margin`, `transition`, `transform`, and
 * most numeric/geometry properties — geometry stays literal for that
 * reason.
 *
 * The card stays clickable only via the title-wrapped wikilink and the
 * CTA buttons; the image itself isn't a link (avoids click conflicts
 * with the buttons floating above it).
 */

.wiki-events-featured {
	display: flex;
}

.wiki-events-featured-card {
	position: relative;
	width: 100%;
	height: 0;
	padding-bottom: 75%; /* 4:3 aspect */
	overflow: hidden;
	border: 1px solid var(--labki-border, #d8dde3);
	border-radius: 8px;
	/* Fallback gradient — visible when no image is set or image fails */
	background: linear-gradient(135deg, #1a2538 0%, #0e1c2e 50%, var(--labki-primary, #003B5C) 100%);
	z-index: 0;
	transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

/* Hover accent-border uses a literal color because the MW 1.44.5 /
 * css-sanitizer 5.5.0 sanitizer rejects var() for the `border-color`
 * property longhand (the `border` shorthand on the rule above accepts
 * var() fine). #2774AE matches the --labki-accent token literal
 * across the schema. */
.wiki-events-featured-card:hover {
	border-color: #2774AE;
	box-shadow: 0 6px 16px -4px rgba(0, 0, 0, 0.10);
	transform: translateY(-2px);
}

@media (prefers-reduced-motion: reduce) {
	.wiki-events-featured-card {
		transition: border-color 0.15s ease, box-shadow 0.15s ease;
	}
	.wiki-events-featured-card:hover {
		transform: none;
	}
}

/* Image fills the card behind the overlay and content. No explicit
 * width/height on the wrapper because top/right/bottom/left:0 plus the
 * card's padding-bottom-derived size give it the full card area. */
.wiki-events-featured-image {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	z-index: 1;
}

.wiki-events-featured-image img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Readability overlay — dark gradient fading from opaque at the bottom
 * (where the body sits) to transparent at the top. Matches the hero's
 * ::before pattern, just bottom-anchored rather than centered. Without
 * this, white body text against a bright image would be unreadable.
 *
 * Stops chosen to clear the body region (bottom ~40% of card) at high
 * opacity and fade out by 70% upward so the image's upper portion
 * shows through cleanly. */
.wiki-events-featured-card::before {
	content: "";
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	z-index: 2;
	background: linear-gradient(to top,
		rgba(0, 0, 0, 0.85) 0%,
		rgba(0, 0, 0, 0.55) 35%,
		rgba(0, 0, 0, 0.10) 70%,
		rgba(0, 0, 0, 0.00) 100%);
}

/* Body anchored to the bottom of the card. left/right: 0 + padding
 * gives the inset; bottom: 0 plus content height determines how far
 * up the body extends. Long content would clip against the card's
 * top edge via overflow: hidden — the tagline below uses single-line
 * truncation to keep this predictable. */
.wiki-events-featured-body {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	padding: 16px 22px 22px;
	z-index: 3;
	color: #ffffff;
}

/* Eyebrow — small uppercased kicker above the title. text-shadow
 * mirrors the hero's eyebrow treatment, gives a soft halo so the
 * label stays readable even where the underlying image is busy. */
.wiki-events-featured-eyebrow {
	font-size: 0.78em;
	font-weight: 600;
	letter-spacing: 0.10em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.85);
	text-shadow: 0 1px 6px rgba(0, 0, 0, 0.6);
	margin: 0 0 6px;
}

.wiki-events-featured-title {
	font-size: 1.5em;
	font-weight: 700;
	line-height: 1.2;
	margin: 0 0 8px;
}

/* labki-tweeki.css recolors links inside .mw-parser-output globally;
 * the card title sits on the dark overlay and needs white link text.
 * !important matches the pattern used in {{UI/hero}} for the same
 * reason. */
.wiki-events-featured-title a,
.wiki-events-featured-title a:visited {
	color: #ffffff !important;
	text-decoration: none;
}

.wiki-events-featured-title a:hover {
	color: rgba(255, 255, 255, 0.85) !important;
	text-decoration: underline;
}

.wiki-events-featured-tagline {
	font-size: 0.95em;
	color: rgba(255, 255, 255, 0.92);
	line-height: 1.4;
	margin: 0 0 12px;
	/* Multi-line clamp at ~3 lines via max-height. The modern
	 * -webkit-line-clamp idiom would give a clean ellipsis on the
	 * last line, but the MW 1.44.5 / css-sanitizer 5.5.0 sanitizer
	 * rejects `display: -webkit-box` as an unsupported value
	 * (templatestyles-error-bad-value-for-property), which breaks
	 * the whole line-clamp construct. max-height is the universal
	 * fallback: line-height (1.4em) × 3 lines = 4.2em fits exactly
	 * three lines, and a fourth line starts past the max-height and
	 * gets clipped by overflow: hidden at the line boundary.
	 *
	 * No `…` ellipsis on the cut line — the text just ends mid-word
	 * if the description runs long. Acceptable: the cut itself
	 * signals "there's more" and a Learn more button sits right
	 * below.
	 *
	 * 3 lines balances readability with body-vs-image proportions:
	 * at a 600px column the body region is ~190px (~42% of card
	 * height), leaving the image clearly dominant. */
	max-height: 4.2em;
	overflow: hidden;
}

.wiki-events-featured-actions {
	display: flex;
	gap: 10px;
	flex-wrap: wrap;
}

/* Empty state — dashed-border placeholder for when the auto-pick
 * query returns no upcoming workshops. Doesn't share the card's
 * overlay structure (there's no image to overlay). Same idiom as
 * .wiki-activity-empty / .wiki-forum-empty so the "no content yet"
 * affordances stay visually consistent across the schema. */
.wiki-events-featured-empty {
	padding: 20px;
	color: var(--labki-text-muted, #5a6a7a);
	font-style: italic;
	text-align: center;
	border: 1px dashed var(--labki-border, #d8dde3);
	border-radius: 4px;
	background: var(--labki-bg-subtle, #f8f9fa);
	flex: 1;
}

.wiki-events-featured-empty code {
	font-style: normal;
	background: var(--labki-bg, #ffffff);
	padding: 1px 4px;
	border-radius: 3px;
	border: 1px solid var(--labki-border, #d8dde3);
}