/*
 * The one file that decides what the portal looks like.
 *
 * Every colour, font, spacing step, radius and border width used anywhere in this application
 * is declared here and nowhere else. Templates and components refer to these custom properties
 * and never write a literal value - DesignTokenDisciplineTest fails the build when one
 * reappears, because a promise like this one stops being true within two work packages unless
 * something checks it.
 *
 * THE PALETTE IS SNOGARD'S, AS OF 14.08.2026
 *
 * Wine red on light grey, from snogard.de. One accent, used for what can be acted on - links,
 * buttons, the focus ring, the chosen day - and nowhere decorative. A second colour would have
 * to earn its place by meaning something.
 *
 * EVERY RATIO BELOW IS COMPUTED, NOT ESTIMATED
 *
 * Chapter 21 asks for WCAG 2.1 AA: 4.5:1 for body text, 3:1 for the visual boundary of a
 * control (SC 1.4.11). The figures beside each token were calculated from the sRGB relative
 * luminance formula against the surface named. One value had to be corrected and it is marked
 * where it stands.
 */

:root {
    /* ---------------------------------------------------------------- colour */

    /* Surfaces. The page is grey and cards are white, so a card is a card without needing a
       heavy edge to say so. */
    /*
        The header's own ground, taken from snogard.de so the portal and the shop read as one
        company rather than as two products. Dark, and therefore the one surface in the portal
        whose text is light - hence the pair: never write one without the other.

        Contrast of --colour-header-text on --colour-header ......... 15.9:1
    */
    --colour-header: #1e1d1e;
    --colour-header-text: #ffffff;

    --colour-page: #f5f6f7;
    --colour-surface: #ffffff;
    --colour-surface-sunken: #f5f6f7;
    --colour-surface-raised: #ffffff;

    /* Text.
       --colour-text on card ............. 17.40:1
       --colour-text on page ............. 16.08:1
       --colour-text-muted on card ........ 6.90:1
       --colour-text-muted on page ........ 6.37:1 */
    --colour-text: #1a1a1a;
    --colour-text-muted: #5a5a5a;
    --colour-text-inverse: #ffffff;

    /* Borders, and the one correction in this palette.
       --colour-border on card ............ 1.30:1  decorative only: card edges, table rules,
                                                    dividers. Exempt from SC 1.4.11, which asks
                                                    3:1 only for what is *required to identify*
                                                    a control - a card is identified by the link
                                                    and text inside it, not by its outline.
       --colour-border-strong on card ..... 3.45:1  }  the boundary of a text field, a chip, a
       --colour-border-strong on page ..... 3.19:1  }  day cell, a secondary button: the only
       --colour-border-strong on accent ... 3.03:1  }  thing that says where the control is.

       The specification asked for #c9c9c9 here. Measured, that is 1.66:1 on white and 1.53:1 on
       the page - it fails SC 1.4.11 outright, and it fails it on the elements where the rule
       actually bites. #8a8a8a is the lightest grey that clears 3:1 on all three surfaces a
       control sits on in this portal. */
    --colour-border: #e2e2e2;
    --colour-border-strong: #8a8a8a;

    /* The accent: SNOGARD's wine red.
       --colour-accent on card ............ 9.77:1  (AA and AAA for body text)
       --colour-accent on page ............ 9.03:1
       --colour-accent on accent surface .. 8.58:1
       --colour-text-inverse on accent .... 9.77:1  white on the filled button
       --colour-text-inverse on hover .... 12.24:1 */
    --colour-accent: #8a0e0e;
    --colour-accent-hover: #6e0b0b;
    --colour-accent-contrast: #ffffff;

    /* A wash of the accent: icon fields, the fill of something chosen.
       1.14:1 against white, and deliberately so - it is a fill, and a fill is not information.
       Everything it carries is said again by a 2px accent border and a drawn tick. */
    --colour-accent-surface: #fbeded;

    /* Status. Each pair is text on its own surface, and each was measured as a pair.
       success 7.10:1   info 6.60:1   warning 6.54:1   danger 8.58:1 */
    --colour-success: #1e5c33;
    --colour-success-surface: #e8f5ec;
    --colour-info: #10559a;
    --colour-info-surface: #e8f1fa;
    --colour-warning: #7a4e00;
    --colour-warning-surface: #fdf3e0;
    --colour-danger: #8a0e0e;
    --colour-danger-surface: #fbeded;

    /* The capacity pools of chapter 6, told apart by colour in the dispatch calendar. Colour is
       never the only carrier - the calendar names the pool in its legend and the service on
       every card (WCAG 1.4.1). Each clears 4.5:1 on a white card.
       Measured: 9.77, 7.35, 6.54, 8.09, 7.72, 6.60. */
    --colour-pool-0: #8a0e0e;
    --colour-pool-1: #1e5c33;
    --colour-pool-2: #7a4e00;
    --colour-pool-3: #5b3a8e;
    --colour-pool-4: #14556e;
    --colour-pool-5: #10559a;

    /* The focus ring. Its own token rather than the accent: a focus indicator has to stay
       visible if the accent is ever replaced by something pale, and WCAG 2.4.11 makes it a
       requirement rather than a nicety. 9.77:1 on card, 9.03:1 on page. */
    --colour-focus: #8a0e0e;
    --focus-ring-width: 2px;
    --focus-ring-offset: 2px;

    /* -------------------------------------------------------------- typography */

    /* A system stack, so nothing is fetched from a third party - the CSP forbids it and a
       webfont is a render-blocking round trip the portal has no typographic need for. */
    --font-family-base: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-family-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

    /* The scale, in rem so that a browser's own font size setting still means something.
       A fixed pixel body size is the most common way a page becomes unreadable for somebody
       who enlarged their default.

       page-title 32px   section 24px   card-title 18px   body 16px
       small 14px        tiny 13px      price 20px */
    --font-size-page-title: 2rem;
    --font-size-section: 1.5rem;
    --font-size-card-title: 1.125rem;
    --font-size-price: 1.25rem;
    --font-size-body: 1rem;
    --font-size-small: 0.875rem;
    --font-size-tiny: 0.8125rem;

    /* The older names, kept pointing at the same scale so that the staff and administration
       pages did not all have to be rewritten for a booking-flow redesign. One scale, two sets
       of names, no second set of values. */
    --font-size-xs: var(--font-size-tiny);
    --font-size-sm: var(--font-size-small);
    --font-size-base: var(--font-size-body);
    --font-size-lg: var(--font-size-card-title);
    --font-size-xl: var(--font-size-section);
    --font-size-2xl: var(--font-size-page-title);

    --font-weight-regular: 400;
    --font-weight-medium: 600;
    --font-weight-semibold: 600;
    --font-weight-bold: 700;

    --line-height-page-title: 1.2;
    --line-height-section: 1.25;
    --line-height-card-title: 1.3;
    --line-height-body: 1.55;
    --line-height-small: 1.5;
    --line-height-tiny: 1.4;

    --line-height-tight: var(--line-height-section);
    --line-height-base: var(--line-height-body);

    /* ---------------------------------------------------------------- spacing */

    /* 4, 8, 12, 16, 24, 32, 48, 64 - one scale for every margin, padding and gap. */
    --space-2xs: 0.25rem;
    --space-xs: 0.5rem;
    --space-sm: 0.75rem;
    --space-md: 1rem;
    --space-lg: 1.5rem;
    --space-xl: 2rem;
    --space-2xl: 3rem;
    --space-3xl: 4rem;

    /* Off the scale, and each for one reason.
       3xs is the hairline inside a pill; card-padding is the 20px the service tile asks for,
       which sits between two steps because a tile wants more air than a form row and less than
       a page section. */
    --space-3xs: 0.125rem;
    --space-card-padding: 1.25rem;

    /* The badge's own padding: 2px above and below, 10px either side. Neither is on the scale,
       and inventing scale steps for one component would put two odd numbers into every other
       component's autocomplete. */
    --badge-padding-y: 0.125rem;
    --badge-padding-x: 0.625rem;

    /* ------------------------------------------------------------------ shape */

    --radius-card: 0.5rem;
    --radius-control: 0.375rem;
    --radius-pill: 999px;

    --radius-sm: var(--radius-control);
    --radius-md: var(--radius-card);
    --radius-lg: var(--radius-card);

    --border-width: 1px;
    --border-width-thick: 2px;

    /* ----------------------------------------------------------------- layout */

    /* 1120px, centred. */
    --layout-max-width: 70rem;

    /* The page gutter. Overridden at the two breakpoints below; 16px is the narrow default,
       because a phone is the case that has to work rather than the exception. */
    --layout-gutter: 1rem;

    /* The narrowest a service tile may get before the grid drops a column. 280px, and with the
       20px grid gap that produces exactly one column below 640, two to 1024 and three above -
       measured at the three widths the browser test drives, so the auto-fill grid gives the
       column counts the specification asks for without a media query to keep in step. */
    --layout-card-min: 17.5rem;
    --layout-slot-min: 9rem;

    /* The grid gap between tiles: 20px, off the scale for the same reason as the tile's own
       padding, and declared once because the tile must never carry a margin of its own. */
    --layout-grid-gap: 1.25rem;

    /* The reserved badge row at the foot of a service tile. The tile keeps a row of exactly
       this height whether or not there is a badge, so the price line above it sits on the same
       baseline in every tile - and the badge takes its own minimum height from the same token,
       so the two cannot drift apart. */
    --layout-tag-row: 1.5rem;

    /* The icon field on a service tile, and the drawing inside it. */
    --layout-icon-field: 2.5rem;
    --layout-icon: 1.25rem;
    --layout-icon-stroke: 1.5;

    /* The step indicator: circle, connector, and the bar the narrow variant shows instead. */
    --layout-step-circle: 1.75rem;
    --layout-step-line: 2px;
    --layout-progress-bar: 2px;

    /* One hour in the dispatch calendar. */
    --layout-calendar-row: 4rem;

    /* A form that is only a form - signing in, setting a password. Narrow on purpose: at full
       window width a label sits a hand's width from the field it names. */
    --layout-form-width: 26rem;

    /* The gap between a card and the heading that follows it, and above every heading that has
       something before it. 32px, everywhere - see the `* + h1` rule in portal.css. */
    --space-section: var(--space-xl);

    /* Interactive targets. 44px is WCAG 2.5.5 and the reason every button, input, chip and day
       cell below has a minimum height rather than only padding. */
    --target-min-size: 2.75rem;

    /* The insides of the controls that share that height. */
    --control-padding-x: 0.75rem;
    --button-padding-x: 1.5rem;
    --chip-padding-x: 1rem;

    /* ------------------------------------------------------------------ overlay */

    /*
        The ground a lightbox is painted on. Nearly opaque rather than a light wash: the thing
        underneath is a case page full of a customer's contact details, and it should be out of
        the way while somebody looks at a photograph, not readable behind it.
    */
    --colour-scrim: rgba(0, 0, 0, 0.86);

    /* The logo in the header. Height rather than width: the file is a wordmark, and a
       re-export with different proportions must not change how tall the header is. */
    --layout-logo: 2rem;

    /* One attachment tile. Four fit across the card on a laptop, two on a phone. */
    --layout-tile: 8rem;

    /* The preview square on an uploaded file's card, and the drop area's resting height.
       The drop area is one row tall: it is an aid beside the description, and a panel the
       height of the textarea above it reads as the task rather than the offer. */
    --layout-thumb: 3rem;
    --layout-dropzone: 4.5rem;

    /* ---------------------------------------------------------------- elevation */

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);

    /* How far a tile lifts under the pointer. */
    --lift-hover: -2px;

    /* ------------------------------------------------------------------ motion */

    --transition-fast: 150ms ease-out;

    /* ------------------------------------------------------------- breakpoints */

    /*
        Declared here although CSS cannot read a custom property inside `@media`. They are here
        because this file is where sizes are decided, and because DesignTokenDisciplineTest
        reads them: a media query in another stylesheet may only use a width that appears as one
        of these values. That turns the unavoidable exception - a breakpoint literal outside the
        token file - back into something checked.
    */
    --breakpoint-sm: 640px;
    --breakpoint-md: 768px;
    --breakpoint-lg: 1024px;
    --breakpoint-xl: 1280px;
}

/*
 * Narrow: the page title and section headings come down a step, and the gutter is already at
 * its 16px default. Nothing else changes size - body text that shrinks on a phone is body text
 * nobody reads.
 */
@media (max-width: 767px) {
    :root {
        --font-size-page-title: 1.625rem;
        --font-size-section: 1.25rem;
    }
}

/* 24px of gutter from 768, 32px from 1280. */
@media (min-width: 768px) {
    :root {
        --layout-gutter: 1.5rem;
    }
}

@media (min-width: 1280px) {
    :root {
        --layout-gutter: 2rem;
    }
}

/*
 * THERE IS NO DARK MODE, AND THAT IS THE DECISION
 *
 * A `prefers-color-scheme: dark` block stood here until 14.08.2026. It was written while Q-35
 * was open, when "follow whatever the reader already told their operating system" was the most
 * honest answer available. Q-35 is now answered, and the answer is snogard.de: measured, its
 * 593 KB of stylesheet contain not one `prefers-color-scheme` and not one `color-scheme`
 * declaration, and its markup carries no theme switch. The shop is light, always.
 *
 * Keeping the block would have meant a customer with a dark desktop crossing from a light shop
 * into a dark portal in the middle of a booking - the one seam the whole exercise exists to
 * smooth over. It would also have doubled the surface somebody has to look at before signing
 * the appearance off, for a variant nobody had ever looked at once.
 *
 * WHY NOTHING REPLACES IT - NOT EVEN `color-scheme: only light`
 *
 * That declaration is the documented way to tell a browser "do not auto-darken me", and setting
 * it here would put the portal in a different bucket from the shop, which sets nothing. Chrome's
 * automatic darkening on Android applies to pages that have not opted out; opting out on one
 * side of the seam and not the other rebuilds the break in the other direction. Declaring
 * nothing is what keeps the two identical.
 *
 * If SNOGARD ever wants the darkening switched off in earnest, it belongs on the shop and the
 * portal in the same change. And whether the staff area should have a dark variant of its own is
 * a live question rather than a settled no - see Q-53.
 */

/*
 * Somebody who has asked their system to reduce motion has asked for a reason - vestibular
 * disorders are the usual one - and WCAG 2.3.3 treats it as a requirement rather than a
 * preference. Zeroing the duration here means no component has to remember; the lift is zeroed
 * too, because a transform that arrives instantly is still movement.
 */
@media (prefers-reduced-motion: reduce) {
    :root {
        --transition-fast: 0ms;
        --lift-hover: 0px;
    }
}
