Template:UI/upcoming events featured/styles.css
From Miniscope
/* 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);
}