@layer components {
    .generator-canvas {
        display: flex;
        flex-direction: column;
        gap: var(--space-6);
        max-inline-size: var(--measure);
        padding-block-start: var(--space-4);
    }

    /* The step headings: small, numbered, flush left — the serif scale does the organising. */
    .generator-canvas__step {
        margin: 0 0 var(--space-2);
        padding: 0;
        font-family: var(--font-heading);
        font-size: var(--text-h4);
        font-weight: var(--font-heading-weight);
    }

    .generator-canvas__hint,
    .generator-canvas__caption {
        margin: 0;
        color: var(--color-text-muted);
        font-size: var(--text-s);
    }

    /* The caption speaks to the primary pointer: a finger unless the device has a fine,
       hovering one (a mouse, a trackpad). Server-rendered both ways — no script, no flash. */
    .generator-canvas__for-mouse {
        display: none;
    }

    @media (hover: hover) and (pointer: fine) {
        .generator-canvas__for-touch {
            display: none;
        }

        .generator-canvas__for-mouse {
            display: inline;
        }
    }

    /* — 1. range: two short number fields side by side, even on a 360 px phone — */
    .generator-canvas__range {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: var(--space-3);
        margin: 0;
        padding: 0;
        border: 0;

        & legend {
            grid-column: 1 / -1;
        }
    }

    /*
     * — the drawing —
     * Sticky on screens tall enough to keep the list visible under it, so editing a value in the
     * list changes the ridge in sight. Never on a short (landscape) phone: it would take the screen.
     */
    .generator-canvas__figure {
        display: flex;
        flex-direction: column;
        gap: var(--space-2);
        margin: 0;
        background: var(--color-bg);

        @media (min-height: 44rem) {
            position: sticky;
            inset-block-start: 0;
            z-index: 5;
            padding-block-end: var(--space-2);
        }
    }

    .generator-canvas__svg {
        display: block;
        inline-size: 100%;
        block-size: auto;
        border-radius: var(--radius-md);
        /* A vertical swipe over empty sky scrolls the page. A press on a point is claimed by the
           controller (non-passive touchstart + preventDefault), so the point drags up and down
           too. Changing this to `none` traps the visitor's scroll on the drawing. */
        touch-action: pan-y;
        user-select: none;
        -webkit-user-select: none;
        -webkit-tap-highlight-color: transparent;
        cursor: crosshair;
    }

    .gc-sky {
        fill: var(--gen-sky);
    }

    .gc-ridge-fill {
        fill: var(--gen-ridge-fill);
    }

    .gc-axis,
    .gc-tick line {
        stroke: var(--gen-line);
        stroke-width: 1;
    }

    .gc-tick text {
        fill: var(--gen-text);
        font-family: var(--font-body);
        font-size: 10px;
        text-anchor: middle;
    }

    .gc-ridge {
        fill: none;
        stroke: var(--gen-ridge-stroke);
        stroke-width: 2.5;
        stroke-linecap: round;
        stroke-linejoin: round;
    }

    .gc-ridge--future {
        stroke-dasharray: 5 5;
    }

    .gc-empty {
        fill: var(--gen-text);
        font-family: var(--font-body);
        font-size: 12px;
        font-style: italic;
        text-anchor: middle;
    }

    .gc-empty[hidden],
    .gc-drag-label[hidden],
    .gc-point__line[hidden] {
        display: none;
    }

    /* The month that follows the finger: at the top of the drawing, where the finger is not. */
    .gc-drag-label {
        fill: var(--gen-text);
        stroke: var(--gen-sky);
        stroke-width: 4px;
        paint-order: stroke;
        font-family: var(--font-heading);
        font-size: 13px;
        font-weight: 600;
        text-anchor: middle;
        pointer-events: none;
    }

    /* Dragged in both directions; `none` where browsers honour it on SVG children (the hit area
       around the handle is covered by the controller's touchstart). */
    .gc-point {
        cursor: move;
        touch-action: none;
        outline: none;
    }

    .gc-point__line {
        stroke: var(--gen-line);
        stroke-width: 1.25;
    }

    .gc-point--future .gc-point__line {
        stroke-dasharray: 3 3;
    }

    .gc-point__dot {
        fill: var(--gen-accent);
        stroke: var(--gen-sky);
        stroke-width: 2;
    }

    /* Helper points only shape the ridge: smaller, hollow, in the line colour. */
    /* The photo badge: a round print with a paper rim above the dot; never takes a touch. */
    .gc-photos {
        pointer-events: none;
    }

    .gc-photo__rim {
        fill: var(--gen-sky);
        stroke: var(--gen-line);
        stroke-width: 1;
    }

    .gc-photo--missing .gc-photo__rim {
        stroke-dasharray: 2 2;
    }

    .gc-point--helper .gc-point__dot {
        fill: var(--gen-sky);
        stroke: var(--gen-line);
    }

    .gc-point__ring {
        fill: none;
        stroke: transparent;
        stroke-width: 2;
    }

    /* Keyboard focus and the selected point: a ring in the accent, never the browser default. */
    .gc-point:focus-visible .gc-point__ring,
    .gc-point.is-selected .gc-point__ring {
        stroke: var(--gen-accent);
    }

    /* Point names: 11 units at weight 600 — the size and weight the label placer measures
       (assets/labels/text_measure.ts) and the cards draw; the anchor comes from the placer. */
    .gc-labels {
        pointer-events: none;
    }

    .gc-label__name {
        fill: var(--gen-text);
        stroke: var(--gen-sky);
        stroke-width: 3px;
        stroke-linejoin: round;
        paint-order: stroke;
        font-family: var(--font-body);
        font-size: 11px;
        font-weight: 600;
    }

    /* A name set on the filled range keeps a halo in the range's colour. */
    .gc-label--on-range .gc-label__name {
        stroke: var(--gen-ridge-fill);
    }

    .gc-label__leader {
        stroke: var(--gen-line);
        stroke-width: 0.75;
        opacity: 0.7;
    }

    .gc-label__leader[hidden] {
        display: none;
    }

    /* A named point whose name found no room: a ring says "there is a name here — tap me". */
    .gc-point--unlabelled .gc-point__ring {
        stroke: var(--gen-line);
        stroke-dasharray: 2 2;
    }

    .generator-canvas__hidden-names {
        margin: 0;
        color: var(--color-text-muted);
        font-size: var(--text-s);

        &[hidden] {
            display: none;
        }
    }

    /* — notices: said, and seen — */
    .generator-canvas__notice {
        min-block-size: 1.5em;
        margin: 0;
        font-size: var(--text-s);

        &:empty {
            min-block-size: 0;
        }

        &[data-tone='error'] {
            color: var(--danger);
            font-weight: 600;
        }
    }

    /* — 2. points — */
    .generator-canvas__points,
    .generator-canvas__name,
    .generator-canvas__output {
        display: flex;
        flex-direction: column;
        gap: var(--space-3);
    }

    .generator-canvas__add {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 6.5rem;
        gap: var(--space-2);
        align-items: end;
    }

    .generator-canvas__add-submit {
        grid-column: 1 / -1;
        justify-self: start;
    }

    .generator-canvas__list {
        display: flex;
        flex-direction: column;
        gap: var(--space-4);
        margin: 0;
        padding: 0;
        list-style: none;

        &:empty {
            display: none;
        }
    }

    /* A row: name across the top, then value, date and the remove button — fits 320 px. */
    .gc-row {
        display: grid;
        grid-template-columns: 5.5rem minmax(0, 1fr) 44px;
        gap: var(--space-2);
        align-items: end;
        padding-inline-start: var(--space-2);
        border-inline-start: 3px solid transparent;

        &.is-selected {
            border-inline-start-color: var(--color-accent);
        }
    }

    .gc-row__name {
        grid-column: 1 / -1;
    }

    .gc-row__helper-note {
        display: none;
    }

    .gc-row.is-helper .gc-row__helper-note {
        display: inline;
    }

    /* A month input has a wide intrinsic size; without these it pushes the row off a phone. */
    .gc-row > *,
    .gc-row .input {
        min-inline-size: 0;
    }

    /*
     * A row's photo (2026-11-02): the 40 px thumbnail and its buttons on their own line under the
     * fields. `data-photo-state` on the part decides what shows: none → "Pridať fotku"; loading /
     * ready → the thumbnail, "Vymeniť fotku", "Odobrať fotku"; missing → the sentence and "Vybrať znova".
     */
    .gc-row__photo {
        display: flex;
        flex-wrap: wrap;
        grid-column: 1 / -1;
        gap: var(--space-1) var(--space-2);
        align-items: center;
    }

    .gc-row__thumb {
        inline-size: 40px;
        block-size: 40px;
        object-fit: cover;
        border: 2px solid var(--color-bg);
        box-shadow: 0 1px 2px rgb(0 0 0 / 0.3);
        background: var(--color-sunken);
    }

    .gc-row__photo-button {
        min-block-size: 44px;
    }

    .gc-row__photo-missing {
        flex-basis: 100%;
        margin: 0;
        color: var(--danger);
        font-size: var(--text-s);
    }

    .gc-row__photo[data-photo-state='none'] {
        & .gc-row__thumb,
        & .gc-row__photo-missing,
        & .gc-row__photo-button--replace,
        & .gc-row__photo-button--remove {
            display: none;
        }
    }

    .gc-row__photo:is([data-photo-state='ready'], [data-photo-state='loading']) {
        & .gc-row__photo-missing,
        & .gc-row__photo-button--add,
        & .gc-row__again-label {
            display: none;
        }
    }

    .gc-row__photo[data-photo-state='missing'] {
        & .gc-row__thumb,
        & .gc-row__photo-button--add,
        & .gc-row__replace-label {
            display: none;
        }
    }

    .generator-canvas__actions-inline {
        margin: 0;
    }

    /* — 6. output — */
    .generator-canvas__bar {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-2);
    }
}
