/* =============================================================================
   eID.gov.rs - shared page components

   The design-system pieces that are not chrome: every page uses them, none of
   them belongs to _Layout.cshtml. Two kinds live here.

   1. Things the plain-CSS export carries, configured for this design through
      the hooks the component exposes (--eds-*). Class names are the library's.

   2. Things the export cannot carry, because the eds-lib component is a wrapper
      around Angular Material and its CSS reaches into Material's DOM
      (`.mat-radio-button`, `:host ::ng-deep`). A static page has no Material,
      so the rules are written here from the design tokens - but under the
      library's own class names, taken from the component templates, so the
      markup is what Angular renders and the port is a swap rather than a
      rewrite. Each one says which template it came from.

   Everything that departs from a library rule is marked DEVIATION.

   Contents
     1. Page layout
     2. Surface card
     3. Button
     4. Form field
     5. Radio
     6. Checkbox
     7. Upload
     8. Note
     9. Validation summary
    10. Carousel
    11. Auth page shell
    12. Password form
    13. Confirmation dialog
    14. Loader
    15. Loader on a button
    16. Guide steps
    17. Native select
    18. Registration layout
   ========================================================================== */

/* -----------------------------------------------------------------------------
   1. Page layout

   The centred content column. 880px is the width of the content frame in every
   desktop frame of the design; the gutter is what the mobile frames leave at
   each side.
   -------------------------------------------------------------------------- */

.section {
    width: 100%;
    max-width: calc(var(--page-content) + 2 * var(--page-gutter));
    margin-inline: auto;
    padding-inline: var(--page-gutter);
}

.section__title {
    margin: 0;
    color: var(--eds-color-primary);
}

.section__text {
    margin: 0;
    color: var(--eds-neutral-20);
    opacity: 0.8;
}

/* -----------------------------------------------------------------------------
   2. Surface card

   The white panel with the Forma elevation: the registration card on Početna
   and the contact form on Pomoć are the same surface with different content.
   -------------------------------------------------------------------------- */

.card {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 0;
    overflow: hidden;
    background: var(--eds-color-surface-container-lowest);
    border-radius: var(--eds-radius-md);
    box-shadow: var(--eid-shadow-forma);
}

.card__header {
    position: relative;
    width: 100%;
    padding: var(--eds-space-6) var(--eds-space-8) var(--eds-space-5);
    text-align: center;
}

    /* The divider under the card header is a horizontal gradient rule */
    .card__header::after {
        content: "";
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        height: 1px;
        background: linear-gradient( to right, rgba(154, 176, 193, 0.3), #6f7e8b 49%, rgba(73, 83, 91, 0.3) );
    }

.card__title {
    margin: 0;
    color: var(--eds-color-primary);
}

.card__content {
    display: flex;
    flex-direction: column;
    gap: var(--eds-space-4);
    width: 100%;
    padding: 23px;
}

.card__label {
    margin: 0;
    color: var(--eds-color-primary);
}

/* The button stack. Without this the three buttons are laid out by the block
   flow inside card__content and touch each other; the frame draws the same
   16 between them as card__content uses between its own rows. */
.card__actions {
    display: flex;
    flex-direction: column;
    gap: var(--eds-space-4);
}

/* The card's tinted foot - Figma's `_Footer` slot. It sits on the light surface
   rather than on the card's white, and it is the only corner the card's own
   `overflow: hidden` does not already round.

   Both auth frames draw it 64px tall. On Пријава that is what 24 of padding
   around one line of body/small comes to; on Постављање нове лозинке the slot
   is empty and the height is all that is left of it, so the min-height states
   it once and serves both. */
.card__footer {
    width: 100%;
    min-height: 64px;
    padding: var(--eds-space-6);
    background: var(--eds-color-surface);
    text-align: center;
}

/* -----------------------------------------------------------------------------
   3. Button

   Not the exported eds-lib button. That component's stylesheet opens with a
   bare `button { border-radius: 4px !important; overflow: hidden; ... }`, which
   in Angular is scoped to the component and here would repaint every button on
   the page - the header toggle, every expansion-panel header. So the four
   variants this design uses are written from the tokens instead, and the
   component's own transition is kept so hover reads the same.

   All five of M3's: filled, tonal, outlined, elevated and text. Each is the
   container and the label colour and nothing else - geometry, gap and
   transition are `.button` itself.
   -------------------------------------------------------------------------- */

.button {
    display: flex;
    align-items: center;
    justify-content: center;
    /* The component's button takes an optional leading icon, 8 from its label -
     Login instances two of them. A button with only a label is unaffected. */
    gap: var(--eds-space-2);
    width: 100%;
    min-height: 48px;
    padding: 10px var(--eds-space-4);
    border: 0;
    border-radius: var(--eds-radius-sm);
    cursor: pointer;
    text-align: center;
    text-decoration: none;
    transition: var(--eid-button-transition);
}

.button--filled {
    background: var(--eds-color-primary);
    color: var(--eds-color-on-primary);
}

    .button--filled:hover {
        background: var(--eid-color-primary-hover);
    }

.button--tonal {
    background: var(--eds-color-primary-container);
    color: var(--eds-color-on-primary-container);
}

    .button--tonal:hover {
        filter: brightness(0.95);
    }

/* Outlined - the secondary action on Мој ИД Отвореног Балкана. M3 draws it as
   no container at all, a hairline in outline-variant and the label in
   on-surface-variant; hover is the label's own state layer at 8%, which is the
   opacity M3 gives a hover layer. */
.button--outlined {
    border: 1px solid var(--eds-color-outline-variant);
    background: transparent;
    color: var(--eds-color-on-surface-variant);
}

    .button--outlined:hover {
        background: color-mix( in srgb, var(--eds-color-on-surface-variant) 8%, transparent );
    }

/* Elevated - the two portal buttons in the foot of the same card. The container
   is surfaceContainerLow lifted on elevation 1, and the label is the scheme's
   surface tint.

   Figma sys/light/surface-tint. eds/tokens.css does not carry it: the export's
   light scheme stops at the primary/secondary/surface roles, and the tint is
   the one M3 role none of them stands in for. It is declared on the variant
   that needs it rather than in shared.css, the way this project names any
   value only one place draws; it belongs in the export's section 9 the moment a
   second component reaches for it. */
.button--elevated {
    --eid-color-surface-tint: #36618e;
    background: var(--eds-color-surface-container-low);
    box-shadow: var(--eds-elevation-1);
    color: var(--eid-color-surface-tint);
}

    .button--elevated:hover {
        filter: brightness(0.97);
    }

/* Text - the lowest emphasis of the five, and the last one a frame reached for:
   Прочитајте више under the Регистрација stepper (Figma 1:59346). No container
   at all until it is hovered, and the label in the scheme's surface tint, which
   is the colour the elevated variant above already names and for the same
   reason - the export's light scheme carries no role for it. */
.button--text {
    --eid-color-surface-tint: #36618e;
    background: transparent;
    color: var(--eid-color-surface-tint);
}

    .button--text:hover {
        background: color-mix( in srgb, var(--eid-color-surface-tint) 8%, transparent );
    }

/* The leading icon keeps its own size while the label wraps beside it. */
.button__icon {
    flex: none;
}

/* Disabled, which is the state Подаци о налогу opens its Сачувајте измене
   button in. M3 draws it the same way whatever the variant was - the container
   goes to on-surface at 10% and the label to on-surface at 38% - so it is one
   rule after the two variants rather than a disabled twin of each.

   The 0.1 and the 0.38 are M3's state-layer and disabled-content opacities,
   which the export carries as `--state-layers/on-surface/opacity-10` in the
   frames and as nothing at all in eds/tokens.css - the library emits no opacity
   tokens. They are written as `color-mix` off the surface token rather than as
   two more hexes, so the pair still tracks the scheme. */
.button:disabled {
    /* M3 drops the outlined variant's hairline and its elevation along with the
     container colour, so a disabled button reads the same whichever variant it
     was - which is what both Мој ИД Отвореног Балкана frames draw. */
    border-color: transparent;
    background: color-mix(in srgb, var(--eds-color-on-surface) 10%, transparent);
    box-shadow: none;
    color: color-mix(in srgb, var(--eds-color-on-surface) 38%, transparent);
    cursor: default;
}

    /* The label takes the 38% through `color`; a leading icon is a bitmap and has
   to be faded rather than recoloured. */
    .button:disabled .button__icon {
        opacity: 0.38;
    }

/* -----------------------------------------------------------------------------
   4. Form field

   /eds/lib/form-field.css and /eds/lib/native-input.css carry the component;
   what follows is this design's configuration of it plus two departures.
   -------------------------------------------------------------------------- */

.eds-form-field {
    /* The frames draw a 56px control; the component's default is 48. */
    --eds-field-height: 56px;
    /* schemes/outline in the frames. The component defaults to outlineVariant,
     which is the lighter of the two greys. */
    --eds-ff-border: var(--eds-color-outline);
    --eds-ff-border-focus: var(--eds-color-primary);
    --eds-input-font-size: var(--eds-font-size-body-medium);
}

/* The label is body/small, and it keeps its own line box so a field that wraps
   its label does not shift the control. */
.eds-form-field__label {
    line-height: var(--eds-line-height-body-small);
    letter-spacing: var(--eds-tracking-body-small);
}

/* The required marker is the component's own: a 6px filled dot, drawn as an
   inline <svg><circle fill="currentColor">, so the colour still comes from
   `--eds-ff-error` on the span. The frames draw a red asterisk there instead,
   but that is the design system's decision to make, not the page's - and it
   makes the marker read the same on every page of the portal. Nothing to style
   here; form-field.css already sizes and colours it.

   DEVIATION - `--focused` is a class the Angular component sets from a CDK
   FocusMonitor. A static page has no such observer, so the same treatment is
   driven off the control's own focus. `:has()` is already used by the exported
   component (`__control:has(textarea)`), so it is not a new requirement. */
.eds-form-field__control:has(:focus-visible) {
    border-color: var(--eds-ff-border-focus);
    box-shadow: inset 0 0 0 2px var(--eds-ff-border-focus);
}

/* Three names for one state, all three styled, because three layers name it:

     .eds-form-field--invalid    the library's, already handled by form-field.css
     .eds-form-field--error      this project's, per section 12.4 of claude.md
     .input-validation-error     ASP.NET's, on the control itself

   The last one is why the port needs no CSS change: server-side validation puts
   its class on the <input> and `:has()` carries it up to the control box.

   Error keeps beating focus, exactly as it does in the component, where the
   `--invalid` rule is written after the `--focused` one. */
.eds-form-field--error .eds-form-field__control,
.eds-form-field--error .eds-form-field__control:has(:focus-visible),
.eds-form-field__control:has(.input-validation-error) {
    border-color: var(--eds-ff-error);
    box-shadow: inset 0 0 0 2px var(--eds-ff-error);
}

.eds-form-field--error .eds-form-field__label,
.eds-form-field--error .eds-form-field__subscript {
    color: var(--eds-ff-error);
}

/* The clear (X) button.

   In Angular it is `@if (showClear())`, which is `clearable() && hasValue() &&
   !isDisabled() && !isReadonly()`. A static page has no `hasValue()`, so the
   markup is always there and CSS decides whether it shows: `:placeholder-shown`
   is false exactly when the control has a value, and the other three halves of
   the condition are the classes the component already sets.

   That ties the button to the placeholder being present. Every control this
   design puts a clear button on has one, and the frames show one in each; a
   field that ever loses its placeholder has to gain a class instead.

   `clearable` is opt-in and defaults to false, so it needs a marker on the
   field. The component has no class for it - it is a component input - so
   `--clearable` is this page's stand-in, named the way the library names its
   other modifiers. */
.eds-form-field__clear {
    display: none;
}

.eds-form-field--clearable:not(.eds-form-field--disabled):not(.eds-form-field--readonly)
.eds-form-field__control:has(.eds-native-input:not(:placeholder-shown))
.eds-form-field__clear {
    display: inline-flex;
}

.eds-form-field__clear svg {
    display: block;
}

/* ASP.NET's message class, on the span that `asp-validation-for` renders. The
   glyph that keeps colour from being the only carrier is the component's own
   `__error-icon`, which sits inside the control box - see form-field.css. */
.eds-form-field__subscript .field-validation-error {
    display: block;
    color: var(--eds-ff-error);
}

.eds-form-field__error-icon svg {
    display: block;
}

/* The eye on a password field, and the pencil on Подаци о налогу.

   Both are content the form field projects through its `edsSuffix` slot rather
   than a part of the component, so their size and their states are the page's
   to state - and the names are generic because seven fields across four pages
   instance them: Пријава once, Постављање нове лозинке twice, Измена лозинке
   three times, Подаци о налогу once. `.password-reveal` is the eye, which has
   behaviour; `.field-action` is the trailing button with none. The frames draw
   one slot for both, so the geometry is stated once here under the two names
   rather than twice.

   The frames nest it the way M3 nests an icon button: a 48px slot, a 40px
   state layer centred in it, a 24px glyph centred in that. The button is the
   slot - 48 is also the mobile target size 13.5 asks for - and the state layer
   is a pseudo-element rather than the button's own background, because the two
   are not the same box. Painting hover on the 48px box runs it flush into the
   field's border, and over the 2px inset ring `--error` and focus draw there,
   so the ring reads broken exactly where the button sits. Inset by 4 it clears
   the ring on every side, which is what the frames draw.

   Behaviour, for the eye, is /shared/form-field.js.

   DEVIATION - the exported control pads 16px on both sides and the frames pad
   only on the left, hanging the icon slot flush against the field's right edge.
   The negative margin gives back exactly that inset, so the glyph lands where
   the frames draw it without touching the component's own rule. */
.password-reveal,
.field-action {
    position: relative;
    /* The state layer sits below the glyph, so it is a negative-z child - which
     needs a stacking context of its own here, or it would drop behind the
     field's white background instead of behind the glyph. */
    isolation: isolate;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    margin-right: calc(-1 * var(--eds-input-padding-horizontal));
    padding: 0;
    border: none;
    background: transparent;
    cursor: pointer;
}

    /* The state layer. Behind the glyph, inset 4 from the slot on every side. */
    .password-reveal::before,
    .field-action::before {
        content: "";
        position: absolute;
        inset: 4px;
        z-index: -1;
        border-radius: var(--eds-radius-lg);
        transition: background-color var(--eds-duration-fast) var(--eds-ease-standard);
    }

    .password-reveal:hover::before,
    .field-action:hover::before {
        background: var(--eds-color-surface-container);
    }

    /* On the state layer too, so the focus ring keeps the same clearance from the
   field's border as the hover fill does. */
    .password-reveal:focus-visible,
    .field-action:focus-visible {
        outline: none;
    }

        .password-reveal:focus-visible::before,
        .field-action:focus-visible::before {
            outline: 2px solid var(--eds-ff-border-focus, var(--eds-color-primary));
        }

@media (prefers-reduced-motion: reduce) {
    .password-reveal::before,
    .field-action::before {
        transition: none;
    }
}

/* -----------------------------------------------------------------------------
   5. Radio

   Class names from radio.component.html. The eds-lib component wraps
   <mat-radio-group>/<mat-radio-button> and styles Material's internals through
   `::ng-deep`, none of which exists here, so the control itself is drawn from
   the tokens to the M3 geometry the frames use: a 20px ring inside a 24px icon
   box inside a 4px state layer, then 5px to the label.
   -------------------------------------------------------------------------- */

/* The group is a <fieldset> and its label a <legend>, so the label belongs to
   the options without an aria-labelledby to hold it there. Both are reset to
   plain blocks: a legend inside a flex fieldset is not laid out as a flex item
   in every browser, so the 4px to the options is a margin rather than a gap. */
.eds-radio-group-container {
    /* The legend borrows form-field's `__label` and `__required-marker`, and the
     marker takes its colour from `--eds-ff-error` - a token form-field declares
     on itself, so outside one it resolves to nothing and the dot inherits the
     label's grey. Declared here from the same value the library compiles into
     it, rather than the marker being given a second colour of its own. */
    --eds-ff-error: var(--eid-color-error);
    display: block;
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

    .eds-radio-group-container > legend {
        float: none;
        margin-bottom: var(--eds-space-1);
        padding: 0;
    }

.eds-radio-group {
    display: flex;
    flex-direction: column;
    gap: var(--eds-space-1);
}

/* `position: relative` only so the input, which is taken out of the layout
   just below, is anchored to its own option rather than to whatever happens to
   be positioned further up the page. */
.eds-radio-option {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding-inline: var(--eds-space-1);
    cursor: pointer;
}

.eds-radio-input {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
}

.eds-radio-mark {
    position: relative;
    flex: none;
    width: 32px;
    height: 32px;
    border-radius: var(--eds-radius-full);
}

    /* The ring: 20px, centred in the 32px state layer. */
    .eds-radio-mark::before {
        content: "";
        position: absolute;
        inset: 6px;
        border: 2px solid var(--eds-color-on-surface-variant);
        border-radius: var(--eds-radius-full);
        transition: border-color var(--eds-duration-medium) var(--eds-ease-standard);
    }

    /* The dot: 10px, and it grows out of nothing when the option is chosen. */
    .eds-radio-mark::after {
        content: "";
        position: absolute;
        inset: 11px;
        border-radius: var(--eds-radius-full);
        background: var(--eds-color-primary);
        transform: scale(0);
        transition: transform var(--eds-duration-medium) var(--eds-ease-standard);
    }

.eds-radio-input:checked + .eds-radio-mark::before {
    border-color: var(--eds-color-primary);
}

.eds-radio-input:checked + .eds-radio-mark::after {
    transform: scale(1);
}

.eds-radio-input:focus-visible + .eds-radio-mark {
    outline: 2px solid var(--eds-color-primary);
    outline-offset: -2px;
}

.eds-radio-option:hover .eds-radio-mark {
    background: color-mix(in srgb, var(--eds-color-primary) 8%, transparent);
}

.eds-radio-content {
    display: flex;
    min-width: 0;
}

.eds-radio-label {
    color: var(--eds-color-on-surface);
}

/* -----------------------------------------------------------------------------
   6. Checkbox

   Class names from checkbox.component.html, drawn here for the same reason as
   the radio: the component's CSS is `:host ::ng-deep` into <mat-checkbox>.
   -------------------------------------------------------------------------- */

.eds-checkbox {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: var(--eds-space-2);
    cursor: pointer;
}

.eds-checkbox__input {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
}

.eds-checkbox__box {
    position: relative;
    flex: none;
    width: 18px;
    height: 18px;
    border: 2px solid var(--eds-color-on-surface-variant);
    border-radius: var(--eds-radius-xs);
    transition: var(--eid-button-transition);
}

.eds-checkbox__input:checked + .eds-checkbox__box {
    border-color: var(--eds-color-primary);
    background: var(--eds-color-primary);
}

    .eds-checkbox__input:checked + .eds-checkbox__box::after {
        content: "";
        position: absolute;
        inset: 0;
        background: var(--eds-color-on-primary);
        /* mask-src: assets/icon-check.svg */
        mask: url('data:image/svg+xml,<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="11" height="8.25" viewBox="0 0 11 8.25" fill="none" xmlns="http://www.w3.org/2000/svg"><path id="Icon" fill-rule="evenodd" clip-rule="evenodd" d="M9.88991 0.211538C10.0245 0.0705121 10.1792 0 10.3541 0C10.5291 0 10.6838 0.0705121 10.8183 0.211538C10.9395 0.338462 11 0.497114 11 0.6875C11 0.877886 10.9395 1.03654 10.8183 1.16346L4.37982 7.95385C4.36636 7.96795 4.35291 7.98205 4.33945 7.99615C4.32599 8.01026 4.31254 8.02436 4.29908 8.03846C4.17798 8.17949 4.02661 8.25 3.84495 8.25C3.6633 8.25 3.51193 8.17949 3.39083 8.03846L0.181651 4.69615C0.0605499 4.56923 0 4.41058 0 4.22019C0 4.02981 0.0605499 3.87115 0.181651 3.74423C0.316209 3.6032 0.470947 3.53269 0.645872 3.53269C0.820796 3.53269 0.975534 3.6032 1.11009 3.74423L3.83486 6.6L9.88991 0.211538Z" fill="white"/></svg>') center/11px 8.25px no-repeat;
    }

.eds-checkbox__input:focus-visible + .eds-checkbox__box {
    outline: 2px solid var(--eds-color-primary);
    outline-offset: 2px;
}

.eds-checkbox__label {
    min-width: 0;
}

/* -----------------------------------------------------------------------------
   7. Upload

   /eds/lib/upload.css carries the component; this is its configuration and the
   three places the frames differ from it.
   -------------------------------------------------------------------------- */

.eds-upload {
    --upload-trigger-bg: var(--eds-primary-95);
    --upload-trigger-text: var(--eds-color-primary);
    --upload-icon-primary: var(--eds-color-primary);
    --upload-focus: var(--eds-color-primary);
    /* The component is a bare block because Angular composes label, trigger and
     message around it; here they are three children of it, 4px apart as the
     frames set them. */
    display: flex;
    flex-direction: column;
    gap: var(--eds-space-1);
}

/* The trigger's label is body/medium on primary, not the 12px
   surface-variant of a form-field label. */
.eds-upload__label {
    color: var(--eds-color-primary);
}

/* DEVIATION - the component's trigger is 420px wide, 46px tall and 4px round;
   the frames give it the full width of the form, 54px and an 8px corner. */
.eds-upload .upload-box {
    width: 100%;
    height: 54px;
    gap: 10px;
    padding-inline: 23px;
    border-radius: var(--eds-radius-md);
}

.eds-upload .trigger-icon {
    width: 20px;
    height: 20px;
    background: var(--upload-icon-primary);
    /* mask-src: assets/icon-attach.svg */
    mask: url('data:image/svg+xml,<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="Group"><g id="Vector"></g><path id="Vector_2" d="M11.6667 11.25V6.66667C11.6667 5.78261 11.3155 4.93477 10.6904 4.30964C10.0652 3.68452 9.21739 3.33333 8.33333 3.33333C7.44928 3.33333 6.60143 3.68452 5.97631 4.30964C5.35119 4.93477 5 5.78261 5 6.66667V11.25C5 12.6866 5.57068 14.0643 6.5865 15.0802C7.60233 16.096 8.98008 16.6667 10.4167 16.6667C11.8533 16.6667 13.231 16.096 14.2468 15.0802C15.2627 14.0643 15.8333 12.6866 15.8333 11.25V3.33333H17.5V11.25C17.5 13.1286 16.7537 14.9303 15.4253 16.2587C14.097 17.5871 12.2953 18.3333 10.4167 18.3333C8.53805 18.3333 6.73638 17.5871 5.40799 16.2587C4.07961 14.9303 3.33333 13.1286 3.33333 11.25V6.66667C3.33333 5.34058 3.86012 4.06881 4.7978 3.13113C5.73548 2.19345 7.00725 1.66667 8.33333 1.66667C9.65942 1.66667 10.9312 2.19345 11.8689 3.13113C12.8065 4.06881 13.3333 5.34058 13.3333 6.66667V11.25C13.3333 12.0235 13.026 12.7654 12.4791 13.3124C11.9321 13.8594 11.1902 14.1667 10.4167 14.1667C9.64312 14.1667 8.90125 13.8594 8.35427 13.3124C7.80729 12.7654 7.5 12.0235 7.5 11.25V6.66667H9.16667V11.25C9.16667 11.5815 9.29836 11.8995 9.53278 12.1339C9.7672 12.3683 10.0851 12.5 10.4167 12.5C10.7482 12.5 11.0661 12.3683 11.3006 12.1339C11.535 11.8995 11.6667 11.5815 11.6667 11.25Z" fill="%23003964"/></g></svg>') center/contain no-repeat;
}

.eds-upload .trigger-label {
    font-size: var(--eds-font-size-body-medium);
    line-height: var(--eds-line-height-body-medium);
    letter-spacing: var(--eds-tracking-body-medium);
}

/* DEVIATION - the component hides the native input outright (`display: none`)
   and puts `tabindex` and `role="button"` on the trigger instead, which is how
   Angular can also own the keyboard handling. Here the trigger is the input's
   own <label>, so the input has to stay reachable by Tab for the control to be
   operable at all; it is taken out of the layout instead of out of the tree,
   and the focus ring is drawn on the trigger it labels. */
.eds-upload .native-input {
    display: block;
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
}

.eds-upload:has(.native-input:focus-visible) .upload-box {
    outline: 2px solid var(--upload-focus);
    outline-offset: 2px;
}

.eds-upload__hint {
    margin: 0;
    color: var(--eds-color-primary);
}

/* -----------------------------------------------------------------------------
   8. Note

   Figma builds this out of the M3 Rich Tooltip component, but nothing about it
   is a tooltip: it is always visible, it is not attached to a control and it
   has no trigger. eds-lib's tooltip is a real hover/focus tooltip, so reusing
   it would mean disabling everything it does. It is a static callout instead,
   built from the tokens.
   -------------------------------------------------------------------------- */

.note {
    display: flex;
    flex-direction: column;
    gap: var(--eds-space-1);
    padding: var(--eds-space-3) var(--eds-space-4);
    background: var(--eid-color-note-bg);
    border-radius: var(--eid-radius-medium);
    /* Figma's eUprava/Elevation Light/3 is M3 level 3 in full - a 1px key shadow
     under a 4px ambient one. The library's --eds-elevation-3 ships only the
     ambient half; the missing key shadow belongs upstream, not in a page. */
    box-shadow: var(--eds-elevation-3);
    color: var(--eds-color-on-surface-variant);
}

.note__title,
.note__text {
    margin: 0;
}

/* -----------------------------------------------------------------------------
   9. Validation summary

   The container `asp-validation-summary` renders into. Empty and hidden until
   the server puts something in it; a labelled region rather than a bare div, so
   it can be reached and read as a landmark when it does.
   -------------------------------------------------------------------------- */

.validation-summary {
    display: none;
    padding: var(--eds-space-3) var(--eds-space-4);
    border: 1px solid var(--eid-color-error);
    border-radius: var(--eds-radius-sm);
    background: var(--eds-color-surface-container-lowest);
    color: var(--eid-color-error);
}

    .validation-summary.validation-summary-errors {
        display: block;
    }

    .validation-summary ul {
        margin: 0;
        padding-inline-start: var(--eds-space-5);
    }

/* -----------------------------------------------------------------------------
   10. Carousel

   The horizontal strip the EDS example page draws its "Погледај видео" row
   with, taken from

     eds-storybook/src/stories/ExamplePages/contact-faq.page.scss  (.cf-carousel)
     eds-storybook/src/stories/ExamplePages/contact-faq.page.ts    (onDrag*)

   There is no eds-lib carousel component - the example page builds the row out
   of a plain CSS scroller and a few lines of drag handling, and that is what is
   reproduced here, class names kept generic because two pages use it.

   Touch and trackpads pan the row natively; a mouse has nothing to grab, so
   /shared/carousel.js moves `scrollLeft` from pointer events and sets
   `.carousel--dragging` while it does. Without the script the row is still a
   scroller - it only loses mouse dragging.

   The strips keep their own item widths and padding in the page stylesheets;
   this rule is only the scroller behaviour.
   -------------------------------------------------------------------------- */

.carousel {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    /* Swiping the row must not drag the page along with it. */
    overscroll-behavior-x: contain;
    touch-action: pan-x;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* The row is dragged with the mouse, so it advertises itself as grabbable. */
    cursor: grab;
}

    .carousel::-webkit-scrollbar {
        display: none;
    }

/* While dragging, snapping and smooth scrolling would fight `scrollLeft`. */
.carousel--dragging {
    scroll-snap-type: none;
    scroll-behavior: auto;
    cursor: grabbing;
    user-select: none;
}

.carousel__item {
    scroll-snap-align: start;
}

/* Snapping animates the row, so it is a motion the setting covers. */
@media (prefers-reduced-motion: reduce) {
    .carousel {
        scroll-behavior: auto;
    }
}

/* -----------------------------------------------------------------------------
   11. Auth page shell

   The band, the welcome block and the floating card that Пријава and
   Постављање нове лозинке both open with. The two frames draw them identically
   - same wash, same type scale, same 880 column, same card - so they are stated
   once here rather than twice in two page stylesheets.

   The welcome copy is the one thing that differs between the two breakpoints
   rather than between the two pages: the phone frames read "Пријава на Портал
   за електронску идентификацију" and the desktop frames only "Портал за
   електронску идентификацију", so the two words the phone adds are a span the
   desktop breakpoint drops. One string, not two copies of it.
   -------------------------------------------------------------------------- */

/* The band is <main>'s, not the page's: both frames float the card on a wash
   and leave the footer on white. */
.auth {
    background: var(--eid-color-ice-blue);
}

    /* The chrome leaves 87px between the last section and the footer from md up,
   which is what Почетна and Помоћ measure - on both of them that section ends
   on white, so the gap reads as the footer's own air. Here the band is tinted
   and every auth frame runs it straight into the footer, so the gap goes.

   In _Layout the band is inside <main> and the footer is main's sibling, with
   the two <link>s of the _Footer partial between them - so the footer is found
   from <main> with `~`, not from `.auth` with `+`. */
    .auth + .eds-footer,
    main:has(> .auth) ~ .eds-footer {
        margin-top: 0;
    }

/* `.section` already carries the 880 column and the gutter; this adds the
   band's own rhythm. The phone frames run 24 above the welcome block.

   DEVIATION - below the card they do not agree with each other: Пријава leaves
   2px under it and Постављање нове лозинке 43, which is where two hand-set
   container heights happened to land rather than a decision either frame is
   making. Neither is a step on the scale, so the padding is symmetric at 24
   and the band reads the same on both pages. */
.auth__inner {
    display: flex;
    flex-direction: column;
    gap: var(--eds-space-6);
    padding-block: var(--eds-space-6);
}

.auth__welcome {
    color: var(--eds-color-primary);
}

.auth__title {
    margin: 0;
}

.auth__subtitle {
    margin: var(--eds-space-1) 0 0;
}

.auth__card {
    width: 100%;
}

/* md is where the header gives up its drawer, and it is where these pages pick
   up their desktop frames: the wash changes, the welcome block grows a step in
   the type scale and loses the two words the phone frame adds to it. */
@media (min-width: 905px) {
    /* The desktop frames wash the band in primary95 where the phone frames use
     ice blue - #eaf1ff against #eff7ff. Two different values, sampled from the
     two renders, not one value the export rounds. */
    .auth {
        background: var(--eds-primary-95);
    }

    .auth__inner {
        /* The frames measure 49; the scale's step next to it is 48. */
        gap: var(--eds-space-9);
        padding-block: var(--eds-space-9);
    }

    .auth__welcome {
        color: var(--eds-primary-20);
    }

    /* headline/large-emphasized and headline/small-emphasized. Only the size
     role changes - the medium weight is on the element from the markup. */
    .auth__title {
        font-size: var(--eds-font-size-headline-large);
        line-height: var(--eds-line-height-headline-large);
        letter-spacing: var(--eds-tracking-headline-large);
    }

    .auth__subtitle {
        margin-top: 10px;
        font-size: var(--eds-font-size-headline-small);
        line-height: var(--eds-line-height-headline-small);
        letter-spacing: var(--eds-tracking-headline-small);
        opacity: 0.8;
    }

    .auth__subtitle-lead {
        display: none;
    }
}

/* -----------------------------------------------------------------------------
   12. Password form

   The body of the two password cards: Постављање нове лозинке (the forgotten-
   password flow) and Измена лозинке (the signed-in one). Their frames draw the
   same form - the same stacked fields, the same rule list, the same five-pill
   meter, the same full-width button - and differ only in how many fields there
   are and what the card and the button are called. So it is stated once here,
   the way the auth shell above it is, rather than twice in two page
   stylesheets.

   Neither the rule list nor the meter exists in eds-lib. `progress-indiactor`
   is the nearest thing to the meter and it is not near: a single continuous 4px
   track with a sliding indicator, where the frames draw five discrete 30 x 7
   pills with 8 between them. Reusing it would mean overriding every dimension
   it sets, so both are drawn from the tokens instead, under page class names.
   Their ARIA is borrowed from it though - `role="progressbar"` with the three
   value attributes, which is what progress-bar.component.html carries.
   -------------------------------------------------------------------------- */

/* The card body. The card itself is section 2; this is the padding the two
   frames give its `_Content` slot. */
.pwform-body {
    width: 100%;
    padding: var(--eds-space-6);
}

/* The frames stack four rows - the fields, the rules, the meter, the button.
   Three of the gaps are 16 and the last one is 24, so 16 is the gap and the
   button takes the remaining 8 as a margin rather than the whole stack being
   written out as four separate spacings.

   578 is the width of the form in both desktop frames; below that it is simply
   the card's content width, which is what the phone frames draw. */
.pwform {
    display: flex;
    flex-direction: column;
    gap: var(--eds-space-4);
    width: 100%;
    max-width: 578px;
    margin-inline: auto;
}

/* The controls, 16 apart. Пријава leaves 32 between its two because they are a
   username and a password; here they are one value and its confirmation - and
   on Измена лозинке the old value as well - and the frames draw them closer. */
.pwform__inputs {
    display: flex;
    flex-direction: column;
    gap: var(--eds-space-4);
}

.pwform__submit {
    margin-top: var(--eds-space-2);
}

/* The rules: title, then one row per rule - a 14px glyph, 8 of air, the rule.
   body/medium-emphasized for the title and title/small for the rows, both from
   the markup; what is set here is the layout and the two state colours. */
.pwform-rules {
    display: flex;
    flex-direction: column;
    gap: var(--eds-space-2);
}

.pwform-rules__title {
    margin: 0;
    color: var(--eds-color-primary);
}

.pwform-rules__list {
    display: flex;
    flex-direction: column;
    gap: var(--eds-space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* A rule that is not met is drawn in the error red the form field uses for its
   own messages; one that is met, in the green of Figma's extended palette. The
   library has neither as a text colour - see the note on --eid-color-success in
   /shared/shared.css - so both come from the page tokens there. */
.pwform-rule {
    display: flex;
    align-items: center;
    gap: var(--eds-space-2);
    color: var(--eid-color-error);
}

.pwform-rule--met {
    color: var(--eid-color-success);
}

/* The glyph keeps its 14px against a rule that wraps to two lines on a narrow
   screen, and stays on the first line rather than centring against both. */
.pwform-rule__icon {
    flex: none;
    align-self: flex-start;
    margin-top: 3px;
}

/* The meter: label, 16, five pills. The pills are fixed at 30 x 7 as the frames
   draw them, and the row wraps rather than overflowing if the label ever
   grows. */
.pwform-strength {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--eds-space-4);
}

.pwform-strength__label {
    color: var(--eds-color-primary);
}

.pwform-strength__meter {
    display: flex;
    align-items: center;
    gap: var(--eds-space-2);
}

.pwform-strength__segment {
    width: 30px;
    height: 7px;
    border-radius: var(--eds-radius-xs);
    background: var(--eds-color-surface-variant);
}

.pwform-strength__segment--on {
    background: var(--eds-color-primary);
}

/* md is where the header gives up its drawer, and it is where both pages pick
   up their desktop frames. Two places space the form differently there. */
@media (min-width: 905px) {
    /* The desktop frames inset the form 16 from the top of the card body, where
     the phone frames run it straight against the 24 of padding. */
    .pwform {
        padding-top: var(--eds-space-4);
    }

    /* And they open the gap between the controls and the rules from 16 to 24,
     while every other gap in the stack stays where it is. */
    .pwform-rules {
        margin-top: var(--eds-space-2);
    }
}

/* -----------------------------------------------------------------------------
   13. Confirmation dialog

   The card that floats over a dimmed page to ask whether an action is meant.
   Two pages open it: еГрађанин before the Грађанин label moves (Figma 83:12356
   and 83:12524, the only frames drawn for it), and Квалификовани електронски
   сертификат у клауду before each of its three certificate actions - issuing
   parameters, revoking the certificate, revoking every certificate. It started
   on еГрађанин and moved here when the second page needed it; the class name is
   the one it was given there.

   /shared/role-dialog.js opens it, and what it opens is the platform's
   <dialog>: eds-lib has no dialog component, and showModal() is what carries
   the focus trap, the Escape, the inert background and the scrim that section
   13 of claude.md asks for - none of which a <div> overlay gets for free.

   The card inside it is `.card` and `.card__header` from section 2,
   unchanged: the frame draws the same white surface, the same Forma elevation,
   the same 8px corner and the same 24/40/20 header over a rule. Only what the
   frame does differently is written here.

   No mobile frame exists for it - the brief asks only that it be responsive -
   so it takes the desktop card's proportions and stops growing at the frame's
   564.
   -------------------------------------------------------------------------- */

.role-dialog {
    width: min(564px, 100% - var(--eds-space-8));
    max-width: min(564px, 100% - var(--eds-space-8));
    max-height: calc(100% - var(--eds-space-8));
    padding: 0;
    border: 0;
    background: transparent;
    /* A viewport too short for the card scrolls the card, not the page behind
     it, which showModal() has already made inert. */
    overflow: auto;
    overscroll-behavior: contain;
}

    /* The scrim the frame draws over the page: black at 50%. eDS emits no scrim
   token - the library's schemes stop before M3's `scrim` role - so this is the
   frame's own value. */
    .role-dialog::backdrop {
        background: rgba(0, 0, 0, 0.5);
    }

    /* DEVIATION - the frame lays the title out in a 380px text box inside a header
   that is 484 wide between its insets: centred on the same column the body
   below it uses. `.card__header` centres its text already; the width of the
   column is what has to be said here. */
    .role-dialog .card__title {
        max-width: 380px;
        margin-inline: auto;
    }

/* DEVIATION - `.card__content` is the 23px pad and the 16 rhythm the auth
   cards share. This card is drawn at 24 and 24. */
.role-dialog__content {
    align-items: center;
    gap: var(--eds-space-6);
    padding: var(--eds-space-6);
}

.role-dialog__body,
.role-dialog__actions {
    width: 100%;
    max-width: 380px;
}

/* DEVIATION - the frame sets the body at ref/tertiary/tertiary25 (#393c3d), a
   palette step the export does not emit and a scheme role eDS does not name.
   on-surface-variant (#41484d) is the semantic the frame is reaching for and
   the nearest value the library has; on the card's white it carries 8.6:1.

   The type role is the frame's own: 14/20 medium at 0.1 tracking is
   title-small, which is why the copy is marked up with that rather than with a
   body role. */
.role-dialog__body {
    margin: 0;
    color: var(--eds-color-on-surface-variant);
}

    .role-dialog__body p {
        margin: 0;
    }

    /* The list runs straight on under its lead-in - the frame leaves no gap between
   the two - and its markers sit in the 21px the frame indents them by. */
    .role-dialog__body ul {
        margin: 0;
        padding-inline-start: 21px;
    }

        /* A sentence after the list is a second statement rather than more of the
   list, so it opens where a paragraph would. The еГрађанин frames end on the
   list and never reach this rule; Опозови све сертификате is the body that
   does, because what it revokes and what that costs are two different
   sentences. */
        .role-dialog__body ul + p {
            margin-top: var(--eds-space-2);
        }

/* A dialog that asks for something before it acts, rather than only for a yes
   or a no, puts the control and the two buttons in one form: what the control
   holds is what posts with the answer. Then the form is the 380 column and
   `.role-dialog__actions` is a row inside it rather than the form itself.

   Опозови on Квалификовани електронски сертификат у клауду is the one dialog
   here shaped that way - it asks which reason. The еГрађанин dialogs and the
   other two on that page keep the plain shape, where the actions row *is* the
   form. No gap: `.role-dialog__actions` already opens with 16 of its own. */
.role-dialog__form {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 380px;
}

.role-dialog__actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--eds-space-4);
    padding-top: var(--eds-space-4);
}

    /* `.button` is full width wherever the pages stack it; here the two sit on one
   row at the widths their labels come to, and Не is held at the 94 the frame
   draws so the pair does not read as one long button and one stub.

   Which of the two gives way is the point of the second rule. Below about
   360px the row no longer fits, and if both held their width the confirm
   label - the long one - would be the one squeezed, onto three lines. So Не
   keeps the 94 as a basis it may shrink from, and the confirm keeps its label
   on one line down to 320. The `value` is the same contract the answer travels
   on: it is what the dialog hands back as `returnValue`. */
    .role-dialog__actions .button {
        width: auto;
        flex: 0 0 auto;
    }

        .role-dialog__actions .button[value="no"] {
            flex: 0 1 94px;
            min-width: 0;
        }

/* The card lifts and its scrim fades - a motion like the drawer's, and it
   answers to the same setting. */
@media (prefers-reduced-motion: no-preference) {
    .role-dialog[open] {
        animation: role-dialog-in 150ms cubic-bezier(0.4, 0, 0.2, 1);
    }

        .role-dialog[open]::backdrop {
            animation: role-dialog-scrim-in 150ms cubic-bezier(0.4, 0, 0.2, 1);
        }
}

@keyframes role-dialog-in {
    from {
        opacity: 0;
        transform: translateY(8px);
    }
}

@keyframes role-dialog-scrim-in {
    from {
        opacity: 0;
    }
}

/* -----------------------------------------------------------------------------
   14. Loader

   Figma 119:14884 draws it over Мој ИД Отвореног Балкана: the page dimmed under
   a scrim with a ring centred on it. It is not part of that page though - it is
   what any page puts up while it waits - so it lives here and /shared/loader.js
   builds it on demand. See that file for the API and for the ARIA.

   The ring itself is eds-lib's progress spinner, exported to
   /eds/lib/progress-spinner.css, in the indeterminate mode that spins. Nothing
   about the ring is drawn here; what is here is the scrim the frame puts behind
   it and the size the frame draws it at.
   -------------------------------------------------------------------------- */

.loader {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--eds-space-4);
    padding: var(--eds-space-4);
    /* The frame's overlays/default. The confirmation dialog above draws its scrim
     at 50% and this one at 20%, which is the frames' own difference: the dialog
     asks a question and wants the page out of the way, the loader only says to
     wait and leaves the page readable underneath. eDS emits no scrim token -
     the library's schemes stop before M3's `scrim` role - so both are stated
     where they are used. */
    background: rgba(0, 0, 0, 0.2);
}

    /* `display: flex` would otherwise beat the `hidden` attribute, and `hidden` is
   how loader.js puts it away. */
    .loader[hidden] {
        display: none;
    }

.loader__box {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--eds-space-4);
}

/* The frame's indicator is 125 x 120. The component's SVG is square - a 100x100
   viewBox - so it takes the 120, and the CSS sizes it rather than the width and
   height attributes on the element, which is what lets the phone size below
   override it. The 8 stroke-width is in viewBox units: on a 120px ring that
   comes to 9.6px, which is the ~10px the frame draws. */
.loader__spinner {
    width: 120px;
    height: 120px;
}

/* DEVIATION - the frames carry no text with the ring, and none is shown unless
   a caller passes one to showLoader(). When one is passed it takes the primary
   the rest of the pages label with: over a page dimmed only 20% a white label
   would sit on whatever happened to be behind it, and this reads at every
   width. */
.loader__text {
    max-width: 32ch;
    margin: 0;
    color: var(--eds-color-primary);
    text-align: center;
}

/* The page behind it does not scroll while it is up. `inert` already takes the
   background off the tab order; this is the pointer half of the same idea. */
body.loader-open {
    overflow: hidden;
}

/* The phone. The frames give the loader only at 1280, so this is the one value
   chosen here: 120 is over a third of a 390px screen, and 88 keeps the ring
   clearly the subject without crowding the width. */
@media (max-width: 599.98px) {
    .loader__spinner {
        width: 88px;
        height: 88px;
    }
}

/* DEVIATION - the exported component animates unconditionally; eds-lib gives
   the spinner no `prefers-reduced-motion` block, though the navigation-menu and
   the dialog above both have one, and claude.md 13.5 asks for it.

   A loader that does not move is a loader that looks broken, so the motion is
   reduced rather than removed: the ring keeps turning, slowly and at a steady
   rate, and the dash animation - the part that pulses the arc's length, which
   is the restless half - is dropped. This belongs upstream in the component;
   until it is there it is stated here, where the loader is composed. */
@media (prefers-reduced-motion: reduce) {
    .loader__spinner .eds-progress-spinner__indicator--indeterminate {
        animation: eds-spinner-rotate 3s linear infinite;
    }
}

/* -----------------------------------------------------------------------------
   15. Loader on a button

   Figma 116:13410 and 116:11710: Издај параметре, while it works, keeps its
   filled container and shows a bar in place of its label. /shared/button-
   loader.js runs it; the bar is eds-lib's progress bar out of
   /eds/lib/progress-bar.css, determinate, whose markup is in the button.

   A <button> holds only phrasing content, so the component's <div>s are
   <span>s here and are given back the block display a <div> would have had.
   -------------------------------------------------------------------------- */

.button-loader__bar,
.button-loader__bar .eds-progress-bar__track,
.button-loader__bar .eds-progress-bar__indicator {
    display: block;
}

    .button-loader__bar[hidden] {
        display: none;
    }

/* DEVIATION - geometry. The component is a 4px hairline with rounded ends that
   fills its container. The frames draw a 12px bar with square ends, 121px wide
   on either width, centred in the button. The frame wins: the bar stands in for
   the label, and a 4px line would read as a rule under a missing label rather
   than as the button's content. Colours stay the component's - its primary
   indicator is the frames' surface-tint #36618e exactly, and its track is
   surfaceVariant where the frames draw #d9d9d9, a neutral grey the export
   does not carry. */
.button-loader__bar {
    width: 121px;
    max-width: 100%;
}

    .button-loader__bar .eds-progress-bar__track,
    .button-loader__bar .eds-progress-bar__indicator {
        height: 12px;
        border-radius: 0;
    }

    .button-loader__bar .eds-progress-bar__indicator {
        width: 0;
    }

/* While it works the button looks like itself, not like a disabled button, and
   does not respond to hover as if it were waiting for a click. */
.button-loader--active {
    cursor: progress;
}

.button--filled.button-loader--active:hover {
    background: var(--eds-color-primary);
}

@media (prefers-reduced-motion: reduce) {
    .button-loader__bar .eds-progress-bar__indicator {
        transition: none;
    }
}

/* -----------------------------------------------------------------------------
   16. Guide steps

   "Постаните еГрађанин" - a numbered list of instructions with a rule running
   from one number to the next. Two pages draw it: еГрађанин — непријављен
   корисник (Figma 1:61220) as a full-width section at the foot of the page, and
   Регистрација (Figma 1:59379) as the left column beside the form. Same list,
   same counters, same rule; what differs between them is only where the column
   sits, which each page states for itself.

   eds-lib has a stepper and this is not it: that component is a wizard - a row
   of clickable step headers over a content pane, with next and back buttons and
   a step the user is currently on - and this is a static list that borrows its
   numbered circle. So the circle is the real component, exported as
   /eds/lib/step-counter.css and configured below through its own custom
   properties, and the list around it is an ordered list.

   The counter is `aria-hidden` in the markup because the <ol> already carries
   the order; that is what the component's own template does with it.

   Everything is scoped under `.guide` on purpose. `.steps` and `.step` are also
   Почетна's class names for a different list - three illustrated cards - and
   that page has no `.guide` around them, so the two never meet.
   -------------------------------------------------------------------------- */

/* Two sizes in one heading, and in the wordmark's dark blue rather than in
   primary - the frames' own colour for it. */
.guide__title {
    display: flex;
    flex-direction: column;
    margin: 0;
    color: var(--eid-color-brand-dark-blue);
}

.guide .steps {
    /* Figma Mobile/Primary Shades/400, the ground of a step not yet reached. The
     library's schemes stop at primary/secondary/tertiary/error and carry no
     shade ramp, so there is no --eds-* to reach for. */
    --eid-color-step-pending: #9ab0c1;
    margin: var(--eds-space-3) 0 0;
    padding: 0;
    list-style: none;
}

/* DEVIATION - the counter's own state modifiers (`--full --active` and the
   rest) are not used. They carry Material's untouched default primary, #36618E,
   which eGDS overrides to the brand blue - eds/tokens.css says the same thing
   about the library's schemes - so the two grounds are set through the
   component's custom properties instead, which is the hook it exposes for
   exactly this. Size and type are the frames' 24 circle and title/small. */
.guide .eds-step-counter {
    --eds-step-counter-size: 24px;
    --eds-step-counter-font-size: var(--eds-font-size-title-small);
    --eds-step-counter-line-height: var(--eds-line-height-title-small);
    --eds-step-counter-letter-spacing: var(--eds-tracking-title-small);
    --eds-step-counter-bg: var(--eid-color-step-pending);
    --eds-step-counter-fg: var(--eds-color-on-primary);
}

.guide .step--current .eds-step-counter {
    --eds-step-counter-bg: var(--eds-color-primary);
}

.guide .step {
    position: relative;
}

/* 8 of lead-in puts the 24 circle's centre on 20, which is where the rule and
   the step body are measured from. */
.guide .step__header {
    display: flex;
    align-items: center;
    gap: var(--eds-space-4);
    min-height: 72px;
    margin: 0;
    padding-inline-start: var(--eds-space-2);
}

.guide .step__label {
    color: var(--eds-color-primary);
}

.guide .step__body {
    display: flex;
    flex-direction: column;
    gap: var(--eds-space-4);
    padding-inline-start: var(--eds-space-8);
}

.guide .step__text {
    margin: 0;
    color: var(--eds-color-primary);
}

/* The rule between two numbers. It starts under the circle it leaves and ends
   on top of the one it reaches - the next step's circle begins 24 into that
   step's 72 header - so it is drawn off the step rather than off the body, and
   the last step has none. Centred on 20: 2 wide, starting at 19. */
.guide .step:not(:last-child)::before {
    content: '';
    position: absolute;
    top: 48px;
    bottom: -24px;
    inset-inline-start: 19px;
    width: 2px;
    background: var(--eds-color-outline-variant);
}

/* -----------------------------------------------------------------------------
   17. Native select

   eds-lib has a select component and this is deliberately not it. That one is a
   `<button aria-haspopup="listbox">` over a CDK overlay - a full listbox with a
   search box, roving focus and its own keyboard contract, Angular from top to
   bottom. Reproducing it means writing that listbox by hand, which is well past
   the interactivity §11.4 of claude.md allows and would be a second, subtly
   different implementation of a component the library already owns.

   The native control is the supported alternative, not a workaround: the
   library's own `styles/_input.scss` - the partial `.eds-native-input` is
   generated from - names `<select>` beside `<input>` as what
   `.eds-form-field__control` centres. So the field, its label, its focus ring,
   its error border and its subscript are all the exported form-field component,
   unchanged, and the select is the control inside it. On the Razor side it is
   `asp-for` plus `asp-items`, which renders exactly this.

   One thing is borrowed from the select component: the chevron. eds-lib draws
   it as `expand_more` at 20 in on-surface-variant, which is what the markup
   redraws inline beside the control.

   Квалификовани електронски сертификат and Мобилна апликација ConsentID each
   still carry their own copy of these three rules, under `.qec__reason-*` and
   `.consentid__reason-*`; those two predate this section and are unchanged.
   -------------------------------------------------------------------------- */

/* DEVIATION - `.eds-native-input` is written for a control that has no
   furniture of its own. A native select brings the platform's own arrow, in the
   platform's own colour and position, which is the one part of it that would
   read as foreign inside an eDS field. `appearance: none` takes it off so the
   component's chevron can stand where the component puts it. */
.select-native {
    appearance: none;
    cursor: pointer;
}

    /* The placeholder row reads as placeholder text, the way the component's
   `.eds-select__value--placeholder` does, until something is chosen. */
    .select-native:has(option[value=""]:checked) {
        color: var(--eds-color-placeholder, var(--eds-color-on-surface-variant));
    }

/* The chevron sits in the control box beside the select, as the component has
   it - not on top of it - so the field's own layout keeps spacing it and the
   error icon apart. Pointer events go through to the select, so clicking the
   arrow opens the list the way clicking the control does. */
.select-arrow {
    display: flex;
    flex: none;
    align-items: center;
    color: var(--eds-color-on-surface-variant);
    pointer-events: none;
}

/* -----------------------------------------------------------------------------
   18. Registration layout

   The shape both registration pages open with: Регистрација корисничким именом
   и лозинком (Figma 1:59346) and Регистрација квалификованим електронским
   сертификатом (1:59721). Their frames compose the page identically - the same
   880 column split into the Постаните еГрађанин list and a floating card, the
   same card padding, the same agreement line under the form - and differ only
   in what the card holds. So it is stated once here rather than twice in two
   page stylesheets.

   The list in the left column is section 16; the card is section 2; the fields
   are section 4 and /eds/lib/form-field.css. This is only how they are placed.
   -------------------------------------------------------------------------- */

/* The desktop frames split the 880 content column into 280 for Постаните
   еГрађанин and the rest for the card, 49 apart. The phone frames have no
   columns at all: the card comes first and Постаните еГрађанин last, below it.
   So the order is the one the phone frames draw, and md puts the guide back on
   the left. */
.reg__layout {
    display: flex;
    flex-direction: column;
    gap: var(--eds-space-9);
}

.reg__main {
    display: flex;
    flex-direction: column;
    /* 16 between the card and whatever the page puts over or under it - the
     stepper on one page, the help link on the other. */
    gap: var(--eds-space-4);
    min-width: 0;
    order: 1;
}

.reg__guide {
    order: 2;
}

/* The one thing both pages add to the guide list: the text button under it,
   which еГрађанин — непријављен корисник does not have. */
.reg__more {
    /* DEVIATION - `.button` centres its label; the frames set this one's content
     against the left edge of the column, in line with the numbers above it. */
    justify-content: flex-start;
    margin-top: var(--eds-space-4);
    padding-inline: var(--eds-space-4);
}

.reg__more-icon {
    flex: none;
}

.reg__card {
    width: 100%;
}

/* 23 is what both frames inset the card's body by - not a step on the scale,
   but the same odd number on every registration frame, so it is taken as
   drawn. */
.reg__content {
    width: 100%;
    padding: 23px;
}

.reg__form {
    display: flex;
    flex-direction: column;
    gap: var(--reg-form-gap, var(--eds-space-4));
}

/* A line of copy inside the card, above whatever it introduces. */
.reg__lead {
    margin: 0;
    color: var(--eds-color-primary);
}

/* The agreement under each form. body/small on primary, the checkbox 8 from it
   and level with the first line rather than with the middle of the paragraph. */
.reg__agree {
    align-items: flex-start;
    gap: var(--eds-space-2);
    color: var(--eds-color-primary);
}

    .reg__agree .eds-checkbox__label {
        color: inherit;
    }

/* A glyph the field projects through the component's `edsSuffix` slot - the
   calendar on a date, the pencil on an editable row - so it is a child of the
   control box and not something laid over it. A glyph and not a control where
   the frames draw no panel for it to open. */
.reg__field-icon {
    display: flex;
    flex: none;
    align-items: center;
    /* The control pads 16 on both sides and the frames leave 4 to the right of
     the glyph; the inset gives that difference back. */
    margin-inline-end: -12px;
    color: var(--eds-color-on-surface-variant);
    pointer-events: none;
}

/* md is where the header gives up its drawer, and it is where both pages pick
   up their desktop frames: the column splits in two. */
@media (min-width: 905px) {
    .reg__layout {
        flex-direction: row;
        align-items: flex-start;
    }

    .reg__guide {
        flex: none;
        order: 0;
        width: 280px;
    }

    .reg__main {
        flex: 1 1 auto;
    }
}