/*
    The sign designer.

    A separate file from app.css rather than more of it: this is the only page in the site with a
    two-column working layout, and everything below is scoped to `.designer*`. app.css stays what it
    is - the public site's small hand-written stylesheet - and nothing here can reach it.

    The palette is app.css's, unchanged, and it is drawn from the work: maple for the page, black
    epoxy for the ink, sapele for anything that has to catch the eye. The two colours added here are
    for the two things the tool has to say, and they are added because there was nothing in the
    existing palette for "this will not work".
*/

.designer {
    --designer-blocking: #a3231b; /* the error red already used by the admin notices */
    --designer-warning: #7a4f00;  /* a burnt amber that clears 4.5:1 on the maple background */
    --designer-ok: #2f6b3a;
}

/*
    The designer wants more room than the public site's 68rem measure - a form column and a 30-inch
    sign side by side do not fit in it - so it opts out of the <main> width for itself rather than
    changing the width for every page.
*/
/*
    WIDENING AN ELEMENT INSIDE A NARROWER, CENTRED PARENT NEEDS THE MARGINS TOO.

    This used to set `width: calc(100vw - 2.5rem)` and leave the margins alone. A block is laid out
    from its parent's content box, so making it wider than that parent grows it to the RIGHT ONLY —
    it does not re-centre. `main` is 68rem wide and centred; the designer asked for the viewport
    width; the difference all went off the right-hand edge.

    It looked fine on a wide monitor, where the 84rem cap happens to land inside the viewport
    anyway, and put 76 pixels of horizontal scroll on a 1280-wide laptop — which is the width
    Playwright uses, which is how it was finally caught.

    The negative margin is half the difference between the parent's width and the target, so the
    element expands symmetrically and stays centred on the viewport. No transform: `.designer-proof`
    is `position: sticky`, and a transformed ancestor becomes its containing block and would change
    how it sticks.

    The 2.5rem it holds back is what keeps a vertical scrollbar — which `100vw` includes and
    `clientWidth` does not — from turning into overflow of its own.
*/
.designer {
    width: min(84rem, calc(100vw - 2.5rem));
    max-width: none;
    margin-inline: calc((100% - min(84rem, 100vw - 2.5rem)) / 2);
}

.designer-intro {
    margin-bottom: 2rem;
}

.designer-grid {
    display: grid;
    gap: 2.5rem;
    grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
    align-items: start;
}

@media (max-width: 62rem) {
    .designer-grid {
        grid-template-columns: 1fr;
    }
}

/*
    The drawing follows the form on a phone but leads on a desktop, where there is room for it to
    stay in view while the customer types. Sticky rather than fixed: it scrolls away when the page
    genuinely runs out, instead of covering the footer.
*/
@media (min-width: 62rem) {
    .designer-proof {
        position: sticky;
        top: 1.5rem;
    }
}

/* ---------------------------------------------------------------- the sticky miniature */

/*
    Hidden by default and revealed only on narrow viewports — the opposite of how the rest of this
    file is written, and that way round deliberately. `display: none` is the safe default: with the
    rule inverted, a media query that failed to match would show a desktop TWO drawings of the same
    sign. This way the cost of a mistake is a phone losing an enhancement rather than everyone
    seeing a duplicate.

    The markup explains why this is a second element rather than a reordering: DOM order is the
    reading order, so the miniature earns its place above the steps by actually being there.
*/
.designer-minipreview {
    display: none;
}

@media (max-width: 62rem) {
    .designer-minipreview {
        display: block;
        position: sticky;
        top: 0;
        z-index: 5;

        /*
            Opaque, and this is load-bearing rather than decorative: a sticky element with a
            transparent background has the steps scroll up through the drawing, and then neither the
            sign nor the fieldset underneath it is readable.
        */
        background: var(--maple);
        border-bottom: 1px solid var(--rule);
        padding: 0.5rem 0 0.45rem;
        margin-bottom: 1.25rem;
    }

    /*
        Capped against the VIEWPORT, not given a fixed height. The miniature is competing with the
        steps for a phone screen, so the limit has to be in the same unit as the thing it competes
        with — 22vh leaves a short screen usable while still drawing a 30:9 sign large enough to
        read. The SVG's own preserveAspectRatio letterboxes it inside whatever box this leaves.
    */
    .designer-minipreview .designer-canvas {
        max-height: 22vh;
    }

    .designer-minipreview__verdict {
        margin: 0.45rem 0 0;
        font-size: 0.875rem;
        font-weight: 700;
    }

    /*
        WCAG 2.2 SC 2.4.11, Focus Not Obscured — and the miniature created this problem by solving
        another one. A sticky element pinned to the top of the viewport will happily cover the
        control the browser has just scrolled to, so a keyboard user tabbing down the form watches
        focus disappear behind the drawing. They cannot see what they are about to type into.

        scroll-margin-top on the focusable elements themselves, rather than scroll-padding-top on
        the root: this stylesheet is loaded site-wide, and reserving space at the top of every
        scroll on every page would be a global fix for one page's local problem.

        The reserve matches the miniature's own ceiling (22vh) plus its padding and border.
    */
    .designer-step input,
    .designer-step select,
    .designer-step textarea,
    .designer-step button,
    .designer-step legend {
        scroll-margin-top: calc(22vh + 2rem);
    }

    /*
        Stated here rather than inherited from .designer-verdict's modifiers, so the miniature does
        not silently lose its colour the day those rules are restructured.
    */
    .designer-minipreview__verdict.designer-verdict--blocking {
        color: var(--designer-blocking);
    }

    .designer-minipreview__verdict.designer-verdict--warning {
        color: var(--designer-warning);
    }

    .designer-minipreview__verdict.designer-verdict--ok {
        color: var(--designer-ok);
    }
}

/* ---------------------------------------------------------------- the steps */

/* ---------------------------------------------------------------- which board

    Only ever rendered for a product that is more than one object - today the cornhole pair. It sits
    above the steps because it changes what every one of them is about: reading the questions and
    then discovering which board they applied to is the wrong order.
*/

.designer-boardswitch {
    border: 1px solid var(--rule);
    border-radius: 3px;
    background: var(--maple-deep);
    padding: 0.85rem 1.1rem 0.95rem;
    margin: 0 0 1.25rem;
}

.designer-boardswitch__legend {
    font-weight: 700;
    padding-inline: 0.4rem;
}

.designer-boardswitch__hint {
    margin: 0 0 0.7rem;
    font-size: 0.9375rem;
    color: var(--ink-soft);
    max-width: 60ch;
}

.designer-boardswitch__option {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    margin-right: 1.25rem;
    /*
        The whole label is the target, not just the 13px dot. Same reason the species swatches are
        clickable through their caption.
    */
    cursor: pointer;
    padding: 0.3rem 0;
}

/*
    A visible focus ring on the label, driven by the input inside it. Without this the keyboard user
    sees the ring on a radio that is visually tiny next to the text they are actually reading.
*/
.designer-boardswitch__option:has(input:focus-visible) {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
    border-radius: 3px;
}

.designer-boardswitch__option:has(input:checked) {
    font-weight: 700;
}

.designer-step {
    border: 1px solid var(--rule);
    border-radius: 3px;
    background: #fff;
    padding: 1rem 1.1rem 1.15rem;
    margin: 0 0 1.25rem;
}

.designer-step > legend {
    font-weight: 700;
    padding-inline: 0.4rem;
}

.designer-step__number {
    display: block;
    font-size: 0.8125rem;
    font-weight: 400;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-soft);
}

/*
    A disabled fieldset is genuinely disabled - nothing inside it is focusable - so it must not look
    merely decorative. Muted and de-emphasised, but the legend stays at full contrast so the step is
    still readable as a step you have not reached yet.
*/
.designer-step:disabled {
    background: var(--maple-deep);
    opacity: 0.7;
}

.designer-step:disabled > legend {
    opacity: 1;
}

.designer-hint {
    margin: 0 0 0.9rem;
    font-size: 0.9375rem;
    color: var(--ink-soft);
    max-width: 46ch;
}

/* ---------------------------------------------------------------- choices */

.designer-choice {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 0.55rem;
    align-items: baseline;
    padding: 0.5rem 0;
    border-top: 1px solid var(--rule);
}

.designer-choice:first-of-type {
    border-top: none;
}

.designer-choice input[type="radio"] {
    /* A 16px default radio is below the 24x24 target size WCAG 2.2 SC 2.5.8 asks for; the label is
       clickable too, which carries the real target, but the control itself should not be tiny. */
    width: 1.25rem;
    height: 1.25rem;
    margin: 0;
    accent-color: var(--sapele);
}

.designer-choice label {
    font-weight: 700;
    cursor: pointer;
}

.designer-choice__hint {
    grid-column: 2;
    margin: 0.15rem 0 0;
    font-size: 0.9375rem;
    color: var(--ink-soft);
    max-width: 44ch;
}

/*
    An unavailable wood is greyed AND carries its explanation in words - the explanation is the
    entire reason it is still on the list. Never hidden: "Hard maple isn't rated for use in direct
    sun and rain" teaches a customer something about their choice; a shorter dropdown does not.
*/
.designer-choice--unavailable label {
    color: var(--ink-soft);
    font-weight: 400;
    text-decoration: line-through;
    text-decoration-thickness: 1px;
}

/* ---------------------------------------------------------------- fields */

.designer-field {
    margin-bottom: 1rem;
}

.designer-field label {
    display: block;
    font-weight: 700;
    margin-bottom: 0.25rem;
}

/*
    Not `input[type="text"]`. That selector cost an afternoon in the admin area, where Blazor's
    <InputText> renders a bare <input> with no type attribute and every styled rule missed it. These
    inputs do carry a type, but the lesson is cheap to apply.
*/
/*
    ...and not [type="checkbox"] either, which was missing and is what broke the spelling
    confirmation. A checkbox stretched to width: 100% becomes a 315-pixel-wide box with its label
    squeezed into whatever is left — 39 pixels of it, wrapping one word per line and running off the
    side of the page. Measured in the browser, not guessed: input 315px, label 39px, exactly
    inverted.

    The exclusion list is the same shape as the note above and gained an entry for the same reason.
*/
.designer-field input:not([type="hidden"]):not([type="radio"]):not([type="checkbox"]),
.designer-field select {
    width: 100%;
    padding: 0.45rem 0.55rem;
    border: 1px solid var(--ink-soft);
    border-radius: 2px;
    background: #fff;
    color: var(--ink);
    font: inherit;
    font-size: 1rem;
}

/*
    Room for the dropdown arrow, and an honest truncation when an option is still too long.

    A screenshot caught a fill option clipped mid-word with the arrow drawn on top of the remaining
    text - unreadable, and invisible to every assertion, because the element existed and its value
    was correct. That specific label is now short. This is the guard for the next one: the arrow gets
    reserved space it does not have to share, and anything that still overruns ends in an ellipsis,
    which at least reads as "there is more" rather than as a typo.

    The real fix for a long option is a shorter option; this only stops the failure being silent.
*/
.designer-field select {
    padding-right: 2rem;
    text-overflow: ellipsis;
}

/* ---------------------------------------------------------------- the drawing */

.designer-proof__heading {
    margin-bottom: 0.75rem;
}

.designer-canvas {
    display: block;
    width: 100%;
    height: auto;
    /*
        The blank's own proportions, reserved before the SVG lays out, so the page does not jump the
        first time a design is drawn. 30:9 is the family name sign; a second template would want this
        from the template rather than from CSS, which is a change to make when there is a second one.
    */
    aspect-ratio: 30 / 9;
    background: var(--maple-deep);
    border-radius: 3px;
    box-shadow: 0 1px 3px rgb(26 23 20 / 18%);
}

.designer-scale {
    margin: 0.6rem 0 1.25rem;
    font-size: 0.9375rem;
    color: var(--ink-soft);
    max-width: 60ch;
}

/* ---------------------------------------------------------------- the verdict */

.designer-verdict {
    border: 1px solid var(--rule);
    border-left-width: 4px;
    border-radius: 3px;
    background: #fff;
    padding: 0.9rem 1.1rem;
    margin-bottom: 1.5rem;
}

.designer-verdict h3 {
    font-size: 1.0625rem;
    margin-bottom: 0.5rem;
}

.designer-verdict--ok {
    border-left-color: var(--designer-ok);
}

.designer-verdict--warning {
    border-left-color: var(--designer-warning);
}

.designer-verdict--blocking {
    border-left-color: var(--designer-blocking);
}

/* ---------------------------------------------------------------- advisories */

.designer-advisories {
    list-style: none;
    margin: 0.6rem 0 0;
    padding: 0;
    display: grid;
    gap: 0.6rem;
}

.designer-advisory {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 0.6rem;
    align-items: baseline;
    padding: 0.55rem 0.7rem;
    border-radius: 2px;
    font-size: 0.9375rem;
    line-height: 1.55;
}

/*
    A block and a warning have to be told apart at a glance and without colour - one stops the order
    and the other does not. So they differ in FOUR ways: the badge text, the badge colour, the
    background tint, and a solid versus dashed left rule. Any one of those surviving on its own is
    enough to tell them apart, which is what WCAG 1.4.1 is asking for.
*/
.designer-advisory--blocking {
    background: #fdf4f3;
    border-left: 4px solid var(--designer-blocking);
}

.designer-advisory--warning {
    background: #fbf6ec;
    border-left: 4px dashed var(--designer-warning);
}

.designer-advisory__badge {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
    padding-top: 0.1rem;
}

.designer-advisory--blocking .designer-advisory__badge {
    color: var(--designer-blocking);
}

.designer-advisory--warning .designer-advisory__badge {
    color: var(--designer-warning);
}

/*
    In the 22rem form column the two-column advisory becomes a ribbon four words wide, which is
    unreadable for a message this long. Beside the drawing there is room, so the badge stays inline
    there. Same markup, same information, different measure.
*/
.designer-steps .designer-advisory {
    grid-template-columns: 1fr;
    row-gap: 0.2rem;
}

.designer-advisory__message {
    /* The message is rendered whole. It names the problem, says why in physical terms, and offers a
       way out; clipping it throws away the only part the customer can act on. */
    max-width: 62ch;
}

/* ---------------------------------------------------------------- notices and actions */

.designer-notice {
    margin: 0 0 1rem;
    padding: 0.7rem 0.9rem;
    border-left: 4px solid var(--sapele);
    background: var(--maple-deep);
    border-radius: 2px;
    max-width: none;
    font-size: 0.9375rem;
}

.designer-notice--ok {
    border-left-color: var(--designer-ok);
}

.designer-notice--warning {
    border-left-color: var(--designer-warning);
}

.designer-notice--blocking {
    border-left-color: var(--designer-blocking);
}

/* ---------------------------------------------------------------- the price */

.designer-price {
    border-top: 1px solid var(--rule);
    margin-top: 1.25rem;
    padding-top: 1rem;
}

.designer-price__total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    margin: 0 0 0.6rem;
    font-size: 1.5rem;
}

/*
    The word "Price" is deliberately quieter than the number. The number is what the customer came
    for; the label is only there so the figure is not floating unexplained, and so a screen reader
    announces what it is before saying it.
*/
.designer-price__label {
    font-size: 0.9375rem;
    font-weight: 400;
    color: var(--ink-soft);
}

.designer-price__parts {
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 0.875rem;
    color: var(--ink-soft);
}

.designer-price__parts li {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.2rem 0;
}

/*
    Tabular figures and a right edge, so the amounts form a column that can be read down and added
    up by eye. A breakdown whose numbers do not line up is one the customer cannot check, which
    defeats the reason for showing it at all — the same lesson the deposit receipt learned when its
    line items rendered as labelled settings rather than as a bill.
*/
.designer-price__amount {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.designer-actions {
    border-top: 1px solid var(--rule);
    padding-top: 1.25rem;
}

/*
    The ambient autosave line. Quiet on purpose — it is reassurance, not news, and it appears without
    the customer having asked for anything. Deliberately NOT styled as a .designer-notice: those have
    a coloured left border because each is something that happened and might need acting on, and
    borrowing that treatment for "still saved" would cry wolf several times a minute.

    --ink-soft rather than a lighter grey because this still has to clear 4.5:1 on the maple
    background. Quiet is a matter of size and weight here, not of contrast (WCAG 1.4.3).
*/
.designer-autosave {
    margin: 0.5rem 0 0;
    font-size: 0.8125rem;
    color: var(--ink-soft);
}

.designer-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-bottom: 1rem;
}

.designer-button {
    display: inline-block;
    padding: 0.55rem 1.1rem;
    border: 1px solid var(--ink);
    border-radius: 2px;
    background: #fff;
    color: var(--ink);
    font: inherit;
    font-size: 1rem;
    /* WCAG 2.2 SC 2.5.8 target size. */
    min-height: 2.75rem;
    cursor: pointer;
}

.designer-button:hover:not(:disabled) {
    border-color: var(--sapele);
}

.designer-button--primary {
    background: var(--epoxy);
    border-color: var(--epoxy);
    color: var(--maple);
}

.designer-button--danger {
    border-color: var(--designer-blocking);
    color: var(--designer-blocking);
}

/*
    A disabled "Continue to ordering" has to read as disabled without relying on colour alone, so it
    also loses its border weight and gains not-allowed. The reason it is disabled is stated in the
    verdict above it, in words - a greyed button with no explanation is the worst version of this.
*/
.designer-button:disabled {
    opacity: 0.55;
    cursor: not-allowed;
    border-style: dashed;
}

.designer-confirm {
    margin-top: 0.75rem;
    padding: 0.9rem 1rem;
    border: 1px solid var(--designer-blocking);
    border-radius: 2px;
    background: #fdf4f3;
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: center;
}

.designer-confirm p {
    margin: 0;
    flex-basis: 100%;
}

/* The spelling check. A checkbox and its label on one line, with the target
   size WCAG 2.2 asks for - this is the last thing between a customer and a
   carved mistake, so it must not be fiddly to hit on a phone. */
.designer-field--check {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    margin: 0.75rem 0 1rem;
}

/* 1.5rem = 24px, which is exactly WCAG 2.2 SC 2.5.8's minimum target size. `flex: none` stops the
   flex row stretching it, and the explicit size stops a phone rendering a checkbox the size of a
   full stop next to 17px text. */
.designer-field--check input[type="checkbox"] {
    flex: none;
    width: 1.5rem;
    height: 1.5rem;
    margin: 0;
}

/*
    The label takes the remaining width and reads as a SENTENCE, not a field name.

    `.designer-field label` is `display: block; font-weight: 700` because it labels a dropdown. Here
    the label is the whole question — "I have checked the spelling of 'X' — carve it exactly like
    that" — and bolding a paragraph of it, at 39px wide, is what the screenshot showed.
*/
.designer-field--check label {
    flex: 1;
    display: block;
    font-weight: 400;
    margin-bottom: 0;
    /* Sits optically level with the box rather than with its top edge. */
    padding-top: 0.1rem;
}

.designer-field--check input[type="checkbox"] {
    width: 1.5rem;
    height: 1.5rem;
    margin: 0;
    flex: 0 0 auto;
}

.designer-field--check label {
    font-size: 0.9375rem;
    line-height: 1.4;
}

/* Width and height side by side. They are one answer in two boxes, so they sit
   together rather than stacking like unrelated fields. */
.designer-field--pair {
    display: flex;
    gap: 1rem;
}

.designer-field--pair > div {
    flex: 1 1 0;
    min-width: 0;
}

.designer-field--pair input {
    width: 100%;
}

/* The product switcher. Only rendered when there is more than one thing to
   make - a switcher with one option is a control that does nothing. */
.designer-products {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0 0 1.5rem;
}

.designer-product {
    display: inline-block;
    padding: 0.4rem 0.9rem;
    border: 2px solid var(--rule);
    border-radius: 3px;
    text-decoration: none;
    font-weight: 700;
}

/* aria-current carries this for a screen reader; the border carries it for
   everyone else. Neither on its own is enough. */
.designer-product--current {
    border-color: var(--epoxy);
    background: var(--epoxy);
    color: var(--maple);
}
