@charset "UTF-8";

@layer reset;

@import url('./reset.css') layer(reset);

/*
//
// Sectioning and Structure
//
*/

html {
    /*
    The online manuals need to adapt the way they look depending on the current
    brand. Key differences between each brand are encoded using custom
    properties, while more unique brand styling happens in the respective CSS
    files. The following parameters should be adjusted exclusivly by using
    custom properties:

    * Colors
    * Fonts, font sizes, and line height
    * Icons
    * Spacing between and within elements

    Everything else diverging from the default styling should be done in the
    respective brand style sheets, using the selectors established by the
    default style sheet. The brand styling is loaded after the default styling,
    so overwriting stuff shouldn't be to painful.
    */

    /*
    Colors
    */
    --color-brand: var(--theme-color-brand, #242526);
    --color-black: var(--theme-color-black, #242526);
    --color-gray1: var(--theme-color-gray1, #c0c0c0);
    --color-gray2: var(--theme-color-gray2, #dcdcdc);
    --color-white: var(--theme-color-white, #f5f5f5);

    /*
    The following custom properties map various color values to semantic color
    names. These semantic color names are used throughout the rest of the code
    to define the color of elements. Changing their values is fine and intended,
    changing their names will break the styling.
    */
    --color-accent-fill: var(--theme-color-accent-fill, var(--color-gray1));
    --color-accent-text: var(--theme-color-accent-text, var(--color-black));
    --color-page-fill: var(--color-white);
    --color-page-text: var(--color-black);
    --color-ui-fill: var(--theme-color-ui-fill, var(--color-brand));
    --color-ui-text: var(--theme-color-ui-text, var(--color-white));

    /*
    Fonts
    */
    --font-family: var(--theme-font-family, system-ui, sans-serif);
    --font-size-sm:  var(--theme-font-size-sm,  round(1rem * pow(1.25, -1), 2px));
    --font-size-md:  var(--theme-font-size-md,  round(1rem * pow(1.25,  0), 2px));
    --font-size-lg:  var(--theme-font-size-lg,  round(1rem * pow(1.25,  1), 2px));
    --font-size-xl:  var(--theme-font-size-xl,  round(1rem * pow(1.25,  2), 2px));
    --font-size-2xl: var(--theme-font-size-2xl, round(1rem * pow(1.25,  3), 2px));
    --font-size-3xl: var(--theme-font-size-3xl, round(1rem * pow(1.25,  4), 2px));
    --font-size-4xl: var(--theme-font-size-4xl, round(1rem * pow(1.25,  5), 2px));
    --font-size-5xl: var(--theme-font-size-5xl, round(1rem * pow(1.25,  6), 2px));
    --line-height: var(--theme-line-height, 1.4);

    /*
    Icons
    */
    --icon-hint: var(--theme-icon-hint, url('./img/icons-24x24.svg#hint'));
    --icon-locales: var(--theme-icon-locales, url('./img/icons-16x16.svg#locale'));
    --icon-note: var(--theme-icon-note, url('./img/icons-24x24.svg#note'));
    --icon-safety: var(--theme-icon-safety, url('./img/icons-24x24.svg#safety'));
    --icon-tags: var(--theme-icon-tag, url('./img/icons-16x16.svg#tag'));
    --icon-warning: var(--theme-icon-warning, url(./img/icons-24x24.svg#warning));

    /*
    Spacing
    */
    --space-xs:  var(--theme-space-xs,  1ex);
    --space-sm:  var(--theme-space-sm,  1rem);
    --space-md:  var(--theme-space-md,  1rlh);
    --space-lg:  var(--theme-space-lg,  2rlh);
    --space-xl:  var(--theme-space-xl,  3rlh);
    --space-2xl: var(--theme-space-2xl, 4rlh);
    --space-3xl: var(--theme-space-3xl, 6rlh);
    --space-4xl: var(--theme-space-4xl, 8rlh);

    background: var(--color-page-fill);
    color: var(--color-page-text);
    container-type: inline-size;
    font-family: var(--font-family);
    font-size: var(--font-size-md);
    line-height: var(--line-height);

    @supports (hyphenate-limit-chars: 10 4) {
        hyphenate-limit-chars: 10 4;
        hyphens: auto;
    }
}

body {
    --body-space: var(--space-md);
    --body-width: 60rem;
    --body-margin: max(var(--body-space), 50cqw - var(--body-width) / 2);

    margin: var(--space-md) var(--body-margin);
}

main,
main > * + * {
    margin-block-start: var(--main-space, var(--space-xl));
}

/*
//
// Headings
//
*/

h1,
h2,
h3,
h4,
h5,
h6 {
    hyphens: manual;
    text-wrap: balance;
}

h1,
h2 {
    line-height: round(1em + (var(--line-height) * 1rem - 1rem), 2px);
}

h1 {
    font-size: var(--font-size-4xl);
}

h2 {
    font-size: var(--font-size-xl);
    font-weight: 600;
}

/*
//
// Media
//
*/

img:where(picture > img) {
    block-size: 100%;
    inline-size: 100%;
    object-fit: cover;
}

img:where(picture:is(.intrinsic, :has(.intrinsic)) > img) {
    block-size: auto;
    inline-size: auto;
    margin: inherit;
    object-fit: unset;
}

img:where(picture.windowbox > img) {
    object-fit: scale-down;
}

/*
Restrict the aspect ratio of 'picture' elements to prevent the layout from
breaking if unexpected image sizes are used. This behaviour can be disabled by
setting the modifier class '.intrinsic' on the 'picture' element.

@modifier .intrinsic - Use the image's intrinsic aspect ratio.
@modifier .windowbox - Don't crop the image, but scale it down to fit.

@param <ratio> --picture-aspect-ratio - The desired aspect ratio.
*/
picture {
    aspect-ratio: var(--picture-aspect-ratio, 1);
    display: block;
    max-inline-size: fit-content;
    overflow: clip;
}

picture:where(.intrinsic, :has(.intrinsic)) {
    display: contents;
}

/*
//
// Tables
//
*/

:is(th, td) {
    border-style: solid;
    border-width: thin 0;
    padding: 1ex 1ch;
    text-align: inherit;
    vertical-align: baseline;
    white-space: nowrap;
}

:is(th, td):where(thead > tr:first-of-type *) {
    border-block-start-width: 0;
    padding-block-start: 1rlh;
}

:is(th, td):where(:first-child) {
    padding-inline-start: 0;
}

:is(th, td):where(:last-child) {
    padding-inline-end: 0;
}

:is(th, td):where([colspan]) {
    padding-block-start: 2ex;
}

:is(th, td):where(.fill) {
    inline-size: 100%;
    white-space: unset;
}

:is(th, td):where(.numerical) {
    text-align: right;
}

/*
//
// Phrasing
//
*/

a:where(:not([class])) {
    text-decoration: underline solid color-mix(in hsl, currentColor, #0000 45%);
    text-underline-offset: 0.125em;
}

/*
//
// Misc.
//
*/

anchor-block:where(:defined) {
    cursor: pointer;
    display: block;
}

/*
//
// Composition
//
*/

/*
/!\ Important: Composition related classes shouldn't be combined on the same
    element. While setting multiple composition related classes might work,
    it most likely results in a visual mess. Nesting various compositions
    inside each other is fine and the intended way of building complex layouts.
*/

/*
Grid
A group of arbitary elements; displayed in a grid with a minimum and maximum
amount of columns, where each column has a minimum width. Refer to the linked
ressources for a detailed explanation.

(i) https://css-tricks.com/an-auto-filling-css-grid-with-max-columns/
(i) https://stackoverflow.com/a/69154193
(i) https://codepen.io/btous/pen/QWvGNGm

1. Force the element to use the available space if its part of a flex layout.

@param <integer> --grid-column-max-count - Maximum number of columns.
@param <integer> --grid-column-min-count - Minimum number of columns.
@param <length>  --grid-column-width     - Ideal width of each column.
@param <length>  --grid-space            - Space between grid items.

@modifier .grid--fill-width - Stretch the items to fill the available space.
*/
.grid {
    --_gridColMax: var(--grid-column-max-count, 4);
    --_gridColMin: var(--grid-column-min-count, 1);
    --_gridColWidth: var(--grid-column-width, 25ch);
    --_gridSpace: var(--grid-space, var(--space-sm, 1rlh));

    --_gridGapMax: calc(var(--_gridSpace) * (var(--_gridColMax) - 1));
    --_gridGapMin: calc(var(--_gridSpace) * (var(--_gridColMin) - 1));
    --_gridMax: calc(100% / var(--_gridColMax) - var(--_gridGapMax) / var(--_gridColMax));
    --_gridMin: calc(100% / var(--_gridColMin) - var(--_gridGapMin) / var(--_gridColMin));

    align-self: stretch; /* 1 */
    display: grid;
    gap: var(--_gridSpace);
    grid-template-columns: repeat(
        auto-fit, minmax(
            0,
            min(var(--_gridMin), max(var(--_gridColWidth), var(--_gridMax)))
        )
    );
}

.grid--fill-width {
    grid-template-columns: repeat(
        auto-fit, minmax(
            min(var(--_gridMin), max(var(--_gridColWidth), var(--_gridMax))),
            1fr
        )
    );
}

/*
Media Column
A group of a piece of media (an image or video) and an associated collection of
textual content; displayed in a single column starting with the media,
regardless of the space available.

1. Prevent alignment issues by forcing the '.media-column' element to the same
   height as its parent, if the '.media-column' element is an only child.
2. Prevent alignment issues by forcing all non-media related elements to take
   up all remaining space. This takes only effect if the '.media-column'
   element is part of a flex or grid layout.

@param <self-position> --media-align - Alignment of items along the inline axis.
@param <length>        --media-space - Amount of space between items.

@modifier .media-column--reversed - Reverse the order of media and text.
*/
.media-column {
    --_mediaAlign: var(--media-align, start);
    --_mediaSpace: var(--media-space, var(--space-sm, 1rem));

    align-items: var(--_mediaAlign);
    display: flex;
    flex-direction: column-reverse;
    gap: var(--_mediaSpace);

    &:where(:only-child) {
        min-block-size: 100%; /* 1 */
    }

    & > :where(:not(img, picture, video, :has(img, picture, video))) {
        flex-grow: 1; /* 2 */
    }
}

.media-column--reversed {
    flex-direction: column;
}

/*
Media Row
A group of a piece of media (an image or video) and an associated collection of
textual content; displayed in a single row starting with the text, if there is
enough space available along the inline axis.

@param <self-position> --media-align
@param <length>        --media-space
@param <length>        --media-width

@modifier .media-row--reversed
*/
.media-row {
    --_mediaAlign: var(--media-align, center);
    --_mediaSpace: var(--media-space, 1em);
    --_mediaWidth: var(--media-width, 30ch);

    align-items: var(--_mediaAlign);
    display: flex;
    flex-flow: row wrap-reverse;
    gap: var(--_mediaSpace);
}

.media-row > * {
    flex: 1 1 calc((2 * var(--_mediaWidth) - 100%) * 999);
}

.media-row--reversed {
    flex-direction: row-reverse;
}

/*
Prose
A group of text-containing elements; displayed in a stack with a certain amount
of space between them.

@param <integer> --prose-font-size  - Font size given as a step on a scale.
@param <length>  --prose-item-space - Space between prose items.

@modifier .prose--onesize - Keep headings the same size as regular text.
*/
.prose {
    max-inline-size: 80ch;

    & > * + * {
        margin-block-start: var(--prose-item-space, var(--space-sm, 1rem));
    }

    & :where(h1, h2, h3, h4, h5, h6, strong, b) {
        font-weight: 600;
    }

    & :where(h1, h2, h3, h4, h5, h6) {
        --prose-item-space: var(--space-md, 2rem);

        font-size: round(1em * pow(1.25, var(--prose-font-size, 0)), 2px);
        line-height: round(1em + 0.5rem, 2px);
        text-wrap: balance;
    }

    & :where(h1) {
        --prose-font-size: 3;
    }

    & :where(h2) {
        --prose-font-size: 2;
    }

    & :where(h3) {
        --prose-font-size: 1;
    }

    & :where(ol, ul) {
        list-style: revert;
        padding-inline-start: 4ch;
    }

    & :where(a) {
        text-decoration: underline solid color-mix(in srgb, currentColor, #0000);
        text-underline-offset: 0.125em;
    }
}

.prose--onesize > :where(h1, h2, h3) {
    --prose-font-size: 0;
}

/*
Stack
A group of arbitary elements; displayed in a stack with a certain amount of
space between them.

1. Prevent alignment issues by forcing the '.stack' element to the same height
   as its parent element, if the '.stack' element is an only child.
2. Prevent the value of the '--stack-item-space' custom property to be
   inherited from a parent element belonging to the '.stack' class; ensuring a
   consistent and predictable spacing within any given '.stack' element.
3. When splitting the stack, an auto margin is added to the bottom of the
   element preceding the one belonging to the '.stack__split' class. This
   allows to keep the vertical spacing consistent within the '.stack' element.

/!\ The value of the '--stack-item-space' custom property should always be set
    on the child elements of the '.stack' element, to prevent unexpected
    behavior when nesting '.stack' elements within each other.

@param <self-position> --stack-item-align - Item alignment along the inline axis.
@param <length>        --stack-item-space - Space between stack items.

@modifier .stack--recursive - Force inheritance of stack item's space.
*/
.stack {
    align-items: start;
    display: flex;
    flex-direction: column;
    justify-content: start;

    &:where(:only-child) {
        min-block-size: 100%; /* 1 */
    }

    &:where(.stack:not(.stack--recursive) > .stack) > * {
        --stack-item-space: initial; /* 2 */
    }

    & > * + * {
        margin-block-start: var(--stack-item-space, var(--space-sm, 1rem));
    }

    & > :where(:has(+ .stack__split)) {
        margin-block-end: auto; /* 3 */
    }
}

/*
//
// Utility
//
*/

/*
Hide elements visually, but keep them accessible for assistive technologies.

(i) https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html
(i) https://www.scottohara.me/blog/2023/03/21/visually-hidden-hack.html
(i) https://www.tpgi.com/the-anatomy-of-visually-hidden/
*/
.visually-hidden:not(:focus):not(:active) {
    clip-path: inset(50%);
    height: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
    width: 1px;
}

/*
//
// Blocks
//
*/

.brand-logo {
    display: block;
    max-inline-size: 12rem;
}

/*
Figure Group
A collection of thematically related 'figure' elements; each one containing up
to two (2) images. This limitation is a direct translation from the printed
manuals, which don't use more than two images in any given context.

All images in a 'figure' element need to have the same aspect ratio. The
preferred aspect ratio can be set by using one of the modifier classes listed
below. The default aspect ratio is 1:1.

/!\ The exact aspect ratio used can differ depending on the viewport width. The
    markup should provide several images to best accomodate that shift.

1. Images nested inside a '.figure-group' element should always fill the entire
   available space.
2. Let items containing a single landscape image, or multiple non-landscape
   images, stretch multiple columns of the '.figure-group' element's layout
   grid. This ensures that they are displayed reasonably well on larger screens.

@modifier .figure-group__item--landscape - Set an item to use a horizontal ratio.
@modifier .figure-group__item--portrait  - Set an item to use a vertical ratio.
*/
.figure-group {
    display: grid;
    gap: 1em;
    grid-template-columns: repeat(
        var(--figure-group-column-count, 1), minmax(0, 1fr)
    );

    @media (width >= 40em) {
        --figure-group-column-count: 2;
        --figure-group-item-column-end: span 2;
        --figure-group-item-landscape: 2 / 1;
        --figure-group-item-portrait: 1 / 2;
    }

    @media (width >= 60em) {
        --figure-group-column-count: 3;
    }
}

.figure-group__item,
.figure-group__item :where(picture) {
    inline-size: unset; /* 1 */
    max-inline-size: unset; /* 1 */
}

.figure-group__item--landscape,
.figure-group__item:has(picture:nth-child(2)) {
    grid-column-end: var(--figure-group-item-column-end, auto); /* 2 */
}

.figure-group__item--landscape {
    --picture-aspect-ratio: var(--figure-group-item-landscape, 5 / 3);
}

.figure-group__item--portrait {
    --picture-aspect-ratio: var(--figure-group-item-portrait, 3 / 5);
}

.figure-group__pictures {
    display: grid;
    gap: 1em;

    @media (width >= 40em) {
        grid-auto-flow: column;
        grid-auto-columns: minmax(0, 1fr);
    }
}

/*
Glossary
A group of various terms and their respective definitions.
*/
.glossary__list > * {
    --stack-item-space: 1ex;
    --prose-item-space: 0;
}

.glossary__list dt {
    float: left;
    font-weight: 700;
    margin-inline-end: 0.25ch;
}

.image-group {
    --grid-column-max-count: 3;
    --stack-item-space: var(--space-xl);
}

.image-group:has(picture:only-child) {
    --grid-column-width: 50ch;
}

/*
Labelled List
A container enclosing a list element and it's associated label; including an
icon to visually hint to the type of list. The enclosed list element is
displayed in a compact style.

@param <url> --labelled-list-icon - An icon representing the list's type.
*/
.labelled-list {
    align-items: baseline;
    display: grid;
    gap: 0.25ex 0.25ch;
}

.labelled-list > * {
    grid-column: 2;
}

.labelled-list::before {
    aspect-ratio: 1;
    block-size: 1em;
    box-shadow: 100vmax 0 inset;
    content: '';
    display: block;
    grid-column: 1;
    mask: var(--labelled-list-icon, url('./img/icons-16x16.svg#no-symbol'));
    transform: translateY(0.125em);
}

.labelled-list :where(ol, ul) {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25ch;
}

.labelled-list :where(li:has(+ li))::after {
    content: ',';
}

.labelled-list :where(strong) {
    font-weight: 700;
}

.labelled-list--locales {
    --labelled-list-icon: var(--icon-locales);
}

.labelled-list--tags {
    --labelled-list-icon: var(--icon-tags);
}

/*
Legend
A group of explanations for more or less cryptic symbols. The available symbols
correspond to the various types of the '.message' block.
*/
.legend__entry {
    align-items: start;
    border: 0.125rem solid;
    border-radius: 0.1875rem;
    display: grid;
    gap: 1ch;
    inline-size: fit-content;
    padding: 1ch;
}

.legend__entry > * {
    grid-column: 2;
}

.legend__icon {
    grid-column: 1;
}

.legend__icon::before {
    aspect-ratio: 1;
    block-size: 1.5rem;
    box-shadow: 100vmax 0 inset;
    content: '';
    display: block;
    mask: var(--legend-icon, url('./img/icons-24x24.svg#no-symbol'));
    transform: translateY(0.125rem);
}

.legend__icon--hint {
    --legend-icon: var(--icon-hint);
}

.legend__icon--note {
    --legend-icon: var(--icon-note);
}

.legend__icon--safety {
    --legend-icon: var(--icon-safety);
}

.legend__icon--warning {
    --legend-icon: var(--icon-warning);
}

/*
Message
Visually highlighted pieces of text, usually used to draw attention to important
information. Comes in a variety of styles; each one indicating the nature of the
highlighted piece of text.

@modifier .message--hint    - Set icon for hints.
@modifier .message--note    - Set icon for notes.
@modifier .message--safety  - Set icon for safety warnings.
@modifier .message--warning - Set icon for generic warnings.
*/
.message {
    align-items: start;
    border: 0.125rem solid;
    border-radius: 0.1875rem;
    display: grid;
    gap: 1ch;
    inline-size: fit-content;
    padding: 1ch;
}

.message > * {
    grid-column: 2;
}

.message::before {
    aspect-ratio: 1;
    block-size: 1.5rem;
    box-shadow: 100vmax 0 inset;
    content: '';
    display: block;
    grid-column: 1;
    mask: var(--message-icon, url('./img/icons-24x24.svg#no-symbol'));
    transform: translateY(0.125rem);
}

.message--hint {
    --message-icon: var(--icon-hint);
}

.message--note {
    --message-icon: var(--icon-note);
}

.message--safety {
    --message-icon: var(--icon-safety);
}

.message--warning {
    --message-icon: var(--icon-warning);
}

/*
Page Collection
A group of hyperlinks pointing to somewhat related pages.
*/
.page-collection {
    --grid-column-max-count: 5;
    --grid-column-min-count: 2;
}

.page-collection__item :where(h1, h2, h3, h4, h5, h6) {
    font-weight: 700;
}

.page-collection__item :where(picture, img) {
    max-inline-size: none;
    inline-size: 100%;
}

/*
Table Container
Table elements might be wider than the viewport. To prevent the whole page from
scrolling horizontally, every 'table' element is wrapped in an element which
contains eventual overflowing content.
*/
.table-container {
    overflow-x: auto;
}

/*
Table of Contents
A container enclosing a list element and it's associated label; containing
various hyperlinks to specific sections and elements found on the page.
*/
.toc-list {
    --stack-item-space: var(--space-xl);
}

.toc-list ol {
    margin-block-start: calc(var(--space-md) - 0.5ex);
}

.toc-list ol ol {
    margin-block-start: 0;
    padding-inline-start: 1lh;
}

.toc-list a {
    display: block;
    inline-size: fit-content;
    padding-block: 0.5ex;
}


.tool-list,
.content-list {
    --grid-column-width: 10em;
    --grid-column-min-count: 2;
    --grid-column-max-count: 5;
}

.tool-list__item,
.content-list__item {
    align-items: center;
    text-align: center;
    text-wrap: balance;
}
