/* The --sav-color-* custom properties and --sav-content-width come from
   /design-tokens.css, generated from theme.json, so the palette and the layout
   width have one source. Bright shades carry surfaces, strong shades carry text
   and accents. */

/* Akkurat LL is licensed for arbeitgeber.ch and its subdomains only, and the
   font files must keep their original names — only the family name below is a
   free CSS alias, deliberately generic so markup never hard-codes the vendor.
   Only the cuts the design uses ship: Light, Regular and Bold. */

@font-face {
    font-family: 'SAV Sans';
    src: url('../fonts/AkkuratLLWeb-Light.woff2') format('woff2');
    font-weight: 300;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'SAV Sans';
    src: url('../fonts/AkkuratLLWeb-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'SAV Sans';
    src: url('../fonts/AkkuratLLWeb-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

/* While Akkurat loads, the text is drawn in Arial with Akkurat's own metrics
   patched onto it, so the swap barely moves a line or a break (no CLS). The
   overrides are Akkurat's metrics (units per em 1000, ascent 955, descent 245,
   no line gap) normalised against Arial's; size-adjust is the ratio of the two
   fonts' frequency-weighted average glyph width, both measured the same way. */
@font-face {
    font-family: 'SAV Sans Fallback';
    src: local('Arial');
    size-adjust: 105.71%;
    ascent-override: 90.34%;
    descent-override: 23.18%;
    line-gap-override: 0%;
}

/* The typographic scale and the grid from the Figma styleguide. Every size and
   line-height scales fluidly with the viewport (Utopia method): clamp() holds
   the Figma mobile value at 375px, the Figma desktop value at 1728px, and
   interpolates in between. Floor and ceiling are in rem and the interpolant
   keeps a rem term, so the sizes still grow with the browser text size and page
   zoom — WCAG 1.4.4 stays satisfied, no size is expressed in vw alone. Tracking
   is in em and thus follows the size on its own.

   These are the source values; the text styles below expose them as classes so
   nothing is bound to an element. */

:root {
    --sav-font-text: 'SAV Sans', 'SAV Sans Fallback', 'Helvetica Neue', Arial, sans-serif;
    --sav-font-weight-light: 300;
    --sav-font-weight-regular: 400;
    --sav-font-weight-bold: 700;

    /* Headline XL — 38/46 → 65/78, tracking -1px */
    --sav-text-headline-xl-size: clamp(2.375rem, 1.9073rem + 1.9956vw, 4.0625rem);
    --sav-text-headline-xl-line: clamp(2.875rem, 2.3207rem + 2.3651vw, 4.875rem);
    --sav-text-headline-xl-tracking: -0.015em;

    /* Headline L — 34/42 → 60/70, tracking -1px */
    --sav-text-headline-l-size: clamp(2.125rem, 1.6746rem + 1.9217vw, 3.75rem);
    --sav-text-headline-l-line: clamp(2.625rem, 2.14rem + 2.0695vw, 4.375rem);
    --sav-text-headline-l-tracking: -0.017em;

    /* Headline M — 28/36 → 40/50, tracking -0.5px */
    --sav-text-headline-m-size: clamp(1.75rem, 1.5421rem + 0.8869vw, 2.5rem);
    --sav-text-headline-m-line: clamp(2.25rem, 2.0075rem + 1.0347vw, 3.125rem);
    --sav-text-headline-m-tracking: -0.0125em;

    /* Headline S — 22/30 → 28/36, tracking -0.5px */
    --sav-text-headline-s-size: clamp(1.375rem, 1.2711rem + 0.4435vw, 1.75rem);
    --sav-text-headline-s-line: clamp(1.875rem, 1.7711rem + 0.4435vw, 2.25rem);
    --sav-text-headline-s-tracking: -0.018em;

    /* Text L / Lead — 20/30 → 30/44, Light */
    --sav-text-l-size: clamp(1.25rem, 1.0768rem + 0.7391vw, 1.875rem);
    --sav-text-l-line: clamp(1.875rem, 1.6325rem + 1.0347vw, 2.75rem);

    /* Text M — 18/28 → 22/32, tracking -0.2px */
    --sav-text-m-size: clamp(1.125rem, 1.0557rem + 0.2956vw, 1.375rem);
    --sav-text-m-line: clamp(1.75rem, 1.6807rem + 0.2956vw, 2rem);
    --sav-text-m-tracking: -0.009em;

    /* Text S — 16/24 → 20/32, Light */
    --sav-text-s-size: clamp(1rem, 0.9307rem + 0.2956vw, 1.25rem);
    --sav-text-s-line: clamp(1.5rem, 1.3614rem + 0.5913vw, 2rem);

    /* Text XS — 14/22 → 16/26 */
    --sav-text-xs-size: clamp(0.875rem, 0.8404rem + 0.1478vw, 1rem);
    --sav-text-xs-line: clamp(1.375rem, 1.3057rem + 0.2956vw, 1.625rem);

    /* Label/Tag — 14/14 across the range, tracking +0.2px */
    --sav-text-label-size: 0.875rem;
    --sav-text-label-line: 0.875rem;
    --sav-text-label-tracking: 0.014em;

    /* Grid — mobile: 4 columns, gutter 20, margin 20;
       desktop: 12 columns à 85px, gutter 30 → 1350px content width.
       The column count is an integer, so the grid keeps its one breakpoint
       while the type scales continuously. The content width itself is
       --sav-content-width, served from theme.json's wide size. */
    --sav-grid-columns: 4;
    --sav-grid-gutter: 1.25rem;
    --sav-page-margin: 1.25rem;

    /* What a block spanning the whole screen aligns its content on. `100vw` and not
       `100%`: such a block measures against the screen, scrollbar included. */
    --sav-band-width: min(var(--sav-content-width), 100vw - 2 * var(--sav-page-margin));

    /* 1120px, the ten of the twelve columns the design centres a section's own list on:
       the FAQ accordion, the download lists and their section title, and the text of the
       page head. It sits between the two bands theme.json serves and is a constant, so it
       stands here rather than there. */
    --sav-inner-width: 70rem;

    /* 775px, the seven of the twelve columns the design wraps running text at where it stands
       narrower than the reading column theme.json serves as --sav-text-width: a page built of
       sections, the «Hervorhebung» with one picture, the newsletter band. */
    --sav-narrow-width: 48.4375rem;

    /* 60px → 140px, the distance the theme keeps around a section on a page. */
    --sav-section-gap: clamp(3.75rem, 3.75rem + (100vw - 24.375rem) * 0.05979, 8.75rem);

    /* The corner the design rounds a surface with — a picture, a tinted box.
       In px, and the only length here that is: a corner belongs to the shape,
       not to the text inside it, so it stays as drawn at any text size. A pill
       or a circle states its own radius, this is the value that repeats. */
    --sav-radius: 5px;

    /* Motion. The curve is the one the design references: it starts fast and settles slowly,
       which is what makes an unfolding panel look like it comes to rest rather than stops.
       Unfolding is the slowest step, what appears inside it is quicker, and the stagger is
       the distance between two entries of the same list. */
    --sav-ease-out: cubic-bezier(0.16, 1, 0.32, 1);
    --sav-duration-unfold: 500ms;
    --sav-duration-fade: 350ms;
    --sav-stagger: 45ms;
}

@media (min-width: 64rem) {
    :root {
        --sav-grid-columns: 12;
        --sav-grid-gutter: 1.875rem;
    }
}

/* The colour of a Themenbereich, wherever one is shown: `data-color` names the light tone the
   term carries, and the pair below adds the strong shade that belongs beside it. One place for
   the pairing, so a ressort wears the same two tones on every page it appears on. */
[data-color] {
    /* Neutral where the term names no tone, and where it names the one without a strong shade. */
    --sav-topic-light: var(--sav-color-hellgrau);
    --sav-topic-strong: var(--sav-color-hellgrau);
}

[data-color='hellblau'] {
    --sav-topic-light: var(--sav-color-hellblau);
    --sav-topic-strong: var(--sav-color-blau);
}

[data-color='hellgelb'] {
    --sav-topic-light: var(--sav-color-hellgelb);
    --sav-topic-strong: var(--sav-color-gelb);
}

[data-color='hellgruen'] {
    --sav-topic-light: var(--sav-color-hellgruen);
    --sav-topic-strong: var(--sav-color-gruen);
}

[data-color='hellrot'] {
    --sav-topic-light: var(--sav-color-hellrot);
    --sav-topic-strong: var(--sav-color-rot);
}

[data-color='helllila'] {
    --sav-topic-light: var(--sav-color-helllila);
    --sav-topic-strong: var(--sav-color-lila);
}

/* reset resets the user-agent styles, base sets the document defaults, and the
   text styles live in the utilities layer. The order is declared so a text
   style always wins over an element default without a specificity fight, and a
   component stylesheet (unlayered) still wins over everything here. */
@layer reset, base, utilities;

@layer reset {
    *,
    *::before,
    *::after {
        box-sizing: border-box;
    }

    :where(body, h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd) {
        margin: 0;
    }

    /* Typography is not bound to semantics: a heading carries meaning, its size
       comes from a text style applied in the markup, not from the element. */
    :where(h1, h2, h3, h4, h5, h6) {
        font-size: inherit;
        font-weight: inherit;
    }

    /* A source note stands shifted, and the user agent gives it the line height of the text
       around it: that box, shifted, grows the line it stands in by a third. */
    :where(sup, sub) {
        line-height: 0;
    }

    :where(ul[role='list'], ol[role='list']) {
        padding: 0;
        list-style: none;
    }

    /* A custom element the user agent knows no display value for, so it stays inline until
       Turbo upgrades it — which never happens where the script did not run, and the two would
       then lay out differently. */
    :where(turbo-frame) {
        display: block;
    }

    :where(img, picture, video, canvas, svg) {
        display: block;
        max-width: 100%;
        height: auto;
    }

    :where(input, button, textarea, select) {
        font: inherit;
        color: inherit;
    }
}

@layer base {
    /* A jump inside the page glides to its target instead of cutting to it, so the
       reader sees where they land — but not for a visitor who asked for less motion.
       The editor loads these styles as well and scrolls its canvas itself while
       typing, where an animation would drag the caret along, so it is left out. */
    :where(html:not(:has(.editor-styles-wrapper))) {
        /* The header stays at the top of the viewport and would cover a jump target,
           so every jump stops that much earlier. Without a header — the playground,
           and until the header carries the variable — the target sits at the very top. */
        scroll-padding-top: var(--sav-header-height, 0px);

        @media (prefers-reduced-motion: no-preference) {
            scroll-behavior: smooth;
        }
    }

    :where(body) {
        font-family: var(--sav-font-text);
        font-weight: var(--sav-font-weight-regular);
        font-size: var(--sav-text-m-size);
        line-height: var(--sav-text-m-line);
        letter-spacing: var(--sav-text-m-tracking);
        color: var(--sav-color-dunkelblau);
    }

    :where(h1, h2, h3, h4, h5, h6) {
        color: var(--sav-color-blau);
    }

    :where(a) {
        color: var(--sav-color-blau);
    }

    :where(p) {
        overflow-wrap: break-word;
        text-wrap: pretty;
    }

    /* A list item is running text too: without this a long compound keeps the
       line at its own width and pushes the page sideways once the reader
       enlarges the text. */
    :where(li) {
        overflow-wrap: break-word;
    }

    /* The bands of the content grid, on the classes the editor lays its canvas out
       with, so a block sits at the same width there and on the page. Running text
       gets the narrow one; a block belonging in the wide band carries `alignwide`
       from the markup — core's own name for it, and the only one its canvas
       listens to. The block sets it fixed, so the width stays a property of the
       block instead of a choice in the editor. The widths come from theme.json,
       where the editor reads them too.

       min() keeps a band from widening an element that brings its own size along —
       an image would otherwise be drawn at the band's width and push past the edge
       of a narrow screen. */
    .is-layout-constrained {
        padding-inline: var(--sav-page-margin);
    }

    .is-layout-constrained > * {
        max-width: min(100%, var(--sav-text-width));
        margin-inline: auto;
    }

    .is-layout-constrained > .alignwide {
        max-width: min(100%, var(--sav-content-width));
    }

    /* A block that reaches the edge of the screen carries `alignfull`, again core's
       own name. It gives back the margin the band keeps, rather than measuring
       itself in `vw` — a viewport unit counts the scrollbar in and would push the
       page sideways by its width. */
    .is-layout-constrained > .alignfull {
        max-width: none;
        margin-inline: calc(-1 * var(--sav-page-margin));
    }

    /* Every text field of the site sits in a pill of its own that paints the edge, so the mark
       for the one being typed in belongs on that pill rather than on the field inside it — the
       fine line the design draws, in place of a ring standing off the edge. A radio and a
       checkbox are left out: they carry no pill, and where one is drawn as its own label the mark
       belongs to that label. `:where()`, so a component that needs another mark still wins. */
    :where(:has(> :is(input:not([type='radio'], [type='checkbox']), textarea):focus-visible)) {
        outline: 1px solid var(--sav-color-dunkelblau);
    }

    /* 60px → 452px, the distance the design draws below the error page; it meets the 60px → 92px
       a page keeps there anyway, and the larger of the two wins. */
    .error-page {
        margin-block-end: clamp(3.75rem, 3.75rem + (100vw - 24.375rem) * 0.29298, 28.25rem);
    }

    /* The bar Turbo draws across the top while it fetches. It belongs here because Turbo would
       otherwise inject it as a `<style>` element, which the content policy forbids. The two
       durations are the ones the script times the bar's removal against, and the layer is
       Turbo's own — the bar has to stand over everything, including a dialog. */
    .turbo-progress-bar {
        position: fixed;
        z-index: 2147483647;
        top: 0;
        left: 0;
        display: block;
        height: 3px;
        background-color: var(--sav-color-blau);
        transition:
            width 300ms ease-out,
            opacity 150ms 150ms ease-in;
    }

    /* Clipped rather than moved above the top edge, which overscrolling pulls into view, and
       rather than hidden, since it has to stay focusable. */
    .skip-link {
        position: absolute;
        z-index: 2;
        top: 0;
        left: var(--sav-page-margin);
        padding: 0.75rem 1.25rem;
        border-end-end-radius: var(--sav-radius);
        border-end-start-radius: var(--sav-radius);
        background-color: var(--sav-color-dunkelblau);
        color: var(--sav-color-weiss);
        font-size: var(--sav-text-xs-size);
        line-height: var(--sav-text-xs-line);
        text-decoration: none;

        &:not(:focus) {
            clip-path: inset(50%);
        }

        &:focus {
            outline: 2px solid var(--sav-color-weiss);
            outline-offset: -0.25rem;
        }
    }
}

/* The text styles from the Figma styleguide, one class each. They set only
   typography — colour and spacing stay the caller's decision — so any element
   can wear any style. */
@layer utilities {
    /* Text screen readers must read while the design does not show it — the label of an
       icon-only button. The carve-out lets focusable content inside it become visible
       again. Never `display: none`: that would take the text out of the accessibility
       tree, which is the point of the class. */
    .visually-hidden:where(:not(:focus-within, :active)) {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }

    .sav-headline-xl,
    .sav-headline-l,
    .sav-headline-m,
    .sav-headline-s {
        font-weight: var(--sav-font-weight-regular);
        text-wrap: balance;
    }

    .sav-headline-xl {
        font-size: var(--sav-text-headline-xl-size);
        line-height: var(--sav-text-headline-xl-line);
        letter-spacing: var(--sav-text-headline-xl-tracking);
    }

    .sav-headline-l {
        font-size: var(--sav-text-headline-l-size);
        line-height: var(--sav-text-headline-l-line);
        letter-spacing: var(--sav-text-headline-l-tracking);
    }

    .sav-headline-m {
        font-size: var(--sav-text-headline-m-size);
        line-height: var(--sav-text-headline-m-line);
        letter-spacing: var(--sav-text-headline-m-tracking);
    }

    .sav-headline-s {
        font-size: var(--sav-text-headline-s-size);
        line-height: var(--sav-text-headline-s-line);
        letter-spacing: var(--sav-text-headline-s-tracking);
    }

    /* Text L / Lead — Light */
    .sav-text-l {
        font-weight: var(--sav-font-weight-light);
        font-size: var(--sav-text-l-size);
        line-height: var(--sav-text-l-line);
        letter-spacing: normal;
    }

    /* Text M — Regular, with the Light cut the design also shows */
    .sav-text-m {
        font-weight: var(--sav-font-weight-regular);
        font-size: var(--sav-text-m-size);
        line-height: var(--sav-text-m-line);
        letter-spacing: var(--sav-text-m-tracking);
    }

    .sav-text-m-light {
        font-weight: var(--sav-font-weight-light);
        font-size: var(--sav-text-m-size);
        line-height: var(--sav-text-m-line);
        letter-spacing: var(--sav-text-m-tracking);
    }

    /* Text S — Light */
    .sav-text-s {
        font-weight: var(--sav-font-weight-light);
        font-size: var(--sav-text-s-size);
        line-height: var(--sav-text-s-line);
        letter-spacing: normal;
    }

    /* Text XS — Regular */
    .sav-text-xs {
        font-weight: var(--sav-font-weight-regular);
        font-size: var(--sav-text-xs-size);
        line-height: var(--sav-text-xs-line);
        letter-spacing: normal;
    }

    /* Label/Tag — Regular */
    .sav-label {
        font-weight: var(--sav-font-weight-regular);
        font-size: var(--sav-text-label-size);
        line-height: var(--sav-text-label-line);
        letter-spacing: var(--sav-text-label-tracking);
    }
}

/* The other band of the design: a page built of sections stands its blocks on the left edge of
   the content band instead of on a reading column centred in the window. `views/page.html.twig`
   is what names it, so the choice belongs to the template and not to a slug in here.

   Unlayered and with a second selector per rule, because the same three widths have to hold in
   the editor: `page-layout.js` marks the canvas root with the class, core holds the reading
   column there with two classes of its own, and a layered rule loses to core's whatever its
   specificity says. */

.page-layout {
    padding-inline: var(--sav-page-margin);
}

/* The start margin is what carries the block to the band's left edge; `max()` gives that up
   once the window is narrower than the band, where the page margin is the edge. */

.page-layout > * {
    max-width: min(100%, var(--sav-narrow-width));
    margin-inline: max(0px, calc(50% - var(--sav-content-width) / 2)) auto;
}

/* The same in the canvas, which `page-layout.js` marks the root of. Physical rather than
   logical, since core centres a block there with `margin-left` and a
   logical property of ours does not beat that one whatever the specificity — the canvas is
   left to right in all three languages. `!important` because core's own declaration carries
   it, and a canvas that centres what the page left-aligns is the wrong thing to show. */
.wp-block-post-content.page-layout.is-root-container > * {
    max-width: min(100%, var(--sav-narrow-width));
    margin-left: max(0px, calc(50% - var(--sav-content-width) / 2)) !important;
    margin-right: auto !important;
}

/* A picture, a chart, a video and a slider stand on the whole band there rather than on the
   measure of the text beside them — they carry no width of their own, since on every other
   page they take the reading column. */

.page-layout > .alignwide,
.page-layout > .image,
.page-layout > .datawrapper,
.page-layout > .embed,
.page-layout > .image-slider {
    max-width: min(100%, var(--sav-content-width));
    margin-inline: auto;
}

.wp-block-post-content.page-layout.is-root-container > .alignwide,
.wp-block-post-content.page-layout.is-root-container > .image,
.wp-block-post-content.page-layout.is-root-container > .datawrapper,
.wp-block-post-content.page-layout.is-root-container > .embed,
.wp-block-post-content.page-layout.is-root-container > .image-slider,
.wp-block-post-content.page-layout.is-root-container > .wp-block-block:has(> .alignwide) {
    max-width: min(100%, var(--sav-content-width));
    margin-left: auto !important;
    margin-right: auto !important;
}

.page-layout > .alignfull {
    max-width: none;
    margin-inline: calc(-1 * var(--sav-page-margin));
}

.wp-block-post-content.page-layout.is-root-container > .alignfull {
    max-width: none;
    margin-left: 0 !important;
    margin-right: 0 !important;
}
