Template:Category/Workshop/styles.css
From Miniscope
/* TemplateStyles for the Workshop page idiom — shared between
* {{Category/Workshop}} (public landing) and
* {{Category/Workshop internal hub}} (participant-only hub).
*
* Covers:
* * .workshop-banner-wrap — image with overlay text (title + dates +
* location across the bottom)
* * .workshop-meta — fallback inline meta row (when no banner image
* is set)
* * .workshop-status-block — full-block tinted by state, with a big
* heading; replaces the small-chip treatment from the first cut
* * .workshop-description, .workshop-details-list, .workshop-flyer
* — public-page specific
* * .workshop-hub-* — internal-hub specific
*
* 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, padding,
* margin, etc. Status-state colors stay literal because they're
* discrete state signals, not theme tokens.
*
* No aspect-ratio, no -webkit-* properties (both rejected by the
* labki-platform sanitizer). Image proportions come from the natural
* size of Has banner (3:1) or Has card image (4:3); the latter is
* capped via max-height to avoid dominating the page header.
*/
/* ================================================================
Banner with overlay text
z-index stack:
1. .workshop-banner-img — the [[File:...]] image
2. .workshop-banner-wrap::after — dark gradient for legibility
3. .workshop-banner-content — title + meta on top
================================================================ */
.workshop-banner-wrap {
position: relative;
margin: 0 0 24px;
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--labki-border, #d8dde3);
}
.workshop-banner-img {
position: relative;
z-index: 1;
line-height: 0;
}
.workshop-banner-img img {
display: block;
width: 100%;
height: auto;
}
/* When falling back to Has card image (4:3) instead of Has banner
* (3:1), the image is taller. Cap max-height so the banner doesn't
* dominate the page header. object-fit: cover crops to the visible
* region centered. */
.workshop-banner-img--fallback img {
max-height: 360px;
object-fit: cover;
}
/* Readability overlay — dark gradient fading from opaque at the
* bottom (where the title sits) to transparent at the top. Same idiom
* as {{UI/upcoming_events_featured}}'s overlay; tuned slightly more
* subtle here since the banner image is shorter (3:1 vs 4:3) and the
* text band is narrower. */
.workshop-banner-wrap::after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 2;
background: linear-gradient(to top,
rgba(0, 0, 0, 0.75) 0%,
rgba(0, 0, 0, 0.45) 35%,
rgba(0, 0, 0, 0.05) 75%,
rgba(0, 0, 0, 0.00) 100%);
}
.workshop-banner-content {
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: 20px 28px 24px;
z-index: 3;
color: #ffffff;
}
.workshop-banner-title {
font-size: 2em;
font-weight: 700;
line-height: 1.15;
margin: 0 0 6px;
text-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}
.workshop-banner-meta {
display: flex;
flex-wrap: wrap;
gap: 0 12px;
font-size: 1em;
color: rgba(255, 255, 255, 0.92);
line-height: 1.4;
}
.workshop-banner-meta > span:not(:last-child)::after {
content: "·";
margin-left: 12px;
color: rgba(255, 255, 255, 0.55);
}
/* ================================================================
Fallback meta line — used when no banner image is set
================================================================ */
.workshop-meta {
display: flex;
flex-wrap: wrap;
gap: 0 12px;
font-size: 1em;
color: var(--labki-text-muted, #5a6a7a);
margin: 0 0 16px;
line-height: 1.5;
}
.workshop-meta > span:not(:last-child)::after {
content: "·";
margin-left: 12px;
color: var(--labki-text-faint, #a0a8b0);
}
.workshop-meta-date {
font-weight: 600;
color: var(--labki-text, #1c1c1c);
}
/* ================================================================
Status block — full-block tinted, big heading + detail + CTA
================================================================ */
.workshop-status-block {
margin: 0 0 24px;
padding: 20px 24px;
border: 1px solid var(--labki-border, #d8dde3);
border-radius: 8px;
background: var(--labki-bg-subtle, #f8f9fa);
}
/* Per-state full-block tinting. Literal colors (no var) because the
* sanitizer rejects var() in `border-color` longhand. These are
* discrete state signals, not theme tokens, so literals are
* appropriate. */
.workshop-status-block--open {
background: #e6f5eb;
border-color: #27AE60;
}
.workshop-status-block--soon {
background: #e8f0f7;
border-color: #2774AE;
}
.workshop-status-block--closed {
background: #fcf3cf;
border-color: #B7950B;
}
.workshop-status-block--now {
background: #d4f0e0;
border-color: #27AE60;
}
.workshop-status-block--past {
background: #ececec;
border-color: #c0c0c0;
}
.workshop-status-block--cancelled {
background: #fbeaea;
border-color: #c0392b;
}
.workshop-status-block--postponed {
background: #fcf3cf;
border-color: #B7950B;
}
/* Big state heading. Not an <h*> element to avoid MW's auto-anchor
* TOC clutter — styled like a heading via CSS instead. */
.workshop-status-heading {
font-size: 1.6em;
font-weight: 700;
line-height: 1.2;
letter-spacing: -0.01em;
margin: 0;
}
.workshop-status-heading--open { color: #196f3d; }
.workshop-status-heading--soon { color: #1c4e7a; }
.workshop-status-heading--closed { color: #7d6608; }
.workshop-status-heading--now { color: #196f3d; }
.workshop-status-heading--past { color: #555555; }
.workshop-status-heading--cancelled { color: #922b21; }
.workshop-status-heading--postponed { color: #7d6608; }
.workshop-status-detail {
margin: 8px 0 0;
font-size: 0.95em;
color: var(--labki-text-muted, #5a6a7a);
}
.workshop-status-cta {
margin-top: 14px;
display: flex;
flex-wrap: wrap;
gap: 10px;
}
/* ================================================================
Description — italic intro paragraph
================================================================ */
.workshop-description {
font-size: 1.08em;
line-height: 1.6;
color: var(--labki-text, #1c1c1c);
font-style: italic;
margin: 0 0 20px;
}
/* ================================================================
Details list — Type / Dates / Location / Timezone / Status
================================================================ */
.workshop-details {
margin: 24px 0;
}
.workshop-details-list {
list-style: none;
padding: 0;
margin: 8px 0 0;
}
.workshop-details-list li {
padding: 8px 0;
border-bottom: 1px solid var(--labki-border, #d8dde3);
font-size: 0.95em;
line-height: 1.5;
}
.workshop-details-list li:last-child {
border-bottom: none;
}
.workshop-details-list strong {
display: inline-block;
min-width: 110px;
color: var(--labki-text-muted, #5a6a7a);
font-weight: 600;
}
/* ================================================================
Flyer — portrait promo image at the bottom of the public page,
clicks open the full-size file via {{filepath:}} (set in the
template's link= param, not here)
================================================================ */
.workshop-flyer {
margin: 24px 0;
text-align: center;
}
.workshop-flyer img {
max-width: 100%;
height: auto;
border: 1px solid var(--labki-border, #d8dde3);
border-radius: 4px;
}
/* ================================================================
Internal hub specifics
================================================================ */
.workshop-hub-context {
margin: 16px 0;
font-size: 0.95em;
color: var(--labki-text-muted, #5a6a7a);
font-style: italic;
}
.workshop-hub-external {
margin: 24px 0 0;
}
.workshop-hub-external h2 {
margin-bottom: 8px;
}
.workshop-hub-external-list {
list-style: none;
padding: 0;
margin: 0;
}
.workshop-hub-external-list li {
padding: 6px 0;
font-size: 0.95em;
}
.workshop-hub-external-list strong {
display: inline-block;
min-width: 160px;
color: var(--labki-text-muted, #5a6a7a);
font-weight: 600;
}