/* Breadcrumb (breadcrumb.postcss:5-70) */
/* Ink text-500 as in CD (breadcrumb.postcss:8), for EVERY crumb including the
   active one; #6b7280 measures 4.83:1 on white (AA). Alignment/gap live here,
   not on the CD-neutral .container--flex base. */
.breadcrumb { background:transparent; border-bottom:0; font-size:var(--fs-sm); color:var(--color-text-500);
  align-items:center; gap:var(--sp-4); position:relative; z-index:var(--breadcrumb-z); }
/* CD scopes EVERY base rule to direct children — `& > nav > ul`,
   `& > nav > ul > li`, `& > nav > ul > li > a` (breadcrumb.postcss:15-27) — and
   the child combinators are load-bearing, not stylistic: the dropdown nests a
   second `ul > li > a` inside a crumb, and a descendant selector reaches into
   it. The portal had `.breadcrumb ul` / `li` / `a`, which was equivalent while
   the list was flat and broke the moment it was not: panel rows inherited
   `display:flex` and laid themselves out ACROSS the panel instead of down it,
   and the -16px list margin dragged the panel sideways (2026-08-13). */
.breadcrumb > nav > ul { list-style:none; display:flex; flex-wrap:wrap; align-items:center; padding-block:var(--sp-2); margin-left:calc(-1 * var(--sp-4)); }
@media (min-width:1280px){ .breadcrumb > nav > ul { padding-block:var(--sp-3); } }
/* `relative` is CD's (breadcrumb.postcss:20) and is what the dropdown is
   positioned against. Without it the panel resolves against `.breadcrumb`
   itself — also position:relative — and lands at the far left of the bar rather
   than under its own segment. */
.breadcrumb > nav > ul > li { display:flex; align-items:center; position:relative; color:var(--color-text-500); }
/* py-4 (1rem): the breadcrumb renders only at ≥1024px, where CD's md:py-4
   applies (breadcrumb.postcss:23-27); py-2 was the invisible mobile step. */
/* `leading-tight` is CD's (breadcrumb.postcss:27) and it is what makes the fixed
   `top-[3rem]` of the dropdown land exactly: py-4 twice plus a 1.25 line box on
   text-sm is 48px. At the inherited 1.5 the segment measured 52px and the panel
   overlapped it by 4px — the offset was never the thing to adjust. */
.breadcrumb > nav > ul > li > :is(a, span) { display:flex; align-items:center; padding:var(--sp-4); line-height:var(--lh-tight); text-decoration:none; }
.breadcrumb > nav > ul > li > a { color:var(--color-text-500); }
.breadcrumb > nav > ul > li > a:hover { color:var(--color-primary-600); text-decoration:none; }
/* Separator chevron at SvgIcon's 1rem base size (BreadcrumbNavigation.vue:108-112
   → icons.postcss:23-25 h-4); margins already match CD's -ml-5 mr-3. */
.breadcrumb__include-icon { margin-left:calc(-1 * var(--sp-5)); margin-right:var(--sp-3); width:var(--sp-4); height:var(--sp-4); }
@media (max-width:1023.98px){ .breadcrumb { display:none; } }

/* Breadcrumb dropdown (breadcrumb.postcss:46-113). CD draws a bordered box
   around the chevron ALONE — `border border-primary-600 rounded-sm` on
   .breadcrumb__dropdown-icon — so the disclosure already reads as its own
   control there. Here it IS one: a <button>, leaving the crumb link a link.
   The button is bare so the box remains the icon's, exactly as in CD. */
/* CD keeps the chevron INSIDE the link — <a class="px-4">{label}<icon ml-2/></a>
   — so label→icon is exactly ml-2 and the 16px px-4 falls OUTSIDE the icon.
   Splitting the control into a sibling button put that 16px BETWEEN label and
   icon, doubling the gap to 24px… measured 16px, because the button also pulled
   back 8px. Either way it was not CD's 8px. The link therefore gives up its
   right padding to the button, which reassembles the same three boxes.
   `font:inherit` is not cosmetic: <button> does not inherit font-size, so the
   icon's `1.25em` resolved against the UA's 13.33px and drew a 16.7px box
   instead of 17.5px. */
.breadcrumb__dropdown { display:flex; align-items:center; position:relative;
  padding:var(--sp-4) var(--sp-4) var(--sp-4) 0;
  border:0; background:none; color:inherit; font:inherit; cursor:pointer; }
/* `:is(a, span)`: the CURRENT page's crumb is a <span aria-current>, not a
   link, and it carries a dropdown too — so every rule that hands padding or the
   open-state sheet to the crumb head has to reach both forms. */
.breadcrumb > nav > ul > li:has(> .breadcrumb__dropdown) > :is(a, span) { padding-right:0; }
.breadcrumb__dropdown:hover { color:var(--color-primary-600); }
/* CD has no separate control, so it has no target size to meet; this one does.
   The box is 41.5px wide at CD's spacing, so the hit area is widened with a
   pseudo-element instead of padding — padding would move the chevron and break
   the 8px the rule above just restored. */
.breadcrumb__dropdown::before { content:''; position:absolute; top:0; bottom:0;
  left:calc(-1 * var(--sp-1-5)); right:calc(-1 * var(--sp-1-5)); }
/* w-[1.25em] h-[1.25em], ml-2, primary-600 text + 1px border, rounded-sm.
   The frame is a WRAPPER, not the icon. CD puts the border on the inline <svg>
   and strokes the chevron inside it; the portal draws icons as CSS masks, and a
   mask clips everything the element paints — the border with it. Measured: at
   the corner of a masked bordered box the painted pixel is the page behind it,
   not the border colour, so the rule was there and had never once been visible.
   Splitting frame from glyph also lands closer to CD than the old rule did:
   there only the <path> turns while the frame stays put. */
.breadcrumb__dropdown-box { display:inline-flex; align-items:center; justify-content:center;
  flex:none; width:1.25em; height:1.25em; margin-left:var(--sp-2);
  border:var(--stroke-1) solid var(--color-primary-600); border-radius:var(--radius-sm); }
.breadcrumb__dropdown-icon { width:1em; height:1em; color:var(--color-primary-600);
  transition:transform var(--duration-slow); }
.breadcrumb__dropdown[aria-expanded="true"] .breadcrumb__dropdown-icon { transform:rotate(180deg); }
/* .clicked in CD: the open segment lifts onto white with the panel's shadow, and
   clips it at the bottom so panel and segment read as one sheet.
   The segment must sit ABOVE its own panel or the shadow it casts lands under
   the sheet it is supposed to join: CD pairs z-50 on the segment with z-10 on
   the panel, and the two tokens below keep that order (20 > 10). */
.breadcrumb > nav > ul > li:has(> .breadcrumb__dropdown[aria-expanded="true"]) > :is(a, span) {
  position:relative; z-index:var(--z-breadcrumb); background:var(--color-bg);
  box-shadow:var(--shadow-2xl); clip-path:inset(-50px -50px 0 -50px); }
/* The separator chevron fades out while the segment is open (CD :63-70, 200ms). */
.breadcrumb > nav > ul > li:has(> .breadcrumb__dropdown[aria-expanded="true"]) .breadcrumb__include-icon {
  opacity:0; transition:opacity var(--duration); }
/* Panel: w-[300px] p-2 mt-px, absolute top-[3rem] left-0, white, shadow-2xl.
   CD addresses it as `.breadcrumb ul ul` (breadcrumb.postcss:93); the nested
   list is the only second-level one, so the same form is used here. */
.breadcrumb ul ul { position:absolute; top:var(--sp-12); left:0; z-index:var(--z-dropdown);
  width:300px; padding:var(--sp-2); margin-top:var(--stroke-1); list-style:none;
  background:var(--color-bg); box-shadow:var(--shadow-2xl); }
/* Explicit, not inherited: these rows must stack whatever the bar above does. */
.breadcrumb ul ul li { display:block; }
/* Rows are CD menu items: menu__item--mini (px-4 py-2) + --border. */
.breadcrumb ul ul a { display:block; width:100%; padding:var(--sp-2) var(--sp-4);
  border-bottom:var(--stroke-1) solid var(--color-secondary-100); color:var(--color-text-500);
  text-decoration:none; transition:background-color var(--duration), color var(--duration); }
.breadcrumb ul ul li:last-child a { border-bottom:0; }
.breadcrumb ul ul a:hover { background:var(--color-secondary-50); color:var(--color-primary-600); }
/* CD marks the open page with a 2px bar at the left edge (breadcrumb.postcss:106-111).
   Note it is 2px/primary-600 here, NOT the 3px/primary-500 of menu__item--active. */
.breadcrumb ul ul a.active { position:relative; }
.breadcrumb ul ul a.active::after { content:''; position:absolute; top:0; bottom:0; left:0;
  width:var(--stroke-2); background:var(--color-primary-600); }

/* Footer (footer.postcss:5-104) */
/* The footer forms the back-to-top button's reference frame; its stacking
   context sits above content (--z-content) but below the document viewer
   (--z-viewer), keeping the button visible without covering modals. */
.site-footer { position:relative; z-index:var(--z-footer); }
.footer-information { display:flex; flex-direction:column; color:var(--color-text-negative); padding-block:var(--section-py); }
@media (min-width:1024px){ .footer-information { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:var(--sp-16); } }
@media (min-width:1280px){ .footer-information { grid-template-columns:repeat(4,minmax(0,1fr)); } }
.footer-information__entry { color:var(--color-text-negative); margin-bottom:var(--sp-16); }
.footer-information__entry:last-child { margin-bottom:0; }
@media (min-width:1024px){ .footer-information__entry { margin-bottom:0; } }
@media (min-width:1280px){ .footer-information__entry--big { grid-column:span 2; } }
/* REGULAR weight: CD's footer heading is text--xl with NO bold — Preflight
   resets h3 and footer.postcss:49-52 adds only size and margin. The global
   `h1…h5 { font-weight:bold }` (foundations/typography.css) leaked 700 in
   here; the tenant portal renders regular (2026-08 alignment D16). */
.footer-information__entry h3 { font-size:var(--text-xl); font-weight:var(--fw-regular); color:var(--color-text-negative); margin-bottom:var(--sp-6); }
@media (min-width:1024px){ .footer-information__entry h3 { margin-bottom:var(--sp-10); } }
.footer-information__entry p { margin-bottom:var(--sp-3); }   /* CD footer.postcss:54-60 mb-3 xl:mb-4 */
@media (min-width:1280px){ .footer-information__entry p { margin-bottom:var(--sp-4); } }
/* Footnote voice on the dark band: one step down the type ramp and a quieter
   ink, so a caveat reads as a caveat. A named tone rather than a transparency —
   the band's colour changes with the skin, and a fixed opacity would land on a
   different contrast in each. secondary-100, not -200: at 16px this is body
   text, so it needs 4.5:1, and -200 measured 4.16 on the intranet band (its
   secondary-600 is a saturated blue, darker in effect than the default skin's,
   where the same tone passed at 4.87). Verified in BOTH skins. */
.footer-information__note { font-size:var(--text-sm); color:var(--color-secondary-100); }
.footer-information__entry p:last-child { margin-bottom:0; }
.footer__link { display:inline-flex; align-items:center; padding-block:var(--sp-2); color:var(--color-text-negative); cursor:pointer; text-decoration:none; }
.footer__link:hover { color:var(--color-gray-300); text-decoration:none; }
.footer-information__icon { display:inline-block; margin-right:var(--sp-1); width:1.4em; height:1.4em; flex:none; }
.footer-information__links { display:flex; flex-direction:column; margin-top:calc(-1 * var(--sp-4)); }
@media (min-width:640px){ .footer-information__links { flex-direction:row; gap:var(--sp-16); } }
@media (min-width:1024px){ .footer-information__links { flex-direction:column; gap:0; } }
@media (min-width:1280px){ .footer-information__links { flex-direction:row; gap:var(--sp-16); } }
.footer-information__links-column { flex:1; }
.footer-information__links .footer__link { width:100%; display:flex; justify-content:space-between;
  padding:var(--sp-4) var(--sp-2); border-bottom:var(--stroke-1) solid var(--color-secondary-300); }
.footer-information__links .footer__link:hover { background:var(--color-secondary-700); color:var(--color-text-negative); }
/* CD footer.postcss:100-102: in link rows ONLY icon height grows to h-6
   (1.5rem); width remains CD's w-[1.4em] (footer.postcss:28). */
.footer-information__links .footer-information__icon { height:var(--sp-6); }
.footer-information__link--icon-right { flex-direction:row-reverse; }
/* CD footer.postcss:33-38: relative ml-[0.2em] left-[0.1em]; the optical nudge
   moves the right-hand icon to the line edge. */
.footer-information__link--icon-right .footer-information__icon { position:relative; left:.1em; margin-left:.2em; margin-right:0; }
.footer-navigation { list-style:none; display:flex; flex-wrap:wrap; padding-block:var(--sp-3); gap:var(--sp-2);
  font-size:var(--text-xs); color:var(--color-secondary-100); }
@media (min-width:640px){ .footer-navigation { gap:var(--sp-4); } }
/* No dedicated link color in the right band: base .footer__link applies
   unchanged (white at rest → gray-300 on hover/focus, CD footer.postcss:19-23).
   The former inversion (gray → white) directly opposed CD (nav/ft-2). */

/* Page chrome */
.site-main { min-height:50vh; flex:1 0 auto; position:relative; z-index:var(--z-content); }

/* Standalone micro-app shell. The router owns this class and removes it before
   every dispatch, so a failed or departed tool cannot strand hidden portal
   chrome. Logged-out deep links retain the ordinary shell because the class is
   applied only after the central login gate. */
body.body--standalone-app { height:100dvh; min-height:0; overflow:hidden; padding-bottom:0; }
.body--standalone-app > .site-header,
.body--standalone-app > .data-status,
.body--standalone-app > .site-footer,
.body--standalone-app > .banner-host { display:none; }
.body--standalone-app > .site-main { min-height:0; height:100dvh; overflow:hidden; z-index:var(--z-local-content); }

/* A fixed-viewport standalone app scrolls INSIDE itself, so the root scrollbar
   can never move. Two mechanisms nevertheless drew one: `overflow-y:scroll` in
   the reset (which prevents layout shift between short and long portal pages)
   and `scrollbar-gutter:stable` in overlay.css. Beside the app's own scrollbar
   that read as a second, dead scrollbar. Both are switched off here; the body
   already clips, so nothing becomes unreachable. Plan Check is excluded below —
   it scrolls the document and needs the root scrollbar. */
html:has(> body.body--standalone-app) { overflow-y:hidden; scrollbar-gutter:auto; }

/* Plan Check is a document-length workflow, not a fixed workbench. Let it grow
   with its content and use the root page scrollbar; an internal 100dvh scroll
   frame left the app visually truncated above an otherwise blank viewport. The
   rule above matches it too, but this selector is more specific and wins. */
html:has(> body.body--standalone-app .plan-check) { overflow-y:auto; scrollbar-gutter:auto; }
body.body--standalone-app:has(.plan-check) { height:auto; min-height:100dvh; overflow:visible; }
body.body--standalone-app:has(.plan-check) > .site-main { height:auto; min-height:100dvh; overflow:visible; }

@media print {
  /* Every standalone app prints as a document of its natural length, so the
     root must not clip — it now hides its overflow on screen for all of them,
     not only for Plan Check. */
  html:has(> body.body--standalone-app) { overflow:visible; }
  .body--standalone-app { overflow:visible; height:auto; }
  .body--standalone-app > .site-main { height:auto; overflow:visible; }
}

/* Readable line length (Item 2.18). CD enforces it structurally through
   container__center--*, but .page-header and .detail-section do not sit in the
   12-column grid, hence this cap. Measured at 1440: leads 133ch, body copy
   148-166ch, roughly twice a readable length. */
/* No independent cap: 60rem made title and lead wrap in mid-flow while the
   surrounding container was much wider, making the wrap look arbitrary. The
   column containing the header now controls measure alone (CD does the same:
   no max-width on text classes, but container__center--* around content). */
/* Page-header spacing = the tenant portal's shared values (2026-08 alignment
   D24): title→sub gap 8px, bottom space 24 → 32 @1024 → 48 @1280. The h1
   keeps the FIXED CD step ramp — the former `clamp(…, 7.5vw, …)` dropped
   page titles to 22px below ~347px viewports, off the CD scale; CD holds
   text--3xl at 26px on every phone (hyphens+wrap already handle the long
   compounds). */
.page-header { padding:var(--sp-1) 0 var(--sp-6); }
@media (min-width:1024px){ .page-header { padding-bottom:var(--sp-8); } }
@media (min-width:1280px){ .page-header { padding-bottom:var(--sp-12); } }
.page-header h1 {
  margin-bottom:var(--sp-2);
  font-size:var(--text-3xl);
  overflow-wrap:break-word;
  hyphens:auto;
}
/* ONE unscoped lead recipe, instead of one copy per context. `lh-snug` —
   the CD hero-description leading (hero.postcss:30-34), shared with the
   tenant portal's leads (2026-08 alignment D18). */
.lead { font-size:var(--text-lg); line-height:var(--lh-snug); color:var(--color-text-muted); }
/* No more max-width caps on lead, page header or lead notice: they wrapped text
   in mid-flow while the surrounding container was wider. Measure now comes
   exclusively from the column containing the text, exactly as in CD, which
   places `container__center--*` around content instead of capping text classes.
   Where a surface measures too wide, the answer is the column grid (Stage 7),
   not a cap on the class. */
/* NO individual 70ch caps on detail-/anchor-section prose: measure comes from
   the column (container__main at 60rem or the measure-xl article wrapper on
   sheet pages). Individual caps created exactly the ragged widths ("text ends,
   box continues") criticized in the review (C25). */
/* The 70ch cap on `.search-result` was REMOVED: CD places the result list
   directly in `.container` without `container__center--*`
   (searchResults.vue:45-46), so results use the full container width. The cap
   ended the line at 70ch while divider and surroundings continued, making the
   list look indented instead of aligned. The long line is accepted: titles and
   two-line descriptions are short, and CD defines no cap for this component. */
/* DOCUMENTED EXCEPTION to column measure (C25): notifications can appear in
   full-width contexts (error banners, dashboards); 70ch is a component-internal
   readability limit, not a substitute for a column. */
.notification__content > p,
.notification__content > ul { max-width:70ch; }       /* Login gates measured 137ch */
/* The former 70ch preemption on .container__main children is gone; the column
   itself measures 60rem (see grid rules above, C25). */
/* De-emphasized suffix in a case title: `BBL-2026-1042 — <title>` (tenant-portal page-header__count) */
.case-title-sub { font-weight:var(--fw-regular); color:var(--color-text-muted); }
/* Measure on the parent instead of the paragraph (C25): the introductory
   header of anchor pages is capped as a block, aligning the lead and intro. */
.anchor-page__header { max-width:60rem; }
.page-intro { margin-top:0; }

/* Hero (hero.postcss:5-155) — CD heroes sit on white; tint comes from bg-- sections */
.hero { padding-top:var(--section-pt); padding-bottom:var(--section-py); background:none; border-bottom:0; }
/* The former :has() special case for title-only heroes is gone: its only
   consumer (metadata-catalogue details) now uses the app-detail recipe
   detailBar + h1 instead of a hero (Design Review B2). */
.hero__content { display:flex; flex-direction:column; gap:var(--sp-6); max-width:60rem; }
@media (min-width:1024px){ .hero__content { gap:var(--sp-8); } }
@media (min-width:1920px){ .hero__content { gap:var(--sp-10); } }   /* hero.postcss:14-16 3xl:space-y-10 */
/* CD hero--title-only = 6/12 columns (container__center--xs). DELIBERATE
   DEVIATION: CD CENTERS this column (container.postcss:65-87); here it stays
   flush left, the same decision as .container__main above. The back bar and
   tabs over detail headers start in column 1, so a centered heading would read
   as misalignment. */
.hero:not(.hero--main-image) .hero__content { max-width:42rem; }
/* text--3xl matches CD's .hero__title (hero.postcss:18-22) AND h1/.h1; text--4xl
   is reserved for hero--main in CD. Previously the hero h1 was one step larger
   than every other h1 in the product. */
.hero__title { font-size:var(--text-3xl); font-weight:var(--fw-bold); line-height:var(--lh-tight);
  overflow-wrap:anywhere; margin:0; }
/* Title row: the heading plus whatever acts ON the record as a whole — today the
   «merken» star (js/ui/bookmark.js) on the heads that have no picture to carry
   it. `align-items:start` keeps it on the first line of a heading that wraps to
   three, rather than floating beside its middle. The row is part of
   .hero__content's flex column, so a head without one is laid out exactly as
   before. */
.hero__titlebar { display:flex; align-items:flex-start; justify-content:space-between; gap:var(--sp-4); }
.hero__titlebar > .hero__title { flex:1 1 auto; }
/* An icon-only toggle, so it needs its own hit area: .btn--bare
   carries no padding of its own. --target-min is the touch minimum used by the
   tree rows as well. */
.bookmark-icon { flex:none; min-width:var(--target-min); min-height:var(--target-min);
  align-items:center; justify-content:center; color:var(--color-text-light); }
/* Over a picture the control is an OVERLAY, not a row item: .hero__image already
   carries `position:relative` above, so top/right place it in the corner of the
   image itself. Three things change with the placement:
   — SIZE. Beside a heading it borrows the text scale; over a 16:9 hero it
     competes with a photograph, so the icon is set explicitly. `.btn .icon`
     (0,2,0) would otherwise hold it at 1.4em, hence the descendant selector.
   — DISC. An outline glyph has no contrast guarantee over an arbitrary photo
     (the catalogue alone runs from pale site plans to dark façades). The
     surface disc gives it ONE background instead of one per image, so the
     control looks the same on every detail page and its focus ring lands on a
     known colour. The disc then needs its OWN edge for the same reason it
     exists: on a bright image it is white on near-white, so
     --shadow-overlay-control rather than a card elevation (tokens.css).
     No z-index: the control follows the image in the DOM and is the later
     positioned element, which is already the whole stacking answer.
   — TARGET. Icon plus padding is 3.5rem, above --target-min, so the minimum
     sizes inherited from .bookmark-icon do nothing here. */
/* TOP LEFT, the reading corner: the mark on a catalogue row sits beside the
   record's name and the mark on a card sits under its title, both on the left.
   The head follows them rather than the other way round, so «saved» is always
   found in the same place relative to what it belongs to. */
.hero__image > .bookmark-icon { position:absolute; top:var(--sp-3); left:var(--sp-3);
  padding:var(--sp-2); border-radius:var(--radius-full); color:var(--color-secondary-800);
  background:var(--color-bg); box-shadow:var(--shadow-overlay-control); }
.hero__image > .bookmark-icon .btn__icon { width:var(--sp-10); height:var(--sp-10); }
/* The read-only mark (js/ui/bookmark.js) — the same symbol as the saved toggle
   and the same colour, so the catalogue and the detail page agree. Inline-flex
   rather than inline: the icon is a mask span with no baseline of its own, and
   in a pill row it must centre against the badges beside it. */
.bookmark-mark { display:inline-flex; align-items:center; color:var(--color-primary-600); }
/* The two state rules below stay LAST and keep their (0,2,0) weight: they tie
   with the overlay rule above and win on order, so hover and saved read the
   same in the corner of an image as they do beside a heading. */
.bookmark-icon:hover, .bookmark-icon:focus-visible { color:var(--color-primary-600); }
/* Saved state is carried by the FILLED icon; the colour only reinforces it, so
   the control never rests on colour alone. */
.bookmark-icon[aria-pressed="true"] { color:var(--color-primary-600); }
/* DELIBERATE DEVIATION: CD leaves the hero description in default ink
   (hero.postcss:30-34, only text--lg leading-snug). The muted lead is a
   portal-wide convention: .page-header .lead and the home-page lead share the
   same muted text-lg voice; ONE lead treatment across the product. */
.hero__description { font-size:var(--text-lg); line-height:var(--lh-snug); color:var(--color-text-muted); margin:0; }
/* (Dead rules removed in the 2026-08 code review, F-S30 — no emitter in any template.) */
/* hero--main-image (hero.postcss:70-88): content and image share the 12-col
   grid from md up; below that the content stacks above the image. */
/* No independent padding: the .detail-bar rule (Detail pages below) resets the
   top; .heros var(--section-py) applies below, following CD's container--py
   rhythm. Column spacing is CD's gap--responsive
   (hero.postcss:79 grid--responsive-cols-2). */
.hero--main-image { display:grid; gap:var(--gap-responsive);
  /* CD gives THIS variant symmetric container--py — 56/80@1024/128@1920,
     5rem at lg exactly as bbl.admin.ch renders it — overriding the base
     hero's tighter 48/56/80 top (hero.postcss:73-74 `@apply container--py`
     vs :7 `pt-12 lg:pt-14 3xl:pt-20`). Verified in CD source; alignment
     D54 (user finding 2026-08-22). */
  padding-top:var(--section-py); }
.hero--main-image .hero__content { max-width:none; }
@media (min-width:768px){
  /* NO align-items here, which is CD's own arrangement (hero.postcss:70-88):
     the grid default `stretch` gives both columns the row height, so the image
     sits at the TOP of its cell however tall the other column grows. The portal
     used to add `align-items:center`, which centres the two BOXES against each
     other — fine while they are similar heights, wrong once one can grow: an
     opened source selection floated the image halfway down beside it.

     And the content starts at the top too, for the same reason one step in:
     `justify-content:center` centred the copy inside the stretched column, so
     opening the selection pulled the TITLE up by 39px while the image stayed
     put. Nothing on the page should move because a panel below it opened.

     The margin is what centring used to supply by accident. Flush against the
     image the title reads as fighting the photo edge — the cap already starts
     17px below its own line-box top, and 1rem more puts it just under the image
     edge, paired with it rather than butted against it. Two columns only exist
     from this breakpoint up; stacked, the title follows the header and the
     extra space would be dead. */
  .hero--main-image { grid-template-columns:minmax(0,1fr) minmax(0,1fr); }
  .hero--main-image .hero__content { justify-content:flex-start; }
}
/* The optical offset applies ONLY on the widest tier (user decision
   2026-08-22, alignment D45; same 2rem as the tenant portal — the value
   bbl.admin.ch itself uses: its hero column is Tailwind space-y-8 = 2rem,
   i.e. margins of calc(2rem*var(--tw-space-y-reverse))). In the compact
   two-column tier (768–1279) the offset read as dead space — none there. */
@media (min-width:1280px){ .hero--main-image .hero__title { margin-top:var(--sp-8); } }
.hero__image { display:block; position:relative; overflow:hidden; width:100%; }
/* Otherwise the <figure> in a hero carries the user-agent default
   `margin:1em 40px`: the image did not fill its grid column, sat 40px inset on
   both sides, and the 1em above/below offset it from the vertically centered
   text column. `.chart` and `.home-hero__figure` each reset the same margin;
   this structural `.hero__image figure` rule prevents the next hero page from
   needing a fourth special case. */
.hero__image figure, .hero__figure { margin:0; }
.hero__image .photo { width:100%; }
.hero__image .hero-media--natural > img { position:static; width:100%; height:auto; object-fit:contain; }
.hero__image > img { display:block; width:100%; height:auto; background:var(--color-secondary-50); }
.hero__image > .hero-media--16x9, .hero__image figure > .hero-media--16x9 {
  aspect-ratio:16/9; object-fit:cover; }
/* flex children must be allowed to shrink below their intrinsic width, or the
   row overflows the container (the old `.container{overflow-x:clip}` hid this) */
.search__form input { min-width:0; }
.row > * { min-width:0; }

