/* Root
---------------- */

:root {
    /* Colors  */
    --white: #fff;
    --dark: #151d27;

    --text-lt: #a9aeb4;
    --text-lt-2: #8e949c;

    --blue: #3f8dee;
    --blue-lt: #a7d0ef;

    --gray: #ced4da;
    --gray-2: #dde1e5;
    --gray-3: #eff1f6;
    --gray-4: #e6e8ee;
    --gray-5: #c0c5cf;
    --gray-6: #a3acbd;
    --gray-7: #8591a8;
    --gray-8: #f7f8fa;

    --warning: #f59d59;
    --danger: #ee493f;
    --primary: #1a477f;
    --success: #6ac567;

    --danger-lt: #f6a29c;
    --success-lt: #b2e1b0;

    /* Edges

    The page is drawn edge to edge, so it owns its own margins. --gutter is
    the ordinary side margin, and --clear is what sits between the camera
    housing and the first thing in the page, on top of the band iOS already
    reserves - measured on the notch, where the logo lands closest */
    --gutter: 12px;
    --clear: 2px;

    /* Roles

    Each hue exists at two stops: a fill stop (above), which is what the hue
    looks like as a ground, and an ink stop (below), which is the same hue
    darkened until it carries as text or as an icon. Nothing that has to be
    read uses a fill stop */

    /* Surfaces */
    --surface: var(--white);
    --surface-2: var(--gray-3);
    --surface-3: var(--gray-4);
    --surface-4: var(--gray-8);

    /* Text, in three tiers - the third is the floor, and nothing goes under */
    --text: var(--dark);
    --text-2: #475166;
    --text-3: #626d83;

    /* A minor control, e.g., the edit pencil at the end of a row */
    --control: #7c8495;
    --control-hover: #515b71;

    /* What can be followed or acted on */
    --action: #196cca;
    --action-fill: var(--blue);

    /* What a record's state is - each has an ink stop and a fill stop, and
       neither is ever spent on something that is not reporting state */
    --overdue: #d02925;
    --overdue-fill: color-mix(in srgb, var(--danger) 90%, black);
    --soon: #a85700;
    --soon-fill: color-mix(in srgb, var(--warning) 75%, black);
    --settled: var(--success);

    /* The quiet fill, i.e., a call to action that only opens a form */
    --quiet-fill: #6a758c;

    /* Borders, softest to firmest */
    --border-soft: var(--gray-2);
    --border: var(--gray);
    --border-firm: var(--gray-5);

    /* Sizes
    ---------

    --tablet (max): 991.98px;
    --small-tablet (max): 767.98px;
    --mobile (max): 575.98px;

    */
}

html, body {
    font-family: 'Inter', sans-serif;
    caret-color: var(--action);
    accent-color: var(--action);
    scrollbar-color: var(--border-firm) transparent;
    font-feature-settings: 'calt', 'dlig', 'ss01', 'ss02', 'ss03';
    -webkit-font-smoothing: antialiased;
    background: var(--white);

    @supports (font-variation-settings: normal) {
        font-family: InterVariable, sans-serif;
    }
}

/* The page is at least as tall as the window, with the content taking up
   whatever is left over, so that the footer sits at the bottom of a short
   page, rather than partway up it. This is a wrapper rather than the body,
   since jQuery's show() reads an element's default display from a copy of
   it added to the body - a flex body turns that into "block", e.g., for a
   table row, which then drops out of its table's columns */
.page {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;

    > .content {
        flex: 1 0 auto;
    }
}

/* Motion
---------------- */

/* A mark being made - it arrives slightly small and settles to size, once,
   with no bounce, which is as much as a ledger should ever move */
@keyframes settle {
    from {
        transform: scale(0.82);
        opacity: 0.4;
    }

    to {
        transform: scale(1);
        opacity: 1;
    }
}

/* Focus
---------------- */

/* Bootstrap rings every control in its own blue, which is the one thing this
   interface is not allowed to look like - so the ring is restated here, in the
   colour that already means "you can act on this" */
:root {
    --bs-focus-ring-color: color-mix(in srgb, var(--action) 25%, transparent);
    --bs-focus-ring-width: 3px;
}

:focus-visible {
    outline: 2px var(--action) solid;
    outline-offset: 2px;
}

.btn:focus-visible,
.form-control:focus,
.form-check-input:focus {
    border-color: var(--action);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--action) 25%, transparent);
}

.form-control:focus {
    outline: none;
}

/* Utils
---------------- */

.clearfix::after {
    content: '';
    clear: both;
    display: table;
}

.none {
    display: none;
}

/* A label that is there to be read out, rather than seen, e.g., the name of a
   column whose heading is an icon */
.sr {
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    position: absolute;
    overflow: hidden;
    white-space: nowrap;
    clip-path: inset(50%);
}

/* Choices
---------------- */

.choices {
    margin-bottom: 0;

    /* An open dropdown is raised over the page, since it is drawn where the
       fields under it are - the file rows put their own filename over their
       input, and that would otherwise show through the list */
    &.is-open {
        z-index: 8;
    }

    .choices__inner {
        min-height: 0;
        padding: 4px 0px 0px 4px !important;

        .choices__list--multiple {
            .choices__item {
                border: 1px color-mix(in srgb, var(--blue) 90%, black) solid;
                line-height: inherit;
                color: var(--white);
                background: var(--blue);
                margin: 0 4px 2px 0;
            }

            .choices__button {
                margin: 0 0 0 6px;
                padding: 0 10px 0 12px;
                border-left: 1px color-mix(in srgb, var(--blue) 80%, black) dotted;
            }
        }

        .choices__list--single {
            /* As tall with nothing chosen as with something, so that an
               empty single select stands level with the inputs around it
               rather than shrinking to its padding */
            min-height: calc(1.5em + 8px);

            .choices__item {
                margin: 0 0 2px 0;
            }
        }
    }

    /* Option group headings stand apart from the options under them */
    .choices__heading {
        font-size: 13px;
        font-weight: 700;
        color: var(--dark);
        background: var(--gray-8);
        border-bottom: 1px var(--gray-2) solid;
    }

    select.choices__input {
        display: block !important;
        left: 0 !important;
        bottom: 0 !important;
        position: absolute !important;
        opacity: 0;
        pointer-events: none;
    }
}

/* Pagination
---------------- */

.pagination {
    --bs-pagination-color: var(--dark);
    --bs-pagination-hover-color: var(--dark);
    --bs-pagination-focus-color: var(--dark);
    --bs-pagination-active-bg: color-mix(in srgb, var(--blue) 90%, black);
    --bs-pagination-active-border-color: color-mix(in srgb, var(--blue) 90%, black);
}

/* Forms
---------------- */

form {
    .field-group,
    .form-check {
        margin: 0 0 15px 0;

        .readonly {
            font-size: 0.9375rem;
        }
    }

    .invalid-feedback,
    .valid-feedback {
        margin: 0px 0 12px 0px;
        color: var(--overdue);

        .field-group & {
            margin-top: 3px;
        }

        .form-check & {
            margin-top: 7px;
        }
    }

    /* Said of a control that is right, e.g., a password confirmation that
       matches, as it is typed */
    .valid-feedback {
        color: var(--settled);
    }

    /* A set of checkboxes in groups, e.g., the permissions a role grants,
       by feature - the widget's own markup, which is a box per group with
       its name as a label over its options, each an option with its line
       of help under it */
    .checks {
        > div {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
            gap: 18px 28px;

            > div {
                > label {
                    display: block;
                    margin: 0 0 6px 0;
                    padding: 0 0 4px 0;
                    border-bottom: 1px solid var(--border-soft);
                    font-size: 0.8125rem;
                    font-weight: 600;
                    letter-spacing: 0.02em;
                    text-transform: uppercase;
                }

                > div {
                    margin: 0 0 8px 0;

                    > label {
                        display: flex;
                        align-items: center;
                        gap: 8px;
                        margin: 0;
                        cursor: pointer;

                        .form-check-input {
                            flex: 0 0 auto;
                            margin: 0;
                        }
                    }

                    > .form-text {
                        margin: 1px 0 0 calc(1em + 8px);
                        line-height: 1.3;
                    }
                }
            }
        }
    }

    .form-control {
        border-radius: 4px;

        &::placeholder {
            color: var(--text);
            opacity: .35;
        }
    }

    .file-row-container {
        &:has(+ .file-row-container) {
            margin: 0 0 10px 0;
        }

        /* The native control is kept for what only it can do - take the
           click, the keyboard and the picker - and is otherwise unseen. It
           cannot be dressed: iOS draws a thumbnail of a chosen photo inside
           it, and nothing in CSS reaches that. So the face of the control
           is the filename, drawn over it below */
        [data-file] {
            opacity: 0;
            cursor: pointer;
        }

        /* Under the input in stacking terms, since the input is clear and
           shows it through - which leaves the remove button, and the input
           while it has focus, where Bootstrap's input group puts them. The
           corners and the margin are forced, because the group squares off
           and overlaps anything that is not its first child */
        .filename {
            position: absolute;
            inset: 0;
            margin: 0 !important;
            padding: 6px 12px 6px 121px;
            border: 1px var(--bs-border-color) solid;
            border-radius: 4px !important;
            overflow: hidden;
            line-height: 1.5;
            text-overflow: ellipsis;
            text-wrap: nowrap;
            background: var(--white);
            pointer-events: none;

            /* The button, which is drawn rather than the native one - the
               name is the browser's own wording for it. Placed rather than
               floated, so that it spans the whole height whatever padding
               centres the name beside it, and as wide as the name's room */
            &::before {
                content: 'Choose File';
                position: absolute;
                top: 0;
                bottom: 0;
                left: 0;
                width: 109px;
                display: flex;
                align-items: center;
                justify-content: center;
                border-right: 1px var(--bs-border-color) solid;
                background: var(--bs-tertiary-bg);
            }

            /* The ring the covered input would have shown, see Focus */
            [data-file]:focus-visible + & {
                border-color: var(--action);
                box-shadow: 0 0 0 3px color-mix(
                    in srgb, var(--action) 25%, transparent
                );
            }

            [data-file].invalid + & {
                border-color: var(--danger);
                background: var(--danger-lt);
            }

            [data-has-verified-file] & {
                border-color: var(--success);
                background: var(--success-lt);
            }

            /* Short of the remove button, once there is one, so that a long
               name is cut off before it rather than under it */
            .file-row:has([data-remove]:not(.none)) & {
                padding-right: 50px;
            }
        }
    }

    .formset {
        margin: 0 0 15px 0;

        /* Dragging only means something where the order is read, so the
           handles are offered on a formset that says it is sorted and on no
           other - see the sortable option of jquery.formsy.js */
        &:not(.sortable) .handle {
            display: none;
        }

        .headline {
            margin: 0 0 10px 0;
            font-size: 1.2rem;
            font-weight: 500;
        }

        .inlines {
            .inline {
                margin: 0 0 15px 0;
                padding: 15px;
                border-radius: 3px;
                background: var(--gray-4);
                position: relative;

                label strong {
                    font-weight: 600;
                }

                .controls {
                    .control {
                        float: right;
                    }
                }
            }

            /* What an inline is dragged by - the rest of it is left alone,
               so its inputs still take a cursor and select text. It fills
               the corner out to both edges, taking the inline's own radius
               where it meets them, so it reads as part of the box rather
               than as something sitting on top of it */
            .handle {
                position: absolute;
                top: 0;
                right: 0;
                padding: 8px;
                color: var(--text-2);
                background: var(--gray-5);
                border-radius: 0 3px 0 8px;
                cursor: grab;
                line-height: 1;

                &:hover {
                    color: var(--text);
                    background: var(--gray-6);
                }

                &:active {
                    cursor: grabbing;
                }
            }

            /* One inline has nowhere to go, so it is not offered a handle */
            &:has(.inline:only-child) .handle {
                display: none;
            }

            /* The inline being dragged, which is left in place and faded,
               so that the list does not reflow under the cursor */
            .inline.dragging {
                opacity: .4;
            }

            /* Somewhere the dragged inline can go. Every gap but the two it
               already sits between opens one, so what is offered is only
               ever a move */
            .drop {
                height: 42px;
                margin: 0 0 15px 0;
                border-radius: 4px;
                background: color-mix(in srgb, var(--action) 14%, white);
                transition: background 120ms ease-out;

                /* Under the cursor, and so the one a release would take */
                &.over {
                    background: color-mix(in srgb, var(--action) 30%, white);
                }
            }
        }

        > .controls {
            float: right;

            .control {
                float: left;

                &:not(:last-child) {
                    margin: 0 10px 0 0;
                }

                .btn.secondary {
                    opacity: .75;
                }
            }
        }
    }
}

/* Container
---------------- */

/* The page covers the display edge to edge (viewport-fit=cover), so the
   gutter, not iOS, decides where the side edge is - the band iOS reserves
   around the camera housing lands a hair tight against the logo, so --clear
   is added to it, and the result is floored at --gutter, which is what
   portrait and every desktop width keep using */
.container {
    max-width: 1170px;
    padding-left: max(
        var(--gutter), calc(env(safe-area-inset-left) + var(--clear))
    );
    padding-right: max(
        var(--gutter), calc(env(safe-area-inset-right) + var(--clear))
    );
}

/* Header
---------------- */

header {
    background: var(--dark);
    padding-top: env(safe-area-inset-top);

    .logo {
        float: left;

        a {
            width: 126px;
            height: 22px;
            margin: 13px 0;
            float: left;
            text-indent: -9000px;
            background: transparent url("../svg/logo.d45215abc8fe.svg") left top no-repeat;
            opacity: 0.85;

            &:hover {
                opacity: 1;
            }
        }
    }

    > .container > menu {
        margin: 0;
        padding: 0;
        float: right;

        > li {
            margin: 7px 0;
            float: left;
            font-size: 0.875rem;
            line-height: 1;
            list-style: none;

            &:not(:last-child) {
                margin-right: 10px;
            }

            > a {
                padding: 10px;
                border-radius: 4px;
                float: left;
                text-decoration: none;
                color: var(--gray-3);

                &:hover {
                    background: rgba(255, 255, 255, .05);
                }

                @media (max-width: 767.98px) {
                    padding: 10px 15px;
                }

                .active & {
                    color: var(--white);
                    background: rgba(255, 255, 255, .15);
                }

                &:not(.dropdown-trigger) > .icon {
                    margin: 0 7px 0 0;

                    @media (max-width: 767.98px) {
                        margin: 0;
                    }
                }

                > strong {
                    font-weight: normal;

                    @media (max-width: 767.98px) {
                        display: none;
                    }
                }
            }
        }
    }
}

/* Main Menu
---------------- */

nav.main {
    background: var(--primary);

    > .container > menu {
        margin: 0;
        padding: 0;
        float: left;

        &:empty {
            height: 5px;
        }

        > li {
            margin: 7px 0 0 0;
            float: left;
            font-size: 0.875rem;
            line-height: 1;
            list-style: none;

            &:not(:last-child) {
                margin-right: 5px;
            }

            > a {
                padding: 11px 10px 10px 10px;
                border-top-right-radius: 4px;
                border-top-left-radius: 4px;
                float: left;
                text-decoration: none;
                color: var(--white);
                background: rgba(255, 255, 255, .04);

                &:hover {
                    background: rgba(255, 255, 255, .10);
                }

                .active & {
                    color: var(--dark);
                    background: var(--white);

                    .extra & {
                        border-left: 4px var(--gray) solid;
                    }
                }

                /* An item collapses to its icon on a phone where the menu has
                   an extra item, e.g., the client open, and on the smallest
                   phones unless it is the active one - the extra item never
                   does */
                @media (max-width: 767.98px) {
                    &:not(.extra &):is(:has(.extra) &) {
                        padding: 11px 13px 10px 13px;
                    }
                }

                @media (max-width: 575.98px) {
                    &:not(.extra &):not(.active &) {
                        padding: 11px 13px 10px 13px;
                    }
                }

                .icon {
                    + strong {
                        margin: 0 0 0 7px;
                        font-weight: normal;

                        &:not(.extra &):is(:has(.extra) &) {
                            @media (max-width: 767.98px) {
                                display: none;
                            }
                        }

                        &:not(.extra &):not(.active &) {
                            @media (max-width: 575.98px) {
                                display: none;
                            }
                        }
                    }

                    /* On the navy bar, state takes its fill stop rather
                       than its ink stop - the ink stops are cut to carry on
                       white, and would go to mud here */
                    &.success {
                        color: var(--success);
                    }
                }
            }
        }
    }
}

/* Submenu
---------------- */

nav.sub {
    background: linear-gradient(var(--white), var(--gray-3));
    border-bottom: 1px var(--gray) solid;

    > .container > menu {
        margin: 0;
        padding: 0;
        float: left;

        &:empty {
            height: 5px;
        }

        > li {
            margin: 7px 0;
            float: left;
            font-size: 0.875rem;
            line-height: 1;
            list-style: none;

            &:not(:last-child) {
                margin-right: 5px;
            }

            > a {
                padding: 7px 10px;
                border-radius: 3px;
                float: left;
                text-decoration: none;
                color: var(--dark);

                &:hover {
                    background: color-mix(in srgb, var(--dark) 5%, transparent);
                }

                .active & {
                    background: color-mix(in srgb, var(--dark) 15%, transparent);
                }

                /* An item's icon stands in for its label on a phone, where
                   the labels would not fit on one line */
                &:not(.dropdown-trigger) > .icon {
                    display: none;

                    @media (max-width: 767.98px) {
                        display: inline-block;
                    }
                }

                > strong {
                    font-weight: normal;

                    @media (max-width: 767.98px) {
                        display: none;
                    }
                }
            }
        }
    }
}

/* Crumbs
---------------- */

/* The way back up from a page that has no tab of its own, e.g., adding a
   task, to the page whose tab it is under */
nav.crumbs {
    margin: 0 0 12px 0;
    font-size: 0.8125rem;
    color: var(--text-3);

    a {
        color: var(--text-2);
    }

    .icon {
        margin: 0 4px;
        font-size: 0.6875rem;
    }
}

/* Dropdowns
---------------- */

menu.dropdown-menu > li {
    font-size: 0.875rem;

    .dropdown-item {
        padding: 7px 16px;
    }

    .dropdown-header .icon,
    .dropdown-item > .icon {
        display: inline-block;
        margin: 0 7px 0 0;

        /* Matches the same item in the main menu, e.g., "Add Client" */
        &.success {
            color: var(--success);
        }
    }
}

/* A dropdown for adding to a list, which makes something new, or else
   finds something there already, e.g., a contact for a client */
menu.dropdown-menu.adding {
    /* As wide as the select and its button, and no wider, since nothing
       above them needs the room */
    width: max-content;
    max-width: calc(100vw - 32px);

    .existing p {
        margin: 0 0 8px 0;
        padding: 0 16px;
        color: var(--text-2);
    }

    .adder {
        padding: 0 16px 8px 16px;

        /* Wide enough for a full name, and gives way on a phone */
        .choices {
            flex: 0 1 auto;
            width: 256px;
            min-width: 0;
        }

        /* The select's "Press to select" hint, which takes room the names
           need in a list this narrow, where clicking one is obvious anyway */
        .choices__list--dropdown .choices__item--selectable {
            padding-right: 10px;

            &::after {
                display: none;
            }
        }
    }
}

/* Confirmation
---------------- */

.popover.confirmation {
    border-color: var(--gray-5);
    box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.1);

    .popover-header {
        padding: 9px 14px;
        border-bottom-color: var(--gray-4);
        font-size: 0.8125rem;
        font-weight: 500;
        background: var(--gray-3);

        /* The people a reminder would reach, each with when they were last
           written to */
        ul {
            margin: 6px 0 0 0;
            padding: 0 0 0 16px;
            font-weight: normal;

            small {
                margin: 0 0 0 3px;
                color: var(--text-3);
            }
        }
    }

    .popover-body {
        padding: 10px 14px;
        text-align: right;
        white-space: nowrap;

        .btn {
            padding: 3px 14px !important;
            font-size: 0.8125rem;

            &.cancel {
                margin: 0 0 0 5px;
            }
        }
    }
}

/* Message
---------------- */

.message {
    /* The hue the message is drawn in, named once so that the edge and the
       control that dismisses it cannot drift apart. The fallback is what a
       message with no level of its own gets */
    --edge: var(--gray);

    position: relative;
    margin: 20px 0;

    /* Room on the right for the control that dismisses it, which is a
       fixed-width icon in 15px of padding either side */
    padding: 15px 48px 15px 20px;
    border: 1px solid var(--edge);
    border-radius: 4px;

    &.secondary {
        background: color-mix(in srgb, var(--gray) 25%, transparent);
    }

    &.success {
        --edge: var(--success);

        background: color-mix(in srgb, var(--success) 25%, transparent);
    }

    &.info {
        --edge: var(--blue);

        background: color-mix(in srgb, var(--blue) 10%, transparent);
    }

    &.warning {
        --edge: var(--warning);

        background: color-mix(in srgb, var(--warning) 10%, transparent);
    }

    &.danger {
        --edge: var(--danger);

        background: color-mix(in srgb, var(--danger) 10%, transparent);
    }

    /* Drawn in the message's own hue, in the corner, out of the flow of the
       words so that a long message reads the same as a short one */
    .dismiss {
        position: absolute;
        top: 0;
        right: 0;
        padding: 13px 15px;
        border: 0;
        background: none;
        color: var(--edge);
        line-height: 1;
        opacity: 0.7;

        &:hover,
        &:focus {
            opacity: 1;
        }
    }
}

/* Noted
---------------- */

/* A message noted by an action, e.g., an Ajax response - it floats, since the
   action that raised it can be taken anywhere down the page */
.message.noted {
    position: fixed;
    top: calc(20px + env(safe-area-inset-top));
    right: calc(20px + env(safe-area-inset-right));
    z-index: 1090;
    max-width: 360px;
    margin: 0;
    cursor: pointer;
    background: var(--white);
    box-shadow: 1px 1px 6px 0 rgba(0, 0, 0, 0.15);

    &.success {
        background: color-mix(in srgb, var(--success) 25%, white);
    }

    &.danger {
        background: color-mix(in srgb, var(--danger) 10%, white);
    }

    @media (max-width: 575.98px) {
        top: calc(10px + env(safe-area-inset-top));
        right: calc(10px + env(safe-area-inset-right));
        left: calc(10px + env(safe-area-inset-left));
        max-width: none;
    }
}

/* HR
---------------- */

hr {
    border-color: var(--gray-5);
    color: var(--gray-5);
}

/* Button
---------------- */

.btn {
    padding: 6px 18px !important;
    border-radius: 3px;
    font-size: 0.875rem;

    .icon.inline {
        margin: 5px;
    }

    &.small {
        padding: 3px 12px !important;
        font-size: 0.8125rem;
    }

    &[type="submit"] {
        margin: 5px 0 0 0;
    }

    &.adjacent,
    &.cancel {
        margin: 5px 0 0 5px;
    }

    &.primary {
        border-color: var(--primary);
        color: var(--white);
        font-weight: 500;
        background: color-mix(in srgb, var(--primary) 90%, white);

        &:hover {
            border-color: color-mix(in srgb, var(--primary) 95%, black);
            background: color-mix(in srgb, var(--primary) 95%, white);
        }

        &:active {
            color: var(--white);
            border-color: color-mix(in srgb, var(--primary) 90%, black);
            background: var(--primary);
        }
    }

    &.secondary {
        border-color: color-mix(in srgb, var(--quiet-fill) 90%, black);
        color: var(--white);
        font-weight: 500;
        background: var(--quiet-fill);

        &:hover {
            border-color: color-mix(in srgb, var(--quiet-fill) 85%, black);
            background: color-mix(in srgb, var(--quiet-fill) 90%, black);
        }

        &:active {
            border-color: color-mix(in srgb, var(--quiet-fill) 80%, black);
            color: var(--white);
            background: color-mix(in srgb, var(--quiet-fill) 85%, black);
        }
    }

    &.success {
        border-color: color-mix(in srgb, var(--success) 90%, black);
        color: var(--white);
        font-weight: 500;
        background: var(--success);

        &:hover {
            border-color: color-mix(in srgb, var(--success) 85%, black);
            background: color-mix(in srgb, var(--success) 90%, black);
        }

        &:active {
            border-color: color-mix(in srgb, var(--success) 80%, black);
            color: var(--white);
            background: color-mix(in srgb, var(--success) 85%, black);
        }
    }

    &.danger {
        border-color: color-mix(in srgb, var(--overdue-fill) 90%, black);
        color: var(--white);
        font-weight: 500;
        background: var(--overdue-fill);

        &:hover {
            border-color: color-mix(in srgb, var(--overdue-fill) 85%, black);
            background: color-mix(in srgb, var(--overdue-fill) 90%, black);
        }

        &:active {
            border-color: color-mix(in srgb, var(--overdue-fill) 80%, black);
            color: var(--white);
            background: color-mix(in srgb, var(--overdue-fill) 85%, black);
        }
    }

    &.link {
        color: var(--text-3);
        text-decoration: none;
        font-weight: 300;

        &:hover {
            color: var(--text);
            text-decoration: underline;
        }
    }
}

/* Footer
---------------- */

/* The foot of every page, in the header's color - who the app belongs to,
   and the documents it is used under. It runs under the home indicator, and
   pads itself clear of it, so the blue reaches the bottom edge */
footer {
    min-height: 96px;
    padding: 30px 0 calc(30px + env(safe-area-inset-bottom)) 0;
    font-size: 0.8125rem;
    color: rgba(255, 255, 255, .6);
    background: var(--dark);

    .copyright {
        margin: 0;
        float: left;
    }

    menu {
        margin: 0;
        padding: 0;
        float: right;

        li {
            display: inline;
            list-style: none;

            &:not(:last-child) {
                margin-right: 20px;
            }
        }
    }

    a {
        text-decoration: none;
        color: rgba(255, 255, 255, .85);

        &:hover {
            text-decoration: underline;
            color: var(--white);
        }
    }

    /* Stacked on a phone, rather than squeezed onto one line */
    @media (max-width: 575.98px) {
        .copyright,
        menu {
            float: none;
        }

        menu {
            margin: 12px 0 0 0;
        }
    }
}

/* Section
---------------- */

.section {
    margin: 15px 0 0 0;
}

/* Content
---------------- */

.content {
    font-size: 0.9375rem;

    /* Room under the last thing on the page, so that a button at the foot
       of a form is never left pressed against the bottom edge - on a phone,
       that edge is the browser's own toolbar, drawn over the page */
    padding: 0 0 60px 0;

    ::selection {
        color: var(--dark);
        background: var(--blue-lt);
    }

    a {
        text-decoration: none;

        &:hover:not(.btn):not(.dropdown-item):not(.list-toggle) {
            text-decoration: underline;
        }
    }

    /* A minor control, e.g., edit, archive, etc., as a link or a submit */
    .control {
        color: var(--control);

        &:hover {
            color: var(--control-hover);
        }

        &:not(:last-child) {
            margin: 0 10px 0 0;
        }
    }

    button.control {
        padding: 0;
        border: 0;
        line-height: 1;
        cursor: pointer;
        background: none;
    }

    h1, h2, h3, h4, h5, h6 {
        margin: 0;

        .subtitle {
            margin: 0 0 0 4px;
            font-weight: 200;
            font-size: 1rem;

            &::before {
                content: '/ ';
            }
        }
    }

    h1 {
        font-size: 1.375rem;
        font-weight: 400;

        @media (max-width: 767.98px) {
            font-size: 1.25rem;
        }
    }

    h2 {
        margin: 20px 0 0 0;
        font-size: 1.125rem;
        font-weight: 500;

        @media (max-width: 767.98px) {
            font-size: 1.0625rem;
        }
    }

    h3 {
        margin: 2px 0 10px 0;
        font-size: 0.9375rem;
        font-weight: 700;
    }

    .headings {
        .info {
            float: left;

            @media (max-width: 575.98px) {
                float: none;
            }
        }

        .ctas {
            float: right;

            @media (max-width: 575.98px) {
                margin: 15px 0 5px 0;
                float: none;
            }

            /* A cta that acts, rather than links, comes wrapped in its form,
               which floats in its place, leaving the cta itself to shrink the
               form around it */
            form {
                float: left;

                &:not(:last-child) {
                    margin: 0 10px 0 0;
                }

                .cta {
                    float: none;
                }
            }

            .cta {
                float: left;

                @media (max-width: 575.98px) {
                    padding: 4px 16px !important;
                }

                &:not(:last-child) {
                    margin: 0 10px 0 0;
                }

                .icon:first-child {
                    margin: 0 7px 0 -2px;
                }

                .icon.closing {
                    margin: 0 -2px 0 7px;
                }
            }
        }
    }

    .text-success {
        color: var(--settled) !important;
    }

    .text-danger {
        color: var(--overdue) !important;
    }

    .subinfo {
        margin: 5px 0 0 0;

        /* The record a line names, set apart from the words around it - at a
           weight of its own, since the browser's bold would shout it */
        strong {
            font-weight: 500;
        }

        &.deep {
            margin: 15px 0 0 0;
        }
    }

    .subtle {
        color: var(--text-3);

        &:not(.icon) {
            font-weight: 300;
        }

        &.smaller {
            font-size: 0.8125rem;
        }
    }

    .before {
        margin: 0 7px 0 0;
    }

    .after {
        margin: 0 0 0 5px;
    }

    .lighter {
        color: var(--text-3);
    }

    .datum {
        margin: 0 0 10px 0;

        .icon:first-child {
            margin: 0 5px 0 0;
        }
    }

    address {
        margin: 10px 0 0 0;
        line-height: 1.214;

        .line {
            margin: 5px 0 0 0;
        }
    }
}

/* Shell
---------------- */

.shell {
    margin-top: 15px;
    padding: 17px 20px 20px 20px;
    border-radius: 4px;
    background: var(--gray-3);
    box-shadow: 1px 1px 0 0 rgba(0, 0, 0, 0.08);

    &.invalid {
        border-top: 5px var(--danger) solid;
    }

    &.kard {
        .action {
            margin: 0 0 0 10px;
            float: right;
            font-size: 0.8125rem;
            text-decoration: none;
            font-weight: 200;
            color: var(--text-3);

            &:hover {
                color: var(--text);
                text-decoration: underline;
            }
        }
    }

    &.less {
        background: color-mix(in srgb, var(--gray-3) 50%, white);
    }

    .minor {
        font-size: 0.875rem;

        .icon {
            font-size: 0.75rem;
        }
    }

    /* What a button unfolds under itself, e.g., how to close the account -
       hidden until the button is pressed */
    .unfolds {
        display: none;
        margin: 12px 0 0 0;
    }

    .last {
        margin-bottom: 0;
    }
}

/* Sheet
---------------- */

/* A form laid out as panels, e.g., an invitation's who and access side by
   side - a faint wrap standing off the panels, with the buttons under them
   and inside it, so that they belong to the whole and to neither panel */
.sheet {
    margin-top: 15px;
    padding: 12px;
    border: 1px solid var(--border-soft);
    border-radius: 8px;

    &.invalid {
        border-color: var(--danger);
    }

    .row {
        row-gap: 12px;
    }

    .shell {
        height: 100%;
        margin-top: 0;
    }

    .actions {
        margin: 12px 0 0 0;
        padding: 0 8px 0 8px;
    }
}

/* Standing
---------------- */

/* What is outstanding under a record, said in the line under its name, so that
   the first thing read is the answer to why the page was opened */
.subinfo.standing {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 16px;
    font-size: 0.8125rem;

    > a,
    > span {
        color: var(--text-3);
        text-decoration: none;

        .icon {
            margin: 0 5px 0 0;
            font-size: 0.75rem;
        }
    }

    > a:hover {
        color: var(--text);
        text-decoration: underline;
    }

    /* The two segments that report state take their state's ink */
    > .due {
        color: var(--soon);
    }

    > .waiting {
        color: var(--soon);
    }

    > .clear .icon {
        color: var(--settled);
    }
}

/* A panel of what is standing, e.g., the contacts who can be messaged under
   a client - each row is one thing, and nothing else */
.standing-panel {
    .standing-row {
        margin: 0 0 7px 0;
        font-size: 0.875rem;
        line-height: 1.3;

        &:last-child {
            margin: 0;
        }

        > .icon {
            margin: 0 6px 0 0;
            color: var(--control);

            /* How a recently finished one ended, in the same colours as the
               e-sign list */
            &.settled {
                color: var(--settled);
            }

            &.stopped {
                color: var(--text-3);
            }

            &.failed {
                color: var(--overdue);
            }
        }

        /* How long it has stood, pushed to the far end so that it reads as
           its own column rather than as the tail of the name next to it */
        .since {
            float: right;
            margin: 0 0 0 8px;
            color: var(--text-3);
            font-size: 0.8125rem;
            font-weight: 300;
        }
    }

    .datum.last {
        font-size: 0.875rem;
    }
}

/* The heading over the column beside the main list, which names the column as
   a region of its own rather than leaving it under the last heading */
h2.rail {
    margin-top: 0;
}

/* Who a message is about to go to, said above the button that sends it */
.recipients {
    margin: 20px 0 15px 0;
    padding: 10px 14px;
    border-left: 3px var(--action) solid;
    border-radius: 3px;
    font-size: 0.875rem;
    background: color-mix(in srgb, var(--action) 8%, white);

    .icon {
        margin: 0 8px 0 0;
        color: var(--action);

        &.failed {
            color: var(--overdue);
        }
    }
}

/* Nobody to reach, e.g., a message form for a client with no active contacts */
.recipients.none-to-reach {
    border-left-color: var(--overdue);
    background: color-mix(in srgb, var(--danger) 8%, white);

    .icon {
        color: var(--overdue);
    }
}

/* Preview
---------------- */

/* A preview of what a form's input amounts to, e.g., when a schedule is next
   due - hidden until there is enough filled in to tell */
.preview {
    display: none;
    margin: 20px 0 5px 0;
    padding: 12px 15px;
    border-left: 3px var(--action) solid;
    border-radius: 3px;
    background: color-mix(in srgb, var(--action) 8%, white);

    .schedule {
        font-weight: 500;

        .icon {
            margin: 0 8px 0 0;
            color: var(--action);
        }
    }

    .next {
        margin: 6px 0 0 0;
        font-size: 0.875rem;
        color: var(--text-3);
    }
}

/* Cleared
---------------- */

/* A record with nothing outstanding under it - the state the work is aimed
   at, so it is marked as reached rather than reported as missing */
.subinfo.cleared {
    font-size: 0.9375rem;
    color: var(--text-2);

    .icon {
        margin: 0 8px 0 0;
        color: var(--settled);
    }
}

/* Figures
---------------- */

/* Wherever figures are stacked - a column of due dates, the timestamps beside
   them, the details on a record - they are set in tabular numerals, so the
   digits align down the column instead of shuffling by glyph width. Only the
   figures: proportional text keeps its own spacing, since tabular digits pad
   the characters between them, e.g., the hyphen in "1099-NEC" */
.listable td.due,
.listable .subtle,
.subinfo.standing,
.standing-panel .since,
.content .datum,
.content address {
    font-variant-numeric: tabular-nums;
}

/* Listable
---------------- */

.list-buttons {
    float: right;

    @media (max-width: 575.98px) {
        margin: 15px 0 5px 0;
        float: none;
    }
}

/* A switch that stands for what the page is showing, e.g., a list that
   includes what has been completed - it takes no input of its own, so that it
   only ever reads as on as the page it arrived with, and is a link, so that
   the page it means is the one that turns it */
.list-toggle {
    margin: 20px 0 -10px 0;
    display: inline-block;

    /* A second switch beside the first, e.g., a list of tasks that widens to
       what was completed, and to what was put away */
    & + .list-toggle {
        margin-left: 20px;
    }

    .form-check {
        margin: 0;

        /* The switch is inert, since the link around it does the turning, so
           it is kept from reading as the disabled control that it is */
        .form-check-input:disabled {
            opacity: 1;
            filter: none;
            cursor: pointer;

            &:checked {
                border-color: var(--quiet-fill);
                background-color: var(--quiet-fill);
            }

            ~ .form-check-label {
                opacity: 1;
                color: var(--text-3);
                font-size: 0.875rem;
                font-weight: 300;
                cursor: pointer;
            }
        }
    }
}

.listable {
    margin: 20px 0 0 0;
    overflow-x: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--border-firm) transparent;

    > table:not(:has(tbody tr)) {
        display: none;
    }

    > table {
        min-width: 480px;
    }

    /* On a phone the summary row has already dropped two of its columns,
       so there is no longer 480px of anything to hold apart - and what a
       row expands into is a stack of blocks that would rather have the
       width than scroll sideways for it */
    @media (max-width: 575px) {
        > table {
            min-width: 0;
        }
    }

    table tbody td.attachments {
        color: var(--text-3);
    }

    /* What a row expands into - a task's description, a signature request's
       signers and history. Hidden until the row above it is clicked, which is
       common.js's doing, so it starts closed rather than opening on load */
    tr.details {
        display: none;

        .wrap {
            padding: 15px 20px;
            border-radius: 3px;
            color: var(--text-2);
            background: var(--surface-2);
        }

        /* What each block below is. A list of names, a list of things that
           happened and a list of files look alike without one - and a rule
           above each keeps them from running into one another */
        h4 {
            margin: 18px 0 8px 0;
            padding-top: 14px;
            border-top: 1px solid var(--gray-4);
            font-size: 0.6875rem;
            font-weight: 600;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            color: var(--text-3);

            &:first-child {
                margin-top: 0;
                padding-top: 0;
                border-top: 0;
            }
        }
    }

    .cs-box {
        display: block;
        margin-top: -5px;

        .cs {
            float: left;
            margin-top: 5px;
            padding: 2px 7px;
            border-radius: 2px;
            cursor: default;

            &:not(:last-child) {
                margin-right: 5px;
            }

            &.primary {
                color: var(--white);
                background: var(--primary);
            }

            &.secondary {
                color: var(--dark);
                background: var(--gray-3);
            }
        }
    }

    tr.inactive > td {
        color: var(--text-2);
        background: var(--surface-4);
    }

    /* A cell of controls, e.g., edit, archive, deactivate, etc. */
    td.controls {
        white-space: nowrap;

        /* A control that submits is wrapped in its own form, which makes it
           the only child of that form and therefore always :last-child - so
           the gap that .control keeps between itself and the next one never
           applies to it. The form keeps the gap on its behalf */
        form {
            display: inline-block;

            &:not(:last-child) {
                margin: 0 10px 0 0;
            }
        }

        /* A mark that stands among the controls without being one, e.g., a
           lock, or an invitation's expiry, keeps the same gap they do */
        > .icon:not(:last-child) {
            margin: 0 10px 0 0;
        }
    }

    /* Controls that only apply while the row is not inactive, e.g., editing
       a task that has since been completed */
    tr.inactive .editable {
        display: none;
    }

    /* A row the URL's fragment names, e.g., a message that was linked to from
       a dashboard, which is marked, so that it can be picked out */
    tr:target > td {
        background: color-mix(in srgb, var(--action) 10%, white);
    }
}

/* A list under a heading of its own, e.g., the tasks due under one client, on
   a dashboard that covers them all */
.grouping {
    margin: 20px 0 0 0;

    h3 {
        margin: 0;

        /* The client the group is under reads as the heading it is, rather
           than as one more link among the list beneath it */
        a {
            color: var(--dark);
        }

        .icon {
            font-size: 0.8125rem;
        }
    }

    .listable {
        margin: 10px 0 0 0;
    }
}

/* A link out of a shortened list, e.g., to all that is due under a client,
   where a dashboard shows only the next few - it is kept quiet, so that it
   trails the list without competing with anything in it */
.trailing {
    margin: 0;
    font-size: 0.8125rem;
    font-weight: 300;

    a {
        color: var(--text-3);

        &:hover {
            color: var(--text);
        }
    }
}

/* A form for adding to a list, e.g., a contact to a client, by choosing
   from a select, with the button that adds beside it */
.adder {
    display: flex;
    gap: 10px;

    .choices {
        flex: 1;
    }

    /* Level with the select, rather than pushed down by the gap a submit
       button keeps under the field above it */
    .btn[type="submit"] {
        margin: 0;
    }
}

/* Grants
---------------- */

/* What a role grants an account user under one client, said as a mark per
   permission, e.g., "Tasks Complete", in the list of their clients */
.grants {
    .grant {
        display: inline-block;
        margin: 0 6px 4px 0;
        padding: 1px 7px;
        border-radius: 4px;
        background: var(--gray-2);
        font-size: 0.8125rem;
        white-space: nowrap;
    }
}

/* Users
---------------- */

/* The users list and the invitations under it share column widths, so that
   the clients of each line up - an invitation has no phone, so its email
   takes the width of both */
.listable.admins,
.listable.invites {
    th.name {
        width: 35%;
    }

    th.email {
        width: 25%;
    }

    th.phone,
    th.clients {
        width: 15%;
    }
}

.listable.invites {
    th.email {
        width: 40%;
    }

    /* Without the email column, the name takes its width as well, which
       leaves both lists with the same proportions as each other */
    @media (max-width: 767px) {
        th.name {
            width: 50%;
        }
    }

    /* The control that renews an invitation says, by its colour, that the
       invitation has lapsed, or is about to */
    tr.expiring .control.renew {
        color: var(--warning);
    }

    tr.inactive .control.renew {
        color: var(--danger);
    }
}

/* Dashboard
---------------- */

/* The account dashboard is the one page that reports across every client at
   once, so its two sections are bounded rather than running together as one
   unbroken column of rows - each heading takes a rule, and more air above it
   than below, so that the page reads as two regions before it reads as rows */
.dash {
    h2 {
        margin: 32px 0 0 0;
        padding: 0 0 6px 0;
        border-bottom: 1px var(--border-soft) solid;
    }

    .listable {
        margin: 12px 0 0 0;
    }

    > .subinfo {
        margin: 12px 0 0 0;
    }
}

/* One client's tasks, requests, etc. within the list that covers them all,
   e.g., on the dashboard - the client is said as a band across the list,
   rather than as a heading over a table of its own, so that the columns stay
   aligned the whole way down the page and the header is stated once instead
   of once per client */
.listable.grouped {
    tbody:not(:first-of-type) tr.group > td {
        border-top: 1px var(--border-soft) solid;
    }

    tr.group {
        border-radius: 5px;

        &> td {
            padding: 8px 8px 7px 8px;
            background: var(--surface-2);
            border-radius: 2px;

            /* The client reads as the heading it is, rather than as one more link
               among the rows beneath it */
            .client {
                font-weight: 700;
                color: var(--dark);
            }

            /* How much is due under the client, trailing the name it belongs to -
               it is a link only when there is more than the list is showing */
            .count {
                float: right;
                margin: 2px 0 0 0;
                font-size: 0.8125rem;
                font-weight: 300;
                color: var(--text-3);
                font-variant-numeric: tabular-nums;
            }

            a.count:hover {
                color: var(--text);
            }
        }
    }
}

/* Tasks
---------------- */

.tasks {
    td.check {
        width: 1%;

        .check:hover {
            color: var(--settled);
        }

        /* Larger than the other controls, since it is what a task is acted
           on by, and is tapped rather than clicked on a phone */
        .check .icon {
            font-size: 1.25rem;
            vertical-align: middle;

            @media (max-width: 575.98px) {
                font-size: 1.5rem;
            }
        }
    }

    /* A task that has been completed reads as settled, rather than staying
       the same grey as the control that completed it */
    tr.inactive td.check .check {
        color: var(--settled);
    }

    /* Releasing a due date from its state, and marking a task done, are the
       two things worth seeing happen rather than finding already done - so
       the colour eases out, and the mark settles in. The completed list is
       excluded, since its rows arrive already done */
    td.due,
    td.check .icon {
        transition: color 240ms cubic-bezier(0.16, 1, 0.3, 1);
    }

    @media (prefers-reduced-motion: no-preference) {
        .listable.tasks:not(.completed) tr.inactive td.check .icon {
            animation: settle 260ms cubic-bezier(0.16, 1, 0.3, 1) both;
        }
    }

    /* Marks a task that a routine scheduled, so it is left narrow, and only
       filled in for the tasks that came from one */
    .origin {
        width: 1%;
        color: var(--control);

        @media (max-width: 575.98px) {
            display: none;
        }
    }

    /* What is late, and what is about to be - a routine's whole point is that
       the next one is seen before it is missed, so the week ahead is coloured
       too, one step short of overdue */
    td.due {
        white-space: nowrap;
    }

    /* How far off the date is, said in words beside it, so that lateness is
       read rather than worked out - it keeps whichever state ink the date is
       in, and drops to the light weight everything secondary takes. It is the
       first thing the column sheds when the page narrows */
    td.due .lateness {
        margin: 0 0 0 10px;
        font-size: 0.8125rem;
        font-weight: 300;
        font-variant-numeric: normal;

        @media (max-width: 991.98px) {
            display: none;
        }
    }

    tr.overdue td.due {
        color: var(--overdue);
        font-weight: 500;

        .icon {
            font-size: 0.8125rem;
        }
    }

    /* A completed task keeps whichever state its due date was in, so that
       the colour has something to ease out of - this is what it eases to */
    tr.inactive.overdue td.due,
    tr.inactive.soon td.due {
        color: var(--text-2);
        font-weight: normal;
    }

    tr.soon td.due {
        color: var(--soon);

        .icon {
            font-size: 0.8125rem;
        }
    }

    /* The date said as a calendar on a phone, in whichever state ink the
       date would be in, with the date itself in its tooltip - full size,
       rather than the small mark that sits beside a date */
    tr td.due .icon.when {
        font-size: 1rem;
    }

}

/* Comms
---------------- */

/* The attachment mark folded under the direction arrow, where the list is
   too narrow to give it a column of its own - see the message lists */
td.direction .attached {
    display: block;
    margin: 6px 0 0 0;
    color: var(--text-3);
}

/* Marks an inbound message that has been replied to, so it is left narrow,
   and only filled in for the ones that are owed nothing further */
td.answered,
th.answered {
    width: 1%;

    .icon {
        color: var(--settled);
    }
}

.communication {
    display: none;

    .wrap {
        padding: 20px;
        border-radius: 3px;
        background: var(--surface-2);

        .sender {
            color: var(--text-2);
        }

        blockquote.contents {
            margin: 15px 0 0 0;
            padding: 0 0 0 20px;
            border-left: 5px var(--gray) solid;

            .subject {
                margin: 0 0 10px 0;
                font-weight: 700;
            }

            .body {
                margin: 10px 0 0 0;
            }

            .attachments {
                margin: 20px 0 0 0;

                h4 {
                    margin: 2px 0 10px 0;
                    font-size: 0.875rem;
                    color: var(--text-2);
                    font-weight: 600;
                }

                ul {
                    margin: 0;
                    padding: 0;
                    list-style: inside square;

                    li {
                        margin: 0 0 5px 0;

                        &:last-child {
                            margin: 0;
                        }
                    }
                }
            }
        }

        .controls {
            margin: 15px 0 0 0;
            padding: 0;

            li {
                float: left;
                font-size: 0.875rem;
                list-style: none;

                a {
                    float: left;
                    padding: 6px 14px;
                    border-radius: 2px;
                    color: var(--dark);
                    background: var(--gray-2);

                    &:not(:last-child) {
                        border-top-right-radius: 0;
                        border-bottom-right-radius: 0;
                    }

                    &:hover {
                        text-decoration: none;
                        background: var(--gray);
                    }

                    .icon {
                        margin: 0 7px 0 0;
                    }
                }
            }
        }
    }
}

/* Envelopes
---------------- */

/* A whole block's worth of guidance, which sits under the controls it is
   about the way a field's own help text does - but with room to breathe,
   since it follows a group rather than a single input. Its own class
   because .field-group > .form-text is every field's help text in the app */
.form-text.guide {
    margin-top: 10px;
}

/* A control shown so that its absence is not mistaken for an oversight - it
   says, on hover, why it is not offering anything */
.control.inert {
    opacity: 0.3;
    cursor: default;
}

/* The button standing in for "Sign" while a signature just given is being
   recorded - it does nothing, and says so on hover. See sign.js */
.btn.recording {
    opacity: 0.7;
    cursor: default;
}

/* The dashboard's own list of what is standing, which is flatter than the
   Client's - no expanding row, so no pointer on a row and no controls */
.dash-envelopes {
    margin: 0 0 30px 0;

    td.waiting-on small {
        display: block;
    }
}

/* A list of signature requests, each expanding into who was asked, where each
   of them has got to, and what happened when */
.envelopes {

    /* What a request's status amounts to, said in colour in the first column,
       so that a glance down the list finds what is wanted of the Admin
       without reading a single label */
    td.state,
    th.state {
        width: 1%;
        white-space: nowrap;

        &.settled .icon {
            color: var(--settled);
        }

        &.waiting .icon {
            color: var(--control);
        }

        &.stopped .icon {
            color: var(--text-3);
        }

        &.failed .icon {
            color: var(--overdue);
        }
    }

    /* How many people were asked, which is a count rather than a list at this
       width - the list is in the row below */
    td.signers,
    th.signers {
        width: 1%;
        text-align: center;
        color: var(--text-3);
    }

    /* What the signers were told, which is the request's note - quoted, since
       it is somebody's words rather than ours */
    blockquote.note {
        margin: 0 0 12px 0;
        padding: 0 0 0 12px;
        border-left: 3px var(--gray-3) solid;
        font-size: 0.875rem;
        color: var(--text-3);
    }

    /* Who was asked, and where each of them has got to. A list of rows
       that wrap rather than a table, because a table cannot give way on a
       phone - an address of thirty characters beside a status and a button
       made the whole page scroll sideways */
    ul.signers {
        margin: 0 0 12px 0;
        padding: 0;
        list-style: none;
        font-size: 0.875rem;

        li {
            display: flex;
            flex-wrap: wrap;
            align-items: baseline;
            gap: 2px 10px;
            padding: 5px 0;
        }

        /* Where there is no order, every signer stands equal, so this holds
           a dash rather than a number */
        .order {
            flex: 0 0 auto;
            width: 1rem;
            color: var(--text-3);
            text-align: center;
        }

        .who {
            /* Takes what it needs and no more, so that what is said about a
               signer sits beside their name rather than against the far
               edge - and gives way before the row has to scroll */
            flex: 0 1 auto;
            min-width: 0;
            color: var(--dark);

            .icon {
                margin: 0 5px 0 0;
                color: var(--text-3);
            }

            .icon.after {
                margin: 0 0 0 5px;
                color: var(--control);
            }

            small {
                display: block;
                font-size: 0.8125rem;
                font-weight: 300;

                /* An address has nowhere to break, so it is told it may */
                overflow-wrap: anywhere;
            }
        }

        /* Where one signer has got to, coloured by the same four readings
           the request itself uses */
        .state {
            flex: 0 1 auto;

            &.settled {
                color: var(--settled);
            }

            &.waiting {
                color: var(--text-3);
            }

            &.stopped {
                color: var(--text-3);
            }

            &.failed {
                color: var(--overdue);
                font-weight: 500;
            }
        }

        /* Pushed to the end of whatever line it lands on */
        .act {
            flex: 0 0 auto;
            margin-left: auto;
        }
    }

    /* What happened, in order. A list rather than a table, because it is
       read top to bottom and nothing in it lines up with anything else */
    ol.timeline {
        margin: 0;
        padding: 0;
        list-style: none;
        font-size: 0.8125rem;
        color: var(--text-3);

        li {
            display: flex;
            flex-wrap: wrap;
            align-items: baseline;
            gap: 0 8px;
            padding: 2px 0;

            /* What happened, which is a shape with its words in a tooltip -
               a column of the same six words reads as noise */
            > .icon {
                flex: 0 0 auto;
            }

            /* Both take what they need, so the time sits beside the name
               instead of against the far edge, and drops below it when
               there is no room for the two together */
            .who {
                flex: 0 1 auto;
                min-width: 0;
                color: var(--dark);

                .icon {
                    margin: 0 5px 0 0;
                    color: var(--text-3);
                }
            }

            .when {
                flex: 0 1 auto;
            }

            /* The plumbing of a request, which the control below asks for */
            &.quiet {
                display: none;
                color: var(--gray-7);

                .who {
                    color: var(--gray-7);
                }
            }
        }
    }

    /* Asks for the rows that are held back. Quiet itself, since it is an
       offer rather than something to do */
    a.more {
        display: inline-block;
        margin: 8px 0 0 0;
        font-size: 0.8125rem;
        color: var(--text-3);
        text-decoration: underline;

        &:hover,
        &:focus {
            color: var(--dark);
        }
    }

    /* The files that were sent, which are downloadable as they went rather
       than only as they came back */
    ul.files {
        margin: 0;
        padding: 0;
        list-style: none;
        font-size: 0.875rem;

        li {
            padding: 5px 0;

            + li {
                border-top: 1px solid var(--gray-4);
            }
        }

        /* Drawn as the document it is rather than as a link somewhere: the
           name is the thing, and the icon says what kind of thing */
        a {
            color: var(--dark);

            .icon {
                margin: 0 8px 0 0;
                color: var(--gray-7);
            }

            small {
                display: block;
                margin: 1px 0 0 26px;
                font-size: 0.75rem;
            }

            &:hover,
            &:focus {
                color: var(--primary);

                .icon {
                    color: var(--primary);
                }
            }
        }
    }
}

/* Files
---------------- */

/* What a list of files is narrowed by - a search, and a dropdown each for
   where the files came from, the client, and the tax year. The dropdowns are
   lists of links rather than selects, so that the page they narrow to is the
   one that says what it was narrowed by */
.narrowing {
    margin: 20px 0 0 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;

    .search {
        flex: 1 1 240px;
        max-width: 360px;

        .btn[type="submit"] {
            margin: 0;
        }

        /* The browser's own clear button only empties the box, leaving the
           list as it was searched - the one beside it reloads without it */
        input[type="search"]::-webkit-search-cancel-button {
            display: none;
        }

        .btn.clear {
            border: 1px var(--border) solid;
            border-left: 0;
            color: var(--control);
            background: var(--surface);

            &:hover {
                color: var(--control-hover);
            }
        }
    }

    /* Clears the search and every dropdown at once, beside the last of them,
       where it is seen along with what it clears */
    .reset {
        color: var(--text-3);
        font-size: 0.875rem;
        text-decoration: none;

        &:hover {
            color: var(--action);
        }

        .icon {
            margin: 0 4px 0 0;
        }
    }

    .dropdown-trigger {
        border: 1px var(--border) solid;
        color: var(--text-2);
        background: var(--surface);

        &:hover,
        &.show {
            border-color: var(--border-firm);
            color: var(--text);
        }

        /* A dropdown narrowed to anything but all of it, so that a list
           missing what was expected says why at a glance */
        &.narrowed {
            border-color: var(--action);
            color: var(--action);
        }

        .icon {
            margin: 0 6px 0 0;

            &.closing {
                margin: 0 0 0 6px;
            }
        }
    }

    .dropdown-menu .hint {
        margin: 0;
        padding: 0 16px 4px 16px;
        max-width: 280px;
        color: var(--text-3);
        font-size: 0.8125rem;
        white-space: normal;
    }

    /* On a phone, the search takes a line of its own, and the dropdowns
       share the next one, two to a line, whatever each is narrowed to - and
       the reset, wrapped under them, is a button of the same height and edge
       as them, rather than a stray link on a line of its own */
    @media (max-width: 575.98px) {
        .search {
            flex-basis: 100%;
            max-width: none;
        }

        .dropdown {
            flex: 1 1 45%;
            min-width: 0;
        }

        /* Cut short, rather than pushing its neighbour onto another line,
           e.g., a long source or client narrowed to */
        .dropdown-trigger {
            width: 100%;
            padding-left: 10px !important;
            padding-right: 10px !important;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .reset {
            padding: 6px 12px;
            border: 1px var(--border) solid;
            border-radius: 3px;
            color: var(--text-2);
            background: var(--surface);

            &:hover {
                border-color: var(--border-firm);
            }
        }
    }
}

.listable.files {
    td.name {
        /* An upload's notes, read on hover, since they are for the users
           rather than the list */
        .notes {
            margin: 0 0 0 4px;
            color: var(--text-3);
            cursor: help;
        }
    }

    /* Where a file came from - how, then who, on one line */
    td.source {
        white-space: nowrap;

        .how {
            margin: 0 6px 0 0;
            color: var(--text-2);
            font-size: 0.875rem;

            .icon {
                margin: 0 4px 0 0;
            }
        }

        /* The request a signed document or audit trail came from, said by
           its icon alone, with what it is in its tooltip */
        .esign {
            color: var(--text-2);

            &:hover {
                color: var(--text);
            }
        }

        /* How many Messages an upload was sent with */
        .messages {
            margin: 0 0 0 8px;
            color: var(--text-3);
            font-size: 0.8125rem;
            text-decoration: none;

            .icon {
                margin: 0 2px 0 0;
            }
        }

        .cs-box {
            display: inline-block;
            margin-top: 0;
            vertical-align: middle;

            .cs {
                margin-top: 0;
            }
        }
    }
}

/* An upload that names and dates each of its files - the file and its tax
   year on one line, and its name under them, said rather than asked, since
   it starts out as the file's own. A Message's form carries the same rows */
form.uploading {
    /* The column heading over the tax years, only once there is a year
       under it - before a file is up, there is only the file */
    .file-heads {
        margin: 0 0 6px 0;
        display: none;
        justify-content: flex-end;
        color: var(--text-3);
        font-size: 0.8125rem;

        .year {
            flex: 0 0 100px;
        }
    }

    &:has(.file-line .year:not([hidden])) .file-heads {
        display: flex;
    }

    /* Each file is set off from the one before it, since a name under one
       file otherwise reads as belonging to the next */
    .file-row-container:has(+ .file-row-container) {
        margin: 0 0 14px 0;
    }

    .file-row-container + .file-row-container {
        padding: 14px 0 0 0;
        border-top: 1px var(--border-soft) solid;
    }

    .file-line {
        display: flex;
        gap: 10px;

        .file-row {
            flex: 1 1 auto;
            min-width: 0;
        }

        .year {
            flex: 0 0 100px;

            &[hidden] {
                display: none;
            }
        }
    }

    .naming {
        margin: 6px 0 0 0;

        &[hidden] {
            display: none;
        }

        .named {
            color: var(--text-3);
            font-size: 0.875rem;

            strong {
                color: var(--text-2);
                font-weight: 500;
            }

            /* Spaced by margin rather than by the space in the markup, which
               does not survive between two tags */
            [data-rename] {
                margin: 0 0 0 8px;
            }
        }

        .field-group {
            margin: 0;
        }
    }

    /* At phone width the year drops under the file, which keeps the width
       a filename needs */
    @media (max-width: 575.98px) {
        &:has(.file-line .year:not([hidden])) .file-heads,
        .file-heads {
            display: none;
        }

        .file-line {
            flex-wrap: wrap;

            .year {
                flex-basis: 100%;
            }
        }
    }
}

/* Signers
---------------- */

/* The signers of a request being created, each a row that can be dragged into
   the order they are asked in */
.signer-rows {

    .signer-row {
        display: flex;
        gap: 8px;
        align-items: start;
        padding: 8px;
        border: 1px var(--gray-2) solid;
        border-radius: 4px;
        margin: 0 0 8px 0;
        background: var(--surface-3);

        /* The row being dragged, lifted just enough to be obviously the one
           that is moving */
        &.dragging {
            border-color: var(--action);
            box-shadow: 0 2px 8px rgb(0 0 0 / 12%);
        }

        .handle {
            padding: 6px 0 0 0;
            color: var(--control);
            cursor: grab;
        }

        .order {
            padding: 6px 0 0 0;
            min-width: 1.25rem;
            color: var(--text-3);
            text-align: center;
        }

        /* The person, which is the row's main control and takes the room left
           over */
        .who {
            flex: 1 1 auto;
            min-width: 0;

            .field-group {
                margin: 0;
            }

            .form-label {
                display: none;
            }
        }

        .verify {
            flex: 0 1 16rem;
            margin: 0 0 0 5px;

            .form-text {
                font-size: 0.75rem;
            }
        }

        .control {
            padding: 6px 0 0 0;
            border: 0;
            background: none;
            color: var(--control);

            &:hover {
                color: var(--overdue);
            }

            &:disabled {
                opacity: 0.35;
                cursor: not-allowed;
            }
        }
    }
}

/* At phone width the row stacks, since a dropdown and a checkbox side by side
   leave neither enough room to read */
@media (max-width: 767px) {
    .signer-rows .signer-row {
        flex-wrap: wrap;

        .who,
        .verify {
            flex: 1 1 100%;
        }
    }
}

/* Editor
---------------- */

/* The provider's document editor and signing ceremony, framed on our own
   page. Their own guidance is that it wants 1360 x 768, so it is given the
   full width available and a tall frame rather than being boxed in */
.editor,
.ceremony {
    position: relative;

    /* Clear of whatever names the document above it, rather than against it */
    margin: 15px 0 20px 0;
    border: 1px var(--gray-3) solid;
    border-radius: 4px;
    overflow: hidden;
    background: var(--surface);

    iframe {
        display: block;
        width: 100%;
        height: min(82vh, 1100px);
        min-height: 620px;
        border: 0;
    }

    /* Sized by common.js to fit the window, which can be shorter than the
       floor above - a frame taller than the window hides the provider's
       first control, pinned to the frame's foot */
    &.fitted iframe {
        height: var(--fit);
        min-height: 0;
    }

    /* Shown until the frame says it has loaded, so the Admin is not looking
       at an empty rectangle wondering whether it is broken */
    .loading {
        padding: 4rem 1rem;
        text-align: center;

        .icon {
            color: var(--control);
            font-size: 2rem;
        }

        .note {
            margin: 1.5rem 0 0;
            color: var(--text-3);
        }
    }
}

/* The way back up from a fitted frame, which takes the scroll wherever the
   pointer is over it - placed by common.js in the margin beside the frame */
button.up {
    position: fixed;
    z-index: 10;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
    border: 1px var(--border-soft) solid;
    border-radius: 50%;
    background: var(--surface);
    color: var(--control);
    box-shadow: 0 2px 8px rgb(0 0 0 / 12%);
    transition: color 120ms ease-out, box-shadow 120ms ease-out;

    &:hover,
    &:focus-visible {
        color: var(--control-hover);
        box-shadow: 0 4px 14px rgb(0 0 0 / 18%);
    }

    /* Too little margin beside the frame to hold it, e.g., on a phone, or
       the page moved up from the frame */
    &.cramped,
    &.away {
        display: none;
    }

    @media (prefers-reduced-motion: no-preference) {
        animation: rise 200ms cubic-bezier(0.16, 1, 0.3, 1) both;
    }
}

@keyframes rise {
    from {
        opacity: 0;
        transform: translateY(6px);
    }
}

/* The page an Admin waits on while a task prepares a request. It stands alone,
   so it is centred and given room.

   Named for what it is rather than for what it is doing: "waiting" is also one
   of the four readings a row can have, and a rule by that name would reach
   into every list that uses them */
.preparation {
    padding: 4rem 1rem;
    text-align: center;

    .icon {
        color: var(--control);
        font-size: 3rem;
    }

    .note {
        margin: 1.5rem 0 0.5rem;
        color: var(--text-3);
    }

    .btn {
        margin-top: 1.5rem;
    }

    /* The one that went wrong, which is the only state worth colouring */
    .failed .icon {
        color: var(--overdue);
    }
}

/* Alternative
---------------- */

/* A second way to do what the form above does, e.g., signing in with Google
   rather than with a password - ruled off, so that it reads as another way
   in rather than as another step */
.alternative {
    margin: 25px 0 0 0;

    .rule {
        display: block;
        margin: 0 0 15px 0;
        font-size: 0.8125rem;
        color: var(--text-3);
        text-align: center;
        overflow: hidden;

        /* The rule is drawn either side of the word, rather than behind it */
        &::before,
        &::after {
            content: '';
            display: inline-block;
            width: 50%;
            height: 1px;
            position: relative;
            vertical-align: middle;
            background: var(--border);
        }

        &::before {
            right: 12px;
            margin: 0 0 0 -50%;
        }

        &::after {
            left: 12px;
            margin: 0 -50% 0 0;
        }
    }

    .btn.block {
        width: 100%;
        text-align: center;

        .icon {
            margin-right: 5px;
        }
    }
}

/* Agreements
-------------------------------------------------------------------------- */

/* The agreements a person has to accept before going on, and the page that
   shows one of them on its own - a single centred column, since there is
   nothing beside it to read */
.agreements {
    margin: 10px auto 40px auto;

    /* What the page is asking, said once above the documents */
    .intro {
        margin: 0 0 25px 0;

        .eyebrow {
            margin: 0 0 6px 0;
            font-size: 0.75rem;
            font-weight: 500;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--text-3);
        }

        h1 {
            font-size: 1.75rem;
            font-weight: 500;
            letter-spacing: -0.01em;

            @media (max-width: 767.98px) {
                font-size: 1.375rem;
            }
        }

        .lede {
            margin: 8px 0 0 0;
            max-width: 40rem;
            font-size: 1rem;
            line-height: 1.55;
            color: var(--text-2);
        }
    }

    /* The buttons under the documents */
    .actions {
        display: flex;
        margin: 5px 0 0 0;
        gap: 4px;
        align-items: center;
        flex-wrap: wrap;

        .btn.primary {
            padding: 10px 24px !important;
            font-size: 0.9375rem;
        }

        @media (max-width: 575.98px) {
            .btn {
                width: 100%;
                text-align: center;
            }
        }
    }
}

/* An agreement document, e.g., the EULA - a card, with the text under a
   heading that names and dates it */
.agreement {
    margin: 0 0 25px 0;
    border: 1px solid var(--border-soft);
    border-radius: 10px;
    overflow: hidden;
    background: var(--surface);
    box-shadow: 0 1px 2px rgba(21, 29, 39, 0.04), 0 8px 24px rgba(21, 29, 39, 0.05);

    &.invalid {
        border-color: var(--danger);
    }

    /* Not a header element, since the page header is styled by that name */
    .heading {
        display: flex;
        padding: 18px 22px;
        gap: 15px;
        align-items: flex-start;
        justify-content: space-between;
        border-bottom: 1px solid var(--border-soft);

        h1,
        h2 {
            margin: 0;
            font-size: 1.125rem;
            font-weight: 600;
            letter-spacing: -0.005em;
        }

        /* Which version, and since when */
        .meta {
            display: flex;
            margin: 5px 0 0 0;
            gap: 8px;
            align-items: center;
            font-size: 0.8125rem;
            color: var(--text-3);

            .version {
                padding: 1px 8px;
                border: 1px solid var(--border);
                border-radius: 999px;
                font-size: 0.6875rem;
                font-weight: 500;
                font-variant-numeric: tabular-nums;
                color: var(--text-2);
            }
        }

        /* The link to the document on its own page */
        .open {
            flex: none;
            padding: 5px 10px;
            border: 1px solid var(--border-soft);
            border-radius: 6px;
            font-size: 0.8125rem;
            font-weight: 500;
            color: var(--text-2);
            white-space: nowrap;

            .icon {
                margin: 0 4px 0 0;
                font-size: 0.75rem;
            }

            &:hover {
                border-color: var(--border);
                color: var(--text);
                text-decoration: none;
                background: var(--surface-4);
            }
        }
    }

    /* That it changed since it was last agreed to, said before the text */
    .changed {
        margin: 0;
        padding: 10px 22px;
        border-bottom: 1px solid var(--border-soft);
        font-size: 0.875rem;
        color: var(--action);
        background: color-mix(in srgb, var(--action) 6%, white);

        .icon {
            margin: 0 6px 0 0;
        }
    }

    /* The rendered markdown */
    .body {
        padding: 20px 22px;
        font-size: 0.9375rem;

        h1,
        h2,
        h3,
        h4 {
            margin: 1.75rem 0 0.625rem 0;
            font-size: 1rem;
            font-weight: 600;
            letter-spacing: -0.005em;

            &:first-child {
                margin-top: 0;
            }
        }

        h2 {
            font-size: 1.0625rem;
        }

        h3 {
            font-size: 0.9375rem;
            color: var(--text-2);
        }

        p,
        li {
            line-height: 1.65;
            color: var(--text);
        }

        ol,
        ul {
            padding-left: 1.5rem;
        }

        li {
            margin: 0 0 0.5rem 0;
        }

        strong {
            font-weight: 600;
        }

        table {
            width: 100%;
            margin: 0 0 1rem 0;
            font-size: 0.875rem;

            th,
            td {
                padding: 0.5rem 0.625rem;
                border-bottom: 1px solid var(--border-soft);
                vertical-align: top;
                text-align: left;
            }

            th {
                font-weight: 600;
                color: var(--text-2);
            }
        }

        /* The last thing in the box does not need room under it */
        > :last-child {
            margin-bottom: 0;
        }
    }

    /* Boxed, on the page that asks for it to be agreed to - the text is
       previewed, its first lines fading out over the link that unfolds it */
    &.boxed {
        .excerpt {
            --line: calc(0.9375rem * 1.65);

            position: relative;

            .body {
                max-height: calc(20px + var(--line) * 4);
                overflow: hidden;
                mask-image: linear-gradient(
                    to bottom,
                    black calc(20px + var(--line) * 2),
                    transparent
                );
            }

            /* The link that unfolds the text, sitting on the faded lines */
            .expand {
                position: absolute;
                bottom: 10px;
                left: 50%;
                padding: 5px 12px;
                border: 1px solid var(--border-soft);
                border-radius: 999px;
                font-size: 0.8125rem;
                font-weight: 500;
                color: var(--text-2);
                white-space: nowrap;
                background: var(--surface);
                transform: translateX(-50%);

                .icon {
                    margin: 0 4px 0 0;
                    font-size: 0.6875rem;
                }

                &:hover {
                    border-color: var(--border);
                    color: var(--text);
                    background: var(--surface-4);
                }
            }

            /* Unfolded, the text scrolls inside the card, so that the
               checkbox under it stays near */
            &.unfolded {
                .body {
                    max-height: 48vh;
                    overflow-y: auto;
                    overscroll-behavior: contain;
                    mask-image: none;

                    /* A fade over the last lines, saying there is more below */
                    &::after {
                        content: '';
                        display: block;
                        position: sticky;
                        bottom: -20px;
                        height: 36px;
                        margin: -36px -22px -20px -22px;
                        background: linear-gradient(to bottom, transparent, var(--surface));
                        pointer-events: none;
                    }
                }

                .expand {
                    display: none;
                }
            }
        }

        /* The checkbox that agrees to it - a row of its own, under the text,
           with room around it so it reads as the step it is */
        .consent {
            padding: 16px 22px;
            border-top: 1px solid var(--border-soft);
            background: var(--surface-4);

            .form-check {
                display: flex;
                margin: 0;
                padding: 0;
                gap: 12px;
                align-items: flex-start;
                flex-wrap: wrap;

                .form-check-input {
                    flex: none;
                    width: 1.25rem;
                    height: 1.25rem;
                    margin: 1px 0 0 0;
                    border-color: var(--border-firm);
                    cursor: pointer;

                    &:checked {
                        border-color: var(--action);
                        background-color: var(--action);
                    }
                }

                .form-check-label {
                    flex: 1;
                    font-size: 0.9375rem;
                    line-height: 1.45;
                    cursor: pointer;

                    strong {
                        font-weight: 500;
                    }
                }

                .invalid-feedback {
                    width: 100%;
                    margin: 0 0 0 calc(1.25rem + 12px);
                }
            }
        }
    }
}

/* The agreements a user has accepted, listed on their settings page */
ul.accepted {
    margin: 0;
    padding: 0;
    list-style: none;

    li {
        margin: 0 0 8px 0;

        &:last-child {
            margin-bottom: 0;
        }
    }

    .subtle {
        display: block;
        font-size: 0.8125rem;
    }
}
