/* Design tokens: one place for colours, spacing, radius, shadow and type. Every component pulls from these variables (var(--...)), so the whole site shares one look and a change here ripples everywhere. Palette follows the school's own colours (IGMH): its blue for the header, links and headings, its green as the accent. No external anything -- just CSS custom properties. */ :root { /* Brand blue and two derived shades (darker for hover, lighter for tints). This is the IGMH blue (#328fc6) darkened so it stays legible as link/heading text on white; the header keeps the brighter original via --color-header below. */ --color-brand: #2b6f9c; --color-brand-dark: #1f5477; --color-brand-tint: #eaf3f9; /* The header bar's background: the IGMH blue at full strength. Its own token (not --color-brand) both because it only ever carries white text (so it needs no darkening) and because it must stay a deep blue in dark mode, where --color-brand is lightened for text/links. */ --color-header: #328fc6; /* Text and menu states on the header. White text, and two translucent white washes for the menu pills: they lighten whatever part of the gradient sits behind a link, so one value works from the blue end to the green end. The active pill is the stronger one, so "where am I" outranks "where is the mouse". */ --color-on-header: #fff; --color-nav-hover: rgba(255, 255, 255, 0.12); --color-nav-active: rgba(255, 255, 255, 0.2); /* Footer: a dark brand blue, so the page visibly ends there. Light text in two steps (headings and the name brighter, links softer); both stay >= 7:1 on the band. The border token is a faint white line for the copyright rule. */ --color-footer: #1a3d57; --color-on-footer: #f1f5f9; --color-on-footer-soft: #c5d3df; --color-footer-border: rgba(255, 255, 255, 0.15); /* Accent for highlights (active nav, event dates, call-outs): the IGMH green. The -dark shade is darkened enough to keep small text and the FAQ marker legible on a white card. */ --color-accent: #6db863; --color-accent-dark: #4f9247; /* A whisper of the green for calm background areas (info boxes, highlighted rows). Light enough that body text keeps its full contrast on top. */ --color-accent-tint: #eef7ec; /* Warm yellow for the rare thing that must catch the eye (a "new" marker, a deadline). Background only, never text -- yellow text is unreadable on white. Used sparingly: if everything is highlighted, nothing is. */ --color-highlight: #fdf0c2; /* Brand gradient for large surfaces (hero, banner): the header blue flowing into the IGMH green. The green end is a deep shade (#3a7a3e, 5.2:1 with white), not --color-accent, so white text stays readable across the whole sweep. */ --gradient-brand: linear-gradient(135deg, var(--color-header) 0%, #3a7a3e 100%); /* The month band of the calendar sheet (CalendarSheet): the deep green of the gradient's end, because it carries small white text -- on --color-accent that would fall below AA. Same 5.2:1 as in the gradient. */ --color-calendar-band: #3a7a3e; /* Buttons in editor content (a lone mail link, links in an "aufruf" box): a filled blue with white text. Own tokens, not --color-brand, because in dark mode --color-brand turns light for link text, and white on that light blue would fail WCAG AA. Both shades carry white at >= 5.5:1. */ --color-button: #2b6f9c; --color-button-hover: #1f5477; --color-on-button: #fff; /* The light button for dark surfaces (the brand gradient of the home hero), where a filled blue button would melt into the blue end. Dark blue text on white, 8:1; the hover is a faint blue tint, so the button still reads as one. */ --color-button-light: #fff; --color-button-light-hover: #eaf3f9; --color-on-button-light: #1f5477; /* Initials avatars on the person cards (::: team, see TeamMember.cs): only the two brand colours, blue and green tint, so the board stays in the IGMH palette. The colour is picked from the name, so it means nothing -- it only helps tell the cards apart. The tints follow their tokens into dark mode; the green text needs its own shade, because --color-accent-dark is too light for small text on the tint (3.6:1). Blue 7.2:1, green 5.9:1. */ --color-avatar-1: var(--color-brand-tint); --color-on-avatar-1: var(--color-brand-dark); --color-avatar-2: var(--color-accent-tint); --color-on-avatar-2: #2f6b33; /* Keyboard focus ring (:focus-visible). Its own token so it can stay strong on the light page (dark blue, 8:1 on white) and flip to a light blue on the dark one; on the gradient the hero switches it to white. */ --color-focus: #1f5477; /* Headings. Its own token (not --color-brand) so headings and links can differ: in dark mode headings become a soft white while links keep the brand blue. */ --color-heading: #2b6f9c; /* Text and surfaces. */ --color-text: #222; --color-text-soft: #555; --color-bg: #fff; /* cards / content surface */ --color-page: #f4f6f4; /* near-neutral page background with a faint cool tint, so white cards lift off it without the old warm beige clashing with the cool blue */ --color-surface: #fafafa; --color-border: #e0e0e0; /* Spacing scale -- use these instead of ad-hoc rem values so gaps stay even. */ --space-1: 0.25rem; --space-2: 0.5rem; --space-3: 1rem; --space-4: 1.5rem; --space-5: 2rem; --space-6: 3rem; /* Rounded corners and a soft shadow for cards, matching the friendly tone. */ --radius: 12px; --radius-sm: 6px; --radius-lg: 20px; /* large surfaces (hero, banner) look stiff with the card radius at their size */ --shadow: 0 1px 3px rgba(31, 58, 95, 0.08), 0 4px 12px rgba(31, 58, 95, 0.06); --shadow-hover: 0 2px 6px rgba(31, 58, 95, 0.12), 0 8px 20px rgba(31, 58, 95, 0.1); --shadow-lg: 0 4px 12px rgba(31, 58, 95, 0.1), 0 16px 40px rgba(31, 58, 95, 0.12); /* One transition speed for hovers/focus across the site. */ --transition: 0.15s ease; /* Width of the page frame (header, content, footer). Wide enough for card grids side by side; running text does not follow it -- paragraphs keep their own reading width (see p below), so lines never get uncomfortably long. */ --content-width: 72rem; /* Type. The site font is self-hosted (see @font-face below); the system stack stays behind it, so text shows at once and only swaps when Nunito arrives. */ --font-family: "Nunito", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; /* Type scale. h1 and h2 grow fluidly with the viewport (clamp: minimum, preferred in vw, maximum) instead of jumping at a breakpoint, so a long German compound word in a heading still fits a phone screen. Smaller sizes stay fixed: the difference would not be visible. Body text sits a touch above the 1rem default because Nunito's rounded letters read small. */ --font-size-h1: clamp(2rem, 1.6rem + 1.6vw, 2.75rem); --font-size-h2: clamp(1.5rem, 1.35rem + 0.6vw, 1.75rem); --font-size-h3: 1.2rem; --font-size-body: 1.0625rem; /* Headings: extra-bold for a friendly, confident lead, pulled slightly tighter because heavy letters at large sizes otherwise look spaced out. */ --font-weight-heading: 800; --letter-spacing-heading: -0.015em; } /* Dark mode: follows the visitor's OS setting automatically (prefers-color-scheme). No toggle and no JavaScript -- the browser applies this when the operating system is set to dark. Only the colour tokens change; layout, spacing, radius and type stay put, so the whole site adapts from this one block. Choices: a deep blue-grey rather than pure black; cards a touch lighter than the page so they still lift off it; the accent nudged brighter so it doesn't glare; shadows darkened since soft light shadows are invisible on a dark background. The header keeps its deep blue. */ @media (prefers-color-scheme: dark) { :root { --color-brand: #7cc0ec; /* the IGMH blue lightened: headings/links need to stay bright enough to read on the dark page background, not just on the card */ --color-brand-dark: #a3d5f4; /* hover goes lighter, not darker, on dark */ --color-brand-tint: #223038; --color-header: #266f9c; /* the IGMH blue eased down, to sit calmly on dark */ --color-footer: #10202e; /* a deep night blue: darker than the page, so the band still reads as the page's end */ --color-on-footer: #c9ced6; /* the heading tone, 10:1 on the band */ --color-on-footer-soft: #a2a8b2; /* the body text tone, 6.9:1 on the band */ --color-footer-border: rgba(255, 255, 255, 0.1); --color-accent: #86c97d; /* the IGMH green nudged brighter for dark */ --color-accent-dark: #86c97d; /* no darkening needed on a dark surface */ --color-accent-tint: #24332a; /* a dark green-grey: tinted, but the soft body text still reads at 5.5:1 */ --color-highlight: #3a3220; /* the warm yellow as a deep amber -- a bright yellow would glare on the dark page */ --gradient-brand: linear-gradient(135deg, var(--color-header) 0%, #2f6b33 100%); --color-calendar-band: #2f6b33; /* the gradient's dark-mode green, 6.4:1 with white */ --color-button: #266f9c; /* the header blue: deep enough for white text, calm on the dark page */ --color-button-hover: #1f5477; --color-button-light: #e8eef3; /* white eased down, so it does not glare on the darker gradient */ --color-button-light-hover: #d3dee6; --color-on-button-light: #1a3d57; /* 9:1 on the eased white */ /* Avatar green text: the brightened accent, 6.7:1 on the dark green tint (the blue pair follows its tokens, 8.6:1). */ --color-on-avatar-2: var(--color-accent); --color-focus: #a3d5f4; /* light blue: a dark ring would vanish here */ --color-heading: #c9ced6; /* soft white, kept a step brighter than the body text so headings still lead the page */ --color-text: #a2a8b2; /* eased right down to the soft tone -- full near-white reads as glare on the dark page */ --color-text-soft: #a2a8b2; --color-bg: #222834; /* cards / content surface */ --color-page: #171b22; /* page background, darker than the cards */ --color-surface: #1c212a; --color-border: #333b47; --shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 4px 12px rgba(0, 0, 0, 0.3); --shadow-hover: 0 2px 6px rgba(0, 0, 0, 0.5), 0 8px 20px rgba(0, 0, 0, 0.4); --shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.5), 0 16px 40px rgba(0, 0, 0, 0.45); } } /* Nunito, served from our own wwwroot -- never from Google Fonts, which would hand every visitor's IP to Google (see docs/recht.md). One variable file covers every weight from 400 to 800, so body, bold and headings cost a single ~36 KB request instead of three static files. Subset to Latin incl. German and the common European names (ä ö ü ß é ç ğ ş ł ...), € and German quotes; anything outside falls back to the system font. No italic file: Markdown emphasis is rare, so the browser slanting the upright face is worth the saved request. font-display: swap shows the system font immediately and swaps once the file is there -- text never waits. License: SIL OFL 1.1, see fonts/OFL.txt. */ @font-face { font-family: "Nunito"; src: url("fonts/nunito-latin-wght.woff2") format("woff2"); font-weight: 400 800; font-style: normal; font-display: swap; } /* Base styles. */ html { font-family: var(--font-family); line-height: 1.65; color: var(--color-text); /* Tell the browser we support both schemes, so form controls, scrollbars and the native
marker follow the OS setting instead of staying light. */ color-scheme: light dark; /* Smooth-scroll for in-page anchors, with room so headings clear the sticky header instead of hiding under it. */ scroll-padding-top: 5rem; } body { margin: 0; /* A soft tinted page background so white cards/content lift off it. */ background: var(--color-page); color: var(--color-text); font-size: var(--font-size-body); /* Full-width bands inside the content column (the home hero) reach the window edges with 100vw, which includes the vertical scrollbar and would add a few pixels of sideways scroll. clip, not hidden: hidden would make body a scroll container and stop the sticky header from sticking. */ overflow-x: clip; } a { color: var(--color-brand); text-underline-offset: 2px; transition: color var(--transition); } a:hover { color: var(--color-brand-dark); } /* Headings: clear hierarchy and a touch more air above them than below, so sections read as groups. */ h1, h2, h3, h4 { line-height: 1.25; color: var(--color-heading); font-weight: var(--font-weight-heading); letter-spacing: var(--letter-spacing-heading); margin: var(--space-5) 0 var(--space-3); } h1 { font-size: var(--font-size-h1); line-height: 1.15; /* big type needs less leading, or wrapped lines drift apart */ margin-top: 0; /* the first heading on a page needs no gap above */ } h2 { font-size: var(--font-size-h2); } h3 { font-size: var(--font-size-h3); } /* h4 gets its own size so it stays a step below h3 instead of falling back to the browser default, which can render as large as (or larger than) a small h3. Body size: below that it would read smaller than the text it heads; the extra-bold weight alone sets it apart. */ h4 { font-size: var(--font-size-body); } /* Comfortable paragraph rhythm and a capped line length for readability. */ p { margin: 0 0 var(--space-3); max-width: 42rem; } h1:focus { outline: none; } /* Text for screen readers only: off screen visually, still read aloud. For places where the visible form is decoration (the calendar sheet) and the spoken form must carry the full information. Not display:none -- that hides it from screen readers too. */ .visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; } /* Icons (Shared/Icon.razor) sit inline next to text: nudged down to line up with the letters instead of the baseline, and never squeezed when they share a flex row with a long label. */ .icon { flex-shrink: 0; vertical-align: -0.15em; } /* Buttons for links that are an action (the hero's "Kommende Termine", "Kontakt aufnehmen"). Global, because the look must be the same wherever a component puts one. Primary = filled, secondary = outlined; both carry the same 2px border, so a primary and a secondary side by side are exactly the same height. Hover changes colour and shadow only -- nothing moves (hover movement was removed on purpose). */ .btn { display: inline-flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-4); border: 2px solid transparent; border-radius: var(--radius-sm); font-weight: 700; line-height: 1.4; text-decoration: none; transition: background-color var(--transition), box-shadow var(--transition), color var(--transition), border-color var(--transition); } .btn:focus-visible { outline: 3px solid var(--color-focus); outline-offset: 2px; } .btn-primary { background: var(--color-button); border-color: var(--color-button); color: var(--color-on-button); } .btn-primary:hover { background: var(--color-button-hover); border-color: var(--color-button-hover); color: var(--color-on-button); box-shadow: var(--shadow-hover); } .btn-secondary { background: transparent; border-color: var(--color-button); color: var(--color-brand); } .btn-secondary:hover { background: var(--color-brand-tint); color: var(--color-brand); } /* Header navigation links. These live here (global), not in MainLayout.razor.css: NavLink renders plain elements without a scoped-CSS attribute, so a scoped ".main-nav a" rule would not match them -- the links would fall back to the global link colour (dark blue) and become unreadable on the blue header bar. Every link is a pill with the same padding whether active or not, so switching pages never shifts the row. Full white, not a softened white: the blue end of the gradient already leaves little contrast headroom. */ .main-nav a { position: relative; padding: var(--space-1) var(--space-3); border-radius: 999px; color: var(--color-on-header); text-decoration: none; transition: background-color var(--transition); } .main-nav a:hover { color: var(--color-on-header); background: var(--color-nav-hover); } /* NavLink adds .active to the current route's link: a stronger pill plus a short green stroke under the text mark where the visitor is. The stroke is drawn by ::after, not a border, so it follows the text width inside the rounded pill. */ .main-nav a.active { background: var(--color-nav-active); } .main-nav a.active::after { content: ""; position: absolute; left: var(--space-3); right: var(--space-3); bottom: 0.2rem; height: 2px; border-radius: 1px; background: var(--color-accent); } /* Mobile: the stacked links in the open menu become full-width rows with a rounded highlight instead of pills, and the green stroke shrinks to a short mark at the start, so a long row does not get a long line. Same global placement, same NavLink reason as above. */ @media (max-width: 40rem) { .main-nav a { padding: 0.6rem var(--space-3); border-radius: var(--radius-sm); } .main-nav a.active::after { right: auto; width: 1.5rem; } } /* --- Lists of post and event cards ------------------------------------------------ Posts and events appear both on their own page (PostList/EventList) AND embedded on the home page (the *Embed components). The cards themselves are components (PostCard, EventCard) with their own scoped styles; only the list around them is shared here: no bullets, one column with even gaps. A page may widen the grid (the posts page goes to two columns). */ .post-list, .event-list { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-3); } /* FAQ topics: each is a collapsible card. Its summary is the topic heading; open it to reveal the optional intro and the questions (themselves collapsible .faq-item cards). The topic marker is a rotating triangle, distinct from the +/- on the questions nested inside, so the two accordion levels read apart. */ .faq-topic { background: var(--color-bg); border-radius: var(--radius); box-shadow: var(--shadow); padding: var(--space-3) var(--space-4); margin-bottom: var(--space-3); transition: box-shadow var(--transition); } .faq-topic:hover { box-shadow: var(--shadow-hover); } /* A
with class "disclosure": the browser's own marker is replaced by a triangle that turns down when open. Shared by the FAQ topics and the past events, so "click to open" looks the same everywhere. */ .disclosure > summary { cursor: pointer; font-size: 1.15rem; font-weight: 600; color: var(--color-brand); list-style: none; display: flex; align-items: baseline; gap: var(--space-2); } .disclosure > summary::-webkit-details-marker { display: none; } .disclosure > summary::before { content: "▸"; color: var(--color-accent-dark); font-size: 0.9rem; } .disclosure[open] > summary::before { content: "▾"; } /* Space the questions off the topic heading once the topic is open. */ .faq-topic[open] > .faq-item:first-of-type { margin-top: var(--space-3); } .faq-topic-intro { margin-top: var(--space-2); color: var(--color-text-soft); } /* FAQ: each question is an expandable card with an accent +/– marker. */ .faq-item { background: var(--color-bg); border-radius: var(--radius); box-shadow: var(--shadow); padding: var(--space-3) var(--space-4); margin-bottom: var(--space-3); transition: box-shadow var(--transition); } .faq-item:hover { box-shadow: var(--shadow-hover); } .faq-item summary { cursor: pointer; font-weight: 600; color: var(--color-brand); list-style: none; display: flex; align-items: baseline; gap: var(--space-2); } .faq-item summary::-webkit-details-marker { display: none; } .faq-item summary::before { content: "+"; color: var(--color-accent-dark); font-weight: 700; font-size: 1.2rem; line-height: 1; } .faq-item[open] summary::before { content: "–"; } .faq-answer { padding-top: var(--space-2); color: var(--color-text); } /* --- Editor content (.markdown-body) ------------------------------------------- Everything the editors write in PocketBase (page bodies, posts, FAQ answers, the intros on /posts and /events) is Markdown rendered by Shared/Markdown.cs and wrapped in .markdown-body. Editors cannot add classes or HTML, so the look of their text comes entirely from these rules. Every selector is scoped to .markdown-body so nothing here leaks into the site's own components, and the rules must hold for any Markdown an editor might type, including none at all. */ /* The line icons the content styles need, as data URIs: no request, no foreign host. Same Lucide paths as Shared/IconSet.cs (license notice there); CSS cannot reach that C# set, so these are copies. Drawn in black and used as a mask over background-color: currentColor, so each icon takes the colour of its text -- dark mode included -- just like the inline-SVG component. */ .markdown-body { --icon-external-link: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 3h6v6'/%3E%3Cpath d='M10 14 21 3'/%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3C/svg%3E"); --icon-file-text: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z'/%3E%3Cpath d='M14 2v5a1 1 0 0 0 1 1h5'/%3E%3Cpath d='M10 9H8'/%3E%3Cpath d='M16 13H8'/%3E%3Cpath d='M16 17H8'/%3E%3C/svg%3E"); --icon-info: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 16v-4'/%3E%3Cpath d='M12 8h.01'/%3E%3C/svg%3E"); --icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7'/%3E%3Crect x='2' y='4' width='20' height='16' rx='2'/%3E%3C/svg%3E"); } /* A block's last element needs no gap below: the surrounding card or page already spaces it, and a trailing margin makes boxes look bottom-heavy. */ .markdown-body > :last-child, .markdown-body div > :last-child { margin-bottom: 0; } /* Section headings get a short green bar above them. The bodies are mostly a run of ## sections, and the bar makes each start easy to spot when scrolling on a phone. Decoration only: the heading text carries the meaning. */ .markdown-body h2::before { content: ""; display: block; width: 2.5rem; height: 4px; margin-bottom: var(--space-2); border-radius: 2px; background: var(--color-accent); } /* Lists: the reading width of paragraphs, a little air between items, and the bullets and numbers in the green accent so lists tie into the palette. */ .markdown-body ul, .markdown-body ol { margin: 0 0 var(--space-3); padding-left: 1.5rem; max-width: 42rem; } .markdown-body li + li { margin-top: var(--space-1); } .markdown-body li::marker { color: var(--color-accent-dark); font-weight: 700; } /* Quotes (e.g. a passage from the rules of procedure): an accent bar and a faint green wash set them apart from the editor's own words. */ .markdown-body blockquote { margin: 0 0 var(--space-3); padding: var(--space-3) var(--space-4); max-width: 42rem; border-left: 4px solid var(--color-accent); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; background: var(--color-accent-tint); } /* Links: a soft underline that firms up on hover. Underlined at all (not colour alone) so links stay recognisable for colour-blind visitors. */ .markdown-body a { text-decoration-color: color-mix(in srgb, currentColor 40%, transparent); text-decoration-thickness: 1px; text-underline-offset: 3px; transition: color var(--transition), text-decoration-color var(--transition); } .markdown-body a:hover { text-decoration-color: currentColor; } /* Links that leave the site get a small external-link icon, so visitors know before clicking. Editors write links to our own pages as relative paths (/contact), so "absolute http(s) URL" means "another site". PDFs are left out: they carry their own file icon below. */ .markdown-body a:is([href^="http://"], [href^="https://"]):not([href$=".pdf" i])::after { content: ""; display: inline-block; width: 0.8em; height: 0.8em; margin-left: 0.2em; vertical-align: -0.05em; background-color: currentColor; mask: var(--icon-external-link) center / contain no-repeat; } /* PDF links inside running text: a file icon in front and a small "PDF" tag behind, so visitors know a download (not a web page) opens. */ .markdown-body a[href$=".pdf" i]::before { content: ""; display: inline-block; width: 1em; height: 1em; margin-right: 0.25em; vertical-align: -0.15em; background-color: currentColor; mask: var(--icon-file-text) center / contain no-repeat; } .markdown-body a[href$=".pdf" i]::after { content: "PDF"; margin-left: 0.35em; padding: 0 0.35em; border-radius: 4px; background: var(--color-brand-tint); color: var(--color-text-soft); font-size: 0.75em; font-weight: 700; letter-spacing: 0.04em; } /* A PDF link standing alone in its paragraph or list item becomes a file card; this is what turns a plain list of documents on /downloads into a download area. Markdown.cs marks such paragraphs/items .lone-link, because CSS cannot see the text around a link. Two child paths: in a tight list the link sits directly in the
  • , in a loose list inside a

    . border-box: the 42rem include the padding, so the card ends flush with the running text instead of overhanging it (same for the aufruf and hinweis boxes below). */ .markdown-body .lone-link > a[href$=".pdf" i], .markdown-body .lone-link > p > a[href$=".pdf" i] { display: flex; align-items: center; gap: var(--space-3); box-sizing: border-box; max-width: 42rem; padding: var(--space-3) var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius); background: var(--color-bg); box-shadow: var(--shadow); font-weight: 600; text-decoration: none; transition: box-shadow var(--transition), border-color var(--transition); } .markdown-body .lone-link > a[href$=".pdf" i]:hover, .markdown-body .lone-link > p > a[href$=".pdf" i]:hover { border-color: var(--color-brand); box-shadow: var(--shadow-hover); } .markdown-body .lone-link > a[href$=".pdf" i]::before, .markdown-body .lone-link > p > a[href$=".pdf" i]::before { flex-shrink: 0; width: 1.5rem; height: 1.5rem; margin: 0; color: var(--color-accent-dark); background-color: var(--color-accent-dark); } /* The "PDF" tag moves to the card's right edge. */ .markdown-body .lone-link > a[href$=".pdf" i]::after, .markdown-body .lone-link > p > a[href$=".pdf" i]::after { margin-left: auto; } /* A list of file cards needs no bullets and no indent: the cards are the structure. */ .markdown-body li.lone-link:has(> a[href$=".pdf" i], > p > a[href$=".pdf" i]) { list-style: none; } .markdown-body ul:has(> li.lone-link > a[href$=".pdf" i], > li.lone-link > p > a[href$=".pdf" i]) { padding-left: 0; } /* Buttons: a mail link alone in its paragraph (the contact page's main action), and every link inside an "aufruf" box. Filled with the button blue (see --color-button for why not --color-brand); hover darkens it and adds a shadow, nothing moves. */ .markdown-body .lone-link > a[href^="mailto:"], .markdown-body .aufruf a { display: inline-flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-4); border-radius: var(--radius-sm); background: var(--color-button); color: var(--color-on-button); font-weight: 700; text-decoration: none; transition: background-color var(--transition), box-shadow var(--transition); } .markdown-body .lone-link > a[href^="mailto:"]:hover, .markdown-body .aufruf a:hover { background: var(--color-button-hover); color: var(--color-on-button); box-shadow: var(--shadow-hover); } /* The mail button leads with an envelope, so it reads as "write to us" at a glance. */ .markdown-body .lone-link > a[href^="mailto:"]::before { content: ""; width: 1.1em; height: 1.1em; background-color: currentColor; mask: var(--icon-mail) center / contain no-repeat; } /* --- Design blocks (::: name ... :::) ------------------------------------------ Markdown.cs turns "::: name" into

    . The names are German because editors type them (CLAUDE.md: values German). An unknown name has no rule here and so simply reads as normal text -- a typo never breaks a page. */ /* ::: aufruf -- a highlighted call to action: a tinted box with a brand-blue edge. Its links become buttons (rule above). */ .markdown-body .aufruf { box-sizing: border-box; /* padding inside the 42rem, flush with the text */ margin: 0 0 var(--space-4); padding: var(--space-4); max-width: 42rem; border-left: 4px solid var(--color-brand); border-radius: var(--radius); background: var(--color-brand-tint); } /* ::: hinweis -- a quiet info box with an info icon in front. Green wash, not the yellow highlight: it informs, it does not warn. The icon is decoration; the text says what matters. */ .markdown-body .hinweis { position: relative; box-sizing: border-box; /* padding inside the 42rem, flush with the text */ margin: 0 0 var(--space-4); padding: var(--space-3) var(--space-4) var(--space-3) 3.25rem; max-width: 42rem; border-radius: var(--radius); background: var(--color-accent-tint); } .markdown-body .hinweis::before { content: ""; position: absolute; top: calc(var(--space-3) + 0.2rem); left: var(--space-4); width: 1.25rem; height: 1.25rem; background-color: var(--color-accent-dark); mask: var(--icon-info) center / contain no-repeat; } /* ::: kacheln and ::: kennzahlen -- a list laid out as a grid of cards. auto-fill with a minimum width gives as many columns as fit (one on a phone) without any breakpoint. */ .markdown-body :is(.kacheln, .kennzahlen) > ul { display: grid; gap: var(--space-3); max-width: none; margin: 0 0 var(--space-4); padding: 0; list-style: none; } .markdown-body .kacheln > ul { grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); } .markdown-body .kennzahlen > ul { grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); } /* The grid gap does the spacing; the list's own item spacing would only push the later cards of the first row down. */ .markdown-body :is(.kacheln, .kennzahlen) li + li { margin-top: 0; } /* Kacheln: each item a white card; a bold start ("- **Mensa** ...") becomes the card's title on its own line. */ .markdown-body .kacheln li { padding: var(--space-3) var(--space-4); border-radius: var(--radius); background: var(--color-bg); box-shadow: var(--shadow); } .markdown-body .kacheln li > strong:first-child { display: block; margin-bottom: var(--space-1); color: var(--color-heading); } /* Kennzahlen: "- **seit 1975** Gründung" -- the bold part becomes a big figure, the rest a small caption beneath. Brand blue for the figure, not the green: the green does not reach 3:1 on its own tint, the blue does. */ .markdown-body .kennzahlen li { padding: var(--space-4) var(--space-3); border-radius: var(--radius); background: var(--color-accent-tint); color: var(--color-text-soft); text-align: center; } .markdown-body .kennzahlen li > strong:first-child { display: block; color: var(--color-brand); font-size: 2rem; font-weight: var(--font-weight-heading); letter-spacing: var(--letter-spacing-heading); line-height: 1.15; } /* ::: team -- one person card per list item (Markdown.cs/TeamMember.cs build the avatar, name, role chip, duty tags and note). Each "## Vorsitz" etc. above stays a normal heading; every group is a block of its own. One raster for all of them, so the cards line up across groups: a group of one person gets the same card width as a group of six, not a stretched one. 17rem fits a long double name. The cards of a row share one height (the grid's default stretch), so a row reads as a calm band; the card itself keeps its content at the top (align-content). */ .markdown-body .team > ul { display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: var(--space-3); max-width: none; margin: 0 0 var(--space-4); padding: 0; list-style: none; } .markdown-body .team li + li { margin-top: 0; } /* The card: avatar in a column of its own, everything else stacked beside it. Hover only deepens the shadow -- nothing moves. */ .markdown-body .team-card { display: grid; grid-template-columns: auto 1fr; column-gap: var(--space-3); align-content: start; padding: var(--space-3) var(--space-4); border-radius: var(--radius); background: var(--color-bg); box-shadow: var(--shadow); transition: box-shadow var(--transition); } .markdown-body .team-card:hover { box-shadow: var(--shadow-hover); } /* In a loose list (blank lines between items) Markdig wraps the card's text in a

    ; display: contents lets its parts join the card's grid all the same. */ .markdown-body .team-card > p:first-child { display: contents; } /* Everything but the avatar goes into the text column -- including whatever else an editor puts into the item (a second paragraph, a sub-list). */ .markdown-body .team-card > :not(.team-avatar), .markdown-body .team-card > p:first-child > :not(.team-avatar) { grid-column: 2; } /* A card without the convention (no bold name) is just its text. */ .markdown-body .team-card-plain { display: block; } .markdown-body .team-avatar { grid-row: 1 / span 4; display: grid; place-items: center; width: 3rem; height: 3rem; border-radius: 50%; font-weight: var(--font-weight-heading); letter-spacing: 0.02em; } .markdown-body .team-avatar-1 { background: var(--color-avatar-1); color: var(--color-on-avatar-1); } .markdown-body .team-avatar-2 { background: var(--color-avatar-2); color: var(--color-on-avatar-2); } .markdown-body .team-name { color: var(--color-heading); font-size: 1.15rem; line-height: 1.3; } /* The role as a chip under the name; justify-self keeps it as wide as its text, not the column. */ .markdown-body .team-role { justify-self: start; margin-top: var(--space-1); padding: 0.1rem var(--space-2); border-radius: 999px; background: var(--color-brand-tint); color: var(--color-brand-dark); font-size: 0.85rem; font-weight: 700; } /* Duties as small outlined tags: quieter than the role chip, because the role says who someone is and the duties only what they look after. A tag never breaks inside ("Stellvertretende Schulkonferenz" stays one piece); the row wraps between tags instead. */ .markdown-body .team-duties { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-top: var(--space-2); } .markdown-body .team-duty { white-space: nowrap; padding: 0.05rem var(--space-2); border: 1px solid var(--color-border); border-radius: var(--radius-sm); color: var(--color-text-soft); font-size: 0.85rem; } .markdown-body .team-note { margin-top: var(--space-2); color: var(--color-text-soft); font-size: 0.95rem; } /* ::: team gross -- the chair. Same raster and card as every other group, so the page keeps one rhythm; only the role chip stands out, filled in the button blue instead of the pale tint (white on it 5.4:1, in dark mode too). */ .markdown-body .team.gross .team-role { background: var(--color-button); color: var(--color-on-button); } /* Tables (pipe tables): not in the content yet, styled ahead of time. As a block with overflow they scroll sideways on a phone instead of stretching the page. */ .markdown-body table { display: block; max-width: 100%; overflow-x: auto; margin: 0 0 var(--space-4); border-collapse: collapse; } .markdown-body th, .markdown-body td { padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-border); text-align: left; vertical-align: top; } .markdown-body th { background: var(--color-surface); color: var(--color-heading); font-weight: 700; } /* Images never overflow the column and get the site's rounded corners. */ .markdown-body img { max-width: 100%; height: auto; border-radius: var(--radius-sm); } /* A horizontal rule as a calm thin line with room around it. */ .markdown-body hr { margin: var(--space-5) 0; border: none; border-top: 1px solid var(--color-border); }