Files
2026-10-01 19:06:54 +02:00

312 lines
9.3 KiB
CSS

/* --- Hero ---------------------------------------------------------------------
A full-width band in the brand gradient with a faint dot pattern on top. The
page content sits in a centred column (.content in MainLayout), so the band
breaks out of it: 100vw wide, pulled left by the column's offset. body clips the
few pixels of scrollbar this adds (see app.css). The negative top margin cancels
the column's top padding, so the band meets the header without a strip of page
background in between.
The pattern is an inline SVG in a data: URL -- no request, nothing from another
host. White dots at 12% opacity: visible as texture, too faint to cost the
white text any contrast. */
.hero {
width: 100vw;
margin: calc(-1 * var(--space-4)) 0 var(--space-5) calc(50% - 50vw);
background:
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Ccircle cx='3' cy='3' r='1.5' fill='%23fff' fill-opacity='.12'/%3E%3C/svg%3E"),
var(--gradient-brand);
color: var(--color-on-header);
}
/* The inside follows the page frame again, so the hero text lines up with the
tiles and lists below. Stacked on a phone; from tablet width the next-event card
moves beside the text. */
.hero-inner {
box-sizing: border-box;
max-width: var(--content-width);
margin: 0 auto;
padding: var(--space-6) 1.25rem;
display: grid;
gap: var(--space-5);
align-items: center;
}
@media (min-width: 48rem) {
.hero-inner {
grid-template-columns: minmax(0, 1fr) minmax(16rem, 22rem);
}
}
/* On the gradient everything is white: the global heading colour is a blue that
would vanish here. */
/* balance evens out the lines, so a short last word ("IGMH") never wraps alone. */
.hero h1 {
color: var(--color-on-header);
text-wrap: balance;
}
/* The intro is editor Markdown, rendered without scope attributes, so it is reached
through ::deep. Slightly larger than body text, as a lead. Links stay white and
underlined: the blue link colour would be unreadable on the gradient. */
.hero-intro ::deep p {
font-size: 1.15rem;
}
.hero-intro ::deep a,
.hero-intro ::deep a:hover {
color: var(--color-on-header);
}
.hero-actions {
display: flex;
flex-wrap: wrap;
gap: var(--space-3);
margin: var(--space-4) 0 0;
}
/* The hero's buttons, adapted to the dark gradient: the primary turns light (a
filled blue would melt into the blue end), the secondary becomes a white outline
with the same translucent wash as the header menu on hover. The focus ring turns
white for the same reason. */
.hero .btn-primary {
background: var(--color-button-light);
border-color: var(--color-button-light);
color: var(--color-on-button-light);
}
.hero .btn-primary:hover {
background: var(--color-button-light-hover);
border-color: var(--color-button-light-hover);
color: var(--color-on-button-light);
}
.hero .btn-secondary {
border-color: var(--color-on-header);
color: var(--color-on-header);
}
.hero .btn-secondary:hover {
background: var(--color-nav-hover);
color: var(--color-on-header);
}
.hero .btn:focus-visible {
outline-color: var(--color-focus-inverse);
}
/* On a phone the buttons used to wrap onto a row each: two wide blocks stacked,
far too heavy for the top of the page. Instead they share one row in equal
columns -- the same buttons as on the desktop, just side by side and a little
tighter. Short labels ("Termine", "Kontakt") fit on one line; a longer one
wraps inside its button (centred) rather than pushing the other off the row. */
@media (max-width: 40rem) {
.hero-actions {
display: grid;
grid-auto-flow: column;
grid-auto-columns: 1fr;
gap: var(--space-2);
}
.hero .btn {
justify-content: center;
padding: var(--space-2) var(--space-3);
text-align: center;
}
}
/* --- Next event ---------------------------------------------------------------
A card on the gradient: the regular card surface, so its text uses the normal
tokens and adapts to dark mode by itself. The whole card is one link to the
events page. */
.next-event {
display: block;
padding: var(--space-4);
border-radius: var(--radius);
background: var(--color-bg);
box-shadow: var(--shadow-lg);
color: var(--color-text);
text-decoration: none;
transition: box-shadow var(--transition);
}
.next-event:hover {
color: var(--color-text);
box-shadow: var(--shadow-hover), var(--shadow-lg);
}
/* The ring sits outside the card, on the gradient, so it is white like the
hero's button rings. */
.next-event:focus-visible {
outline-color: var(--color-focus-inverse);
outline-offset: 3px;
}
.next-event-label {
display: block;
margin-bottom: var(--space-3);
color: var(--color-text-soft);
font-size: 0.85rem;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.next-event-row {
display: flex;
gap: var(--space-3);
align-items: flex-start;
}
.next-event-details {
min-width: 0; /* lets a long title wrap instead of widening the card */
}
.next-event-title {
display: block;
color: var(--color-brand);
font-size: 1.15rem;
font-weight: 700;
line-height: 1.3;
}
/* Time and place, one line each with their icon, green as on the event cards. The
icon belongs to Icon's own scope, so it is reached through ::deep. */
.next-event-meta {
display: flex;
align-items: center;
gap: var(--space-1);
margin-top: var(--space-1);
color: var(--color-text-soft);
font-size: 0.9rem;
}
.next-event-meta ::deep .icon {
color: var(--color-accent-dark);
}
/* --- Tiles --------------------------------------------------------------------
One card per header page. Fixed columns instead of auto-fill: two on a phone,
three from tablet width, so the six pages always fill whole rows and never leave
a half row behind. On a phone the tiles are compact (icon and title only), the
teaser would make six tiles a long scroll. Hover = stronger shadow and a blue
edge, nothing moves. */
.home-tiles {
margin-block: var(--space-5);
}
.home-tiles ul {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--space-3);
margin: 0;
padding: 0;
list-style: none;
}
/* On a phone the icon sits above the title: beside it, a half-width column leaves
too little room and titles get cut. */
.tile-link {
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-2);
height: 100%;
text-align: center;
padding: var(--space-3);
border: 1px solid transparent;
border-radius: var(--radius);
background: var(--color-bg);
box-shadow: var(--shadow);
color: var(--color-text);
text-decoration: none;
transition: box-shadow var(--transition), border-color var(--transition);
}
.tile-link:hover {
border-color: var(--color-brand);
box-shadow: var(--shadow-hover);
color: var(--color-text);
}
/* The icon in a soft round tint. */
.tile-icon {
flex-shrink: 0;
display: grid;
place-items: center;
width: 3rem;
height: 3rem;
border-radius: 50%;
background: var(--color-brand-tint);
color: var(--color-brand);
}
/* Long German compounds must wrap rather than overflow the narrow tile. */
.tile-title {
max-width: 100%;
color: var(--color-brand);
font-size: 1.1rem;
font-weight: 700;
overflow-wrap: anywhere;
}
/* Hidden on a phone; the title alone says where the tile leads. */
.tile-text {
display: none;
color: var(--color-text-soft);
font-size: 0.9rem;
line-height: 1.45;
}
@media (min-width: 48rem) {
.home-tiles ul {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
/* Icon left, title and teaser right. Both start at the top, so the icon stays
beside the title even when the teaser runs over several lines. The icon spans
both rows here, where the teaser is visible. */
.tile-link {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
column-gap: var(--space-3);
row-gap: 0;
align-content: start;
padding: var(--space-3) var(--space-4);
text-align: start;
}
.tile-icon {
grid-row: span 2;
align-self: start;
}
/* The teaser is a whole sentence; the tile cuts it visually after three lines,
so the tiles of a row keep a similar height whatever the editor wrote. The
-webkit- box is the form every current browser supports for line-clamp. */
.tile-text {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
overflow: hidden;
}
}
/* --- Embeds -------------------------------------------------------------------
The blocks the home page opts into (posts, events) sit side by side from desktop
width, so the start page shows both without a long scroll. One column below.
In the grid the blocks' own top margin no longer collapses with the margin of
the tiles above, so it is dropped there; otherwise the gap would be doubled. */
@media (min-width: 64rem) {
.home-embeds {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--space-5);
align-items: start;
}
.home-embeds ::deep .embed {
margin-top: 0;
}
}