/* ========================================================================== */
/* ArchEx Shared UI Components                                                */
/*                                                                            */
/* GOLD STANDARD: These classes are extracted from the approved login page.   */
/* New pages must compose these components rather than creating parallel       */
/* card, field, button, link, heading, action-row or footer styling.           */
/* ========================================================================== */

/* Page canvas -------------------------------------------------------------- */
.ax-page {
    position: relative;
    min-height: 100dvh;
    /* clip, not hidden (21 September 2026): hidden makes this a scroll container, and every
       position:sticky child inside it stops sticking. clip contains the contours layer without
       that side effect — which matters now that every page carries this class, including the
       ones with sticky field navigation. */
    overflow: clip;
    background:
        radial-gradient(circle at 18% 12%, rgba(217, 162, 107, .20), transparent 34%),
        radial-gradient(circle at 82% 84%, rgba(242, 108, 33, .08), transparent 28%),
        var(--color-background);
    color: var(--color-charcoal);
    font-family: var(--font-body);
    isolation: isolate;
}

.ax-page-contours {
    position: absolute;
    inset: -12%;
    z-index: -1;
    opacity: .28;
    pointer-events: none;
    transform: rotate(-5deg) scale(1.08);
    background-image:
        repeating-radial-gradient(
            ellipse at 18% 34%,
            transparent 0,
            transparent 38px,
            rgba(59, 59, 59, .10) 39px,
            transparent 41px,
            transparent 64px),
        repeating-radial-gradient(
            ellipse at 78% 68%,
            transparent 0,
            transparent 44px,
            rgba(217, 162, 107, .18) 45px,
            transparent 47px,
            transparent 72px);
}

.ax-centered-shell {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-5);
    padding: var(--space-5);
}

/* Surface/card ------------------------------------------------------------- */
.ax-authcard {
    width: min(100%, 480px);
    padding: var(--space-5);
    border: 1px solid rgba(31, 31, 31, .06);
    border-radius: var(--radius-component);
    background: rgba(255, 255, 255, .96);
    box-shadow: var(--shadow-dialog);
    backdrop-filter: blur(8px);
}

/* Branded heading ---------------------------------------------------------- */
.ax-brand-heading {
    display: grid;
    gap: 12px;
    margin-bottom: var(--space-5);
    text-align: center;
}

.ax-brand-logo {
    display: block;
    width: 100%;
    height: auto;
    max-height: 250px;
    margin: 0 auto;
    object-fit: contain;
}

.ax-heading-group {
    display: grid;
    gap: var(--space-2);
}

.ax-title {
    margin: 0;
    color: var(--color-charcoal);
    font-family: var(--font-heading);
    font-size: clamp(1.75rem, 4vw, 2.25rem);
    font-weight: 700;
    line-height: 1.2;
}

.ax-subtitle {
    margin: 0;
    color: var(--color-gunmetal);
    font-size: 1rem;
    line-height: 1.5;
}

/* Forms -------------------------------------------------------------------- */
.ax-form {
    display: grid;
    gap: var(--space-4);
}

.ax-authfield {
    display: grid;
    gap: var(--space-2);
}

.ax-authfield + .ax-authfield {
    margin-top: 16px;
}

.ax-authlabel,
.ax-authfield > label {
    color: var(--color-charcoal);
    font-family: var(--font-body);
    font-size: .95rem;
    font-weight: 700;
}

.ax-authinput {
    box-sizing: border-box;
    width: 100%;
    height: 46px;
    padding: 0 var(--space-3);
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-component);
    background: var(--color-surface);
    color: var(--color-charcoal);
    font-family: var(--font-body);
    font-size: 1rem;
    transition: border-color var(--motion-duration) var(--motion-easing),
                box-shadow var(--motion-duration) var(--motion-easing);
}

.ax-authinput::placeholder {
    color: #6f6f6f;
}

.ax-authinput:hover {
    border-color: var(--color-sandstone);
}

.ax-authinput:focus {
    border-color: var(--color-primary);
    outline: none;
    box-shadow: 0 0 0 3px rgba(242, 108, 33, .18);
}

.ax-authinput.invalid {
    border-color: var(--color-danger);
    outline: none;
}

.ax-form-options {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-top: 8px;
    margin-bottom: 18px;
}

.ax-checkbox-option {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--color-gunmetal);
    cursor: pointer;
    font-size: .95rem;
}

.ax-checkbox {
    width: 20px;
    height: 20px;
    margin: 0;
    border: 1px solid var(--color-divider);
    border-radius: 4px;
    appearance: none;
    background: var(--color-surface);
    cursor: pointer;
}

.ax-checkbox:checked {
    border-color: var(--color-primary);
    background-color: var(--color-primary);
    background-image:
        linear-gradient(45deg, transparent 45%, #fff 45%, #fff 55%, transparent 55%),
        linear-gradient(-45deg, transparent 38%, #fff 38%, #fff 48%, transparent 48%);
    background-position: 6px 9px, 3px 9px;
    background-size: 8px 8px;
    background-repeat: no-repeat;
}

.ax-checkbox:focus-visible {
    outline: 3px solid rgba(242, 108, 33, .24);
    outline-offset: 2px;
}

/* Links and buttons -------------------------------------------------------- */
.ax-link,
.ax-link:link,
.ax-link:visited {
    color: var(--color-primary-dark);
    font-weight: 700;
    text-decoration: none;
    transition: color var(--motion-duration) var(--motion-easing);
}

.ax-link:hover,
.ax-link:focus-visible,
.ax-link:active {
    color: var(--color-charcoal);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.ax-button-primary {
    width: 100%;
    height: 52px;
    min-height: 52px;
    margin-top: var(--space-1);
    border: 0;
    border-radius: var(--radius-component);
    background: var(--color-primary);
    color: #FFFFFF;
    font-family: var(--font-body);
    font-size: 1rem;
    font-weight: 700;
    cursor: pointer;
    box-shadow: 0 2px 8px rgba(242, 108, 33, .22);
    transition: background var(--motion-duration) var(--motion-easing),
                box-shadow var(--motion-duration) var(--motion-easing),
                transform var(--motion-duration) var(--motion-easing);
}

.ax-button-primary:hover {
    background: var(--color-primary-dark);
    box-shadow: 0 4px 12px rgba(216, 90, 20, .28);
}

.ax-button-primary:active {
    transform: translateY(1px);
}

.ax-button-primary:focus-visible {
    outline: 3px solid rgba(242, 108, 33, .30);
    outline-offset: 3px;
}

.ax-secondary-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-2) var(--space-3);
    padding-top: 12px;
    font-size: .875rem;
    text-align: center;
}

.ax-secondary-actions .ax-link,
.ax-secondary-actions .ax-link-button {
    color: var(--color-primary-dark);
    font-family: var(--font-body);
    font-size: .875rem;
    font-weight: 700;
}

.ax-link-button {
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
}

/* Validation and notices -------------------------------------------------- */
.ax-validation {
    margin: 0;
    color: var(--color-danger);
    font-size: .875rem;
    line-height: 1.4;
}

.ax-validation-summary {
    padding: var(--space-3);
    border-left: 4px solid var(--color-danger);
    border-radius: var(--radius-component);
    background: rgba(198, 40, 40, .06);
}

.ax-authcard .alert {
    margin: 0 0 var(--space-4);
    padding: var(--space-3);
    border: 1px solid rgba(198, 40, 40, .30);
    border-radius: var(--radius-component);
    background: rgba(198, 40, 40, .06);
    color: var(--color-danger);
    font-family: var(--font-body);
    font-size: .9rem;
}

/* Application footer ------------------------------------------------------ */
.ax-page-footer {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-2);
    max-width: 640px;
    margin-top: 32px;
    color: var(--color-gunmetal);
    font-size: .78rem;
    line-height: 1.5;
    text-align: center;
}

@media (max-width: 768px) {
    .ax-centered-shell {
        justify-content: flex-start;
        padding: var(--space-4);
        padding-top: var(--space-7);
    }

    .ax-authcard {
        padding: var(--space-4);
    }

    .ax-brand-heading {
        gap: var(--space-4);
        margin-bottom: var(--space-4);
    }

    .ax-brand-logo {
        max-height: 128px;
    }
}

@media (max-width: 480px) {
    .ax-centered-shell {
        padding: var(--space-3);
        padding-top: var(--space-5);
    }

    .ax-authcard {
        padding: var(--space-4) var(--space-3);
    }

    .ax-form-options {
        align-items: flex-start;
        flex-direction: column;
    }

    .ax-page-footer {
        display: grid;
        gap: var(--space-1);
    }

    .ax-page-footer span[aria-hidden="true"] {
        display: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .ax-button-primary,
    .ax-authinput,
    .ax-link {
        transition: none;
    }
}

/* ArchEx 5.0A operating-system foundation -------------------------------- */
.ax-os-page {
    width: min(1480px, 100%);
    margin: 0 auto;
    padding: clamp(20px, 3vw, 38px);
    color: var(--color-charcoal);
    font-family: var(--font-body);
}

.ax-os-header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-4);
}
.ax-os-heading { min-width: 0; }
.ax-os-title-row { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-3); min-width: 0; }
.ax-os-heading h1 {
    margin: 0;
    font-family: var(--font-heading);
    /* The top of the type scale, like every other page title. This asked for
       clamp(2rem, 4vw, 3.6rem) - 57.6px at a 1440px desktop - which is the same habit that
       had page titles ranging from 18px to 86px across the application. The shared header is
       the last place that should be setting its own size: whatever it does, every page that
       adopts it inherits. */
    font-size: var(--archex-text-2xl);
    line-height: 1.12;
    letter-spacing: -.02em;
}
.ax-os-eyebrow {
    margin: 0 0 8px;
    color: var(--color-primary-dark);
    font-size: .7rem;
    font-weight: 800;
    letter-spacing: .16em;
    text-transform: uppercase;
}
.ax-os-subtitle { margin: 8px 0 0; color: var(--color-gunmetal); }
.ax-os-header-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; }

.ax-os-focus {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1px;
    margin-bottom: var(--space-4);
    overflow: hidden;
    border: 1px solid var(--color-divider);
    border-radius: 8px;
    background: var(--color-divider);
    box-shadow: var(--shadow-card);
}
.ax-os-focus article {
    min-height: 110px;
    padding: 18px 20px;
    background: var(--color-surface);
}
.ax-os-focus article.attention { background: #fff8f3; }
.ax-os-focus article.next-action { background: var(--color-panel); }
.ax-os-focus span { display:block; color:var(--color-primary-dark); font-size:.68rem; font-weight:800; letter-spacing:.1em; text-transform:uppercase; }
.ax-os-focus strong { display:block; margin-top:8px; font-family:var(--font-heading); font-size:1.05rem; }
.ax-os-focus small { display:block; margin-top:6px; color:var(--color-gunmetal); line-height:1.4; }
.ax-os-focus .next-action div { margin-top:12px; }

.ax-os-context-bar {
    position: sticky;
    top: 0;
    z-index: 8;
    display: flex;
    gap: 6px;
    margin: 0 0 var(--space-4);
    padding: 8px;
    overflow-x: auto;
    border: 1px solid var(--color-divider);
    border-radius: 8px;
    background: rgba(255,255,255,.96);
    box-shadow: var(--shadow-card);
    backdrop-filter: blur(10px);
}
.ax-os-context-bar button,
.ax-os-context-bar a {
    min-height: 38px;
    padding: 0 13px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--color-charcoal);
    font: 700 .82rem var(--font-body);
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
}
.ax-os-context-bar button:hover,
.ax-os-context-bar a:hover,
.ax-os-context-bar .active { background: var(--color-panel); color: var(--color-primary-dark); }

.ax-os-progressive {
    margin-top: var(--space-3);
    border: 1px solid var(--color-divider);
    border-radius: 8px;
    background: var(--color-surface);
    box-shadow: var(--shadow-card);
}
.ax-os-progressive > summary {
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:16px;
    padding:16px 18px;
    list-style:none;
    cursor:pointer;
}
.ax-os-progressive > summary::-webkit-details-marker { display:none; }
.ax-os-progressive > summary span { display:grid; gap:2px; }
.ax-os-progressive > summary small { color:var(--color-primary-dark); font-size:.65rem; font-weight:800; letter-spacing:.12em; }
.ax-os-progressive > summary strong { font-family:var(--font-heading); }
.ax-os-progressive > summary em { color:var(--color-gunmetal); font-size:.82rem; font-style:normal; font-weight:400; }
.ax-os-progressive[open] > summary b { transform:rotate(45deg); }
.ax-os-progressive-body { padding:0 18px 18px; }

@media (max-width: 850px) {
    /* stretch, not flex-start: flex-start sizes each child to its own content, so a long subtitle
       made the heading 946px wide inside a 360px phone and Permissions, Audit and Governance
       could be dragged 833px sideways. The header looked right in every screenshot, because what
       overflowed was off the side of it. */
    .ax-os-header { align-items:stretch; flex-direction:column; }
    .ax-os-header > * { max-width:100%; min-width:0; }
    .ax-os-header-actions { justify-content:flex-start; }
    .ax-os-focus { grid-template-columns:1fr; }
    .ax-os-focus article { min-height:0; }
    .ax-os-page { padding:16px; }
}

/* Shared operating-system workspace controls ------------------------------ */
.ax-os-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    margin: 0 0 18px;
    padding: 12px 14px;
    border: 1px solid rgba(31,31,31,.08);
    border-radius: var(--radius-component);
    background: rgba(255,255,255,.94);
    box-shadow: var(--shadow-card);
}

.ax-os-toolbar-controls {
    display: flex;
    align-items: center;
    flex: 1;
    flex-wrap: wrap;
    gap: 10px;
    min-width: 0;
}

.ax-os-toolbar input[type="search"],
.ax-os-toolbar input[type="text"],
.ax-os-toolbar select {
    min-height: 40px;
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-component);
    background: var(--color-surface);
    color: var(--color-charcoal);
    font: inherit;
}

.ax-os-toolbar input[type="search"],
.ax-os-toolbar input[type="text"] {
    flex: 1 1 280px;
    min-width: min(280px, 100%);
    padding: 0 12px;
}

.ax-os-toolbar select { padding: 0 34px 0 12px; }
.ax-os-toolbar-result {
    flex: 0 0 auto;
    color: var(--color-gunmetal);
    font-size: .78rem;
    font-weight: 700;
    white-space: nowrap;
}

/* Shared classes deliberately normalise major workspaces without changing
   their business-specific content or interaction logic. */
.ax-os-page > .ax-os-header:first-of-type { margin-bottom: 14px; }
.ax-os-page > .ax-os-focus { margin-bottom: 16px; }
.ax-os-page .primary-button,
.ax-os-page .primary-action,
.ax-os-page .hero-action:not(.secondary) { border-radius: var(--radius-component); }
.ax-os-page .secondary-button,
.ax-os-page .secondary-action,
.ax-os-page .hero-action.secondary { border-radius: var(--radius-component); }

@media (max-width: 720px) {
    .ax-os-toolbar { align-items: stretch; flex-direction: column; }
    .ax-os-toolbar-controls { width: 100%; }
    .ax-os-toolbar-result { white-space: normal; }
}

/* Clean page layouts for unified design ===================================== */

.ax-page {
    position: relative;
    min-height: 100dvh;
    padding: var(--space-4);
    background: var(--color-background);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    /* ROWS PACKED AT THE TOP (3 October 2026). A page that makes itself a grid keeps this
       min-height, and a grid stretches its rows to fill it: on a job's SWMS page, short of
       content, the two tab rows grew to 147 and 124px with their tabs floating in the middle.
       A flex column ignores this; a grid's sized rows (1fr) still fill the space. */
    align-content: start;
}

.page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    padding: 0;
}

.page-header h1 {
    margin: 0;
    font-size: clamp(1.75rem, 4vw, 2.25rem);
    font-weight: 700;
}

.page-header .eyebrow {
    margin: 0 0 var(--space-2);
    font-size: 0.65rem;
    font-weight: 800;
    letter-spacing: 0.12em;
    color: var(--color-primary);
}

.action-button {
    padding: var(--space-3) var(--space-4);
    border: none;
    border-radius: var(--radius-component);
    background: var(--color-primary);
    color: white;
    font-weight: 600;
    font-size: 0.9rem;
    cursor: pointer;
    white-space: nowrap;
    transition: all 150ms ease-in-out;
}

.action-button:hover {
    background: var(--color-primary-dark);
    transform: translateY(-1px);
}

.action-button:active {
    transform: translateY(0);
}

.search-bar {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
}

.search-bar input {
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-component);
    font-size: 0.95rem;
}

.search-bar small {
    color: var(--color-gunmetal);
    font-size: 0.8rem;
}

.projects-grid,
.projects-list {
    display: grid;
    gap: var(--space-3);
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}

.projects-list {
    grid-template-columns: 1fr;
}

.project-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    transition: all 150ms ease-in-out;
}

.project-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 12px 35px rgba(0, 0, 0, 0.12);
}

.project-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--space-3);
}

.project-header h3 {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 600;
}

.project-reference {
    margin: 0;
    color: var(--color-gunmetal);
    font-size: 0.85rem;
    font-weight: 600;
}

.project-meta {
    display: grid;
    gap: var(--space-2);
    margin: 0;
    font-size: 0.9rem;
}

.project-meta div {
    display: flex;
    gap: var(--space-2);
}

.project-meta dt {
    font-weight: 600;
    min-width: 60px;
    color: var(--color-gunmetal);
}

.project-meta dd {
    margin: 0;
    flex: 1;
}

.created-date {
    margin-top: var(--space-2);
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-divider);
    font-size: 0.8rem;
    color: var(--color-muted);
}

.status-badge {
    display: inline-block;
    padding: 4px 10px;
    border-radius: 12px;
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
    background: var(--color-panel);
    color: var(--color-charcoal);
}

.status-badge.active {
    background: var(--color-success);
    color: white;
}

.status-badge.warning {
    background: var(--color-warning);
    color: white;
}

.status-badge.danger {
    background: var(--color-danger);
    color: white;
}

/* ================================================================================================
   EMPTY STATE  (21 September 2026)
   ------------------------------------------------------------------------------------------------
   WHY THIS GREW. A shared .empty-state already existed here, but it only centred text and added
   padding — no border, no background, nothing that reads as a placed object. So twenty pages each
   added their own chrome in their own scoped sheet, and because scoped CSS cannot be shared they
   added it twenty times: seven corner radii (10 to 18px), padding from 1rem to 4rem, dashed and
   solid borders, four background treatments. The under-specified shared rule CAUSED the drift; the
   pages were each finishing a job it had left half done.

   Nine of the twenty had independently arrived at the same design — dashed divider border, rounded,
   centred, muted, generous padding — so that is what this now is. It is their design, promoted, not
   a new one imposed.

   TWO CONTROLS SHARED ONE NAME. Seventeen pages use .empty-state for a titled block with a heading
   and a line of guidance. Three use it for a bare sentence inside a panel: "No spatial packages
   have been uploaded for this project." Giving that a 48px dashed card would be wrong, so .compact
   keeps it a muted line. ActionCentre had already invented that modifier locally; it is promoted
   rather than replaced.
   ============================================================================================== */

.empty-state {
    display: grid;
    gap: 6px;
    padding: 48px 24px;
    border: 1px dashed var(--color-divider);
    border-radius: 16px;
    background: rgba(255, 255, 255, .6);
    color: var(--color-gunmetal);
    text-align: center;
}

.empty-state h1,
.empty-state h2,
.empty-state h3 {
    margin: 0;
    color: var(--color-charcoal);
}

.empty-state h2 { font-size: 1.5rem; }

.empty-state strong {
    color: var(--color-charcoal);
    font-size: 1.05rem;
}

.empty-state p,
.empty-state span {
    margin: 0;
    color: var(--color-gunmetal);
}

/* A line of prose reads badly across a wide card. */
.empty-state p,
.empty-state span { max-width: 62ch; justify-self: center; }

/* One sentence inside a panel, not a placed object. */
.empty-state.compact {
    padding: 14px 0;
    border: 0;
    border-radius: 0;
    background: none;
}

/* The page already put it in a card; two borders around one message is one too many. */
.empty-state.ax-card {
    border-style: solid;
    background: none;
}

.project-item {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-4) !important;
    cursor: pointer;
    transition: all 150ms ease-in-out;
}

.project-item:hover {
    transform: translateY(-2px);
    box-shadow: 0 12px 35px rgba(0, 0, 0, 0.12);
}

.project-main h3 {
    margin: 0 0 var(--space-2);
    font-size: 1.1rem;
}

.project-details-row {
    display: flex;
    gap: var(--space-3);
    flex-wrap: wrap;
    font-size: 0.9rem;
}

.detail {
    color: var(--color-gunmetal);
}

.readiness-issues {
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.issue-badge {
    display: inline-block;
    padding: 4px 8px;
    border-radius: 8px;
    background: rgba(198, 40, 40, 0.1);
    color: var(--color-danger);
    font-size: 0.8rem;
    font-weight: 600;
}

.finance-summary {
    padding: var(--space-4) !important;
}

.summary-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: var(--space-3);
}

.summary-stats article {
    text-align: center;
}

.summary-stats strong {
    display: block;
    font-size: 1.8rem;
    color: var(--color-primary);
}

.summary-stats p {
    margin: var(--space-1) 0 0;
    font-size: 0.8rem;
    color: var(--color-gunmetal);
}

.summary-stats.alert strong {
    color: var(--color-danger);
}

/* ==========================================================================
   UNIFY LAYER — loaded last, wins over every page's scoped .razor.css.
   Purpose: one brand look on all pages (orange primary, warm neutrals,
   small quiet headings) regardless of what each page's own CSS says.
   ========================================================================== */

:root { accent-color: var(--color-primary); }

/* Old operating headers: keep them (they hold each page's title + actions)
   but force them compact and quiet instead of hiding them. */
.ax-page .ax-os-focus { display: none !important; }

.ax-page .ax-os-header {
    display: flex !important;
    align-items: center !important;
    justify-content: space-between;
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    padding: 0 !important;
    margin: 0 0 var(--space-3) !important;
}

.ax-page .ax-os-header p:not(.eyebrow),
.ax-page .ax-os-header .ax-subtitle {
    margin: 2px 0 0 !important;
    color: var(--color-gunmetal) !important;
    font-size: 0.83rem !important;
    max-width: 640px;
}

/* Form controls — no browser blue, no page-specific colours.
   EVERY BOX YOU TYPE IN (5 October 2026, feedback #252). Adam Deane, on a user's page: "how is the first name and last
   name different boxs and text to the rest ... the new password is different again". Blazor's InputText writes an
   <input> with no type at all, which none of the lines below named - so every name box across ArchEx was the browser's
   own - and passwords, phone numbers, web addresses and times weren't named either. Now they are. */
.ax-page select,
.ax-page input:not([type]),
.ax-page input[type="search"],
.ax-page input[type="text"],
.ax-page input[type="date"],
.ax-page input[type="time"],
.ax-page input[type="datetime-local"],
.ax-page input[type="email"],
.ax-page input[type="password"],
.ax-page input[type="tel"],
.ax-page input[type="url"],
.ax-page input[type="number"],
.ax-page textarea {
    padding: 10px 14px !important;
    border: 1px solid var(--color-divider) !important;
    border-radius: var(--radius-component) !important;
    background: var(--color-surface) !important;
    color: var(--color-charcoal) !important;
    font-size: 0.92rem !important;
    font-family: var(--font-body) !important;
}

/* Kill the native Windows dropdown look entirely — this is where the
   "blue" came from. Custom charcoal chevron, brand focus ring. */
.ax-page select {
    cursor: pointer;
    appearance: none !important;
    -webkit-appearance: none !important;
    -moz-appearance: none !important;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%233B3B3B' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E") !important;
    background-repeat: no-repeat !important;
    background-position: right 12px center !important;
    padding-right: 34px !important;
}

/* ONE HEIGHT FOR A BOX YOU TYPE IN (5 October 2026, feedback #252). With one style, the boxes still came in seven
   heights, 34 to 46 pixels, because each page's own line spacing set the height. They were 38 on a user's page, 40 on
   a new opportunity, 44 on Appearance and Library and 46 on Clients, so a box and the list or button beside it didn't
   line up. Found by measuring every box on every page. Every one-line box and every dropdown is now 40 pixels, the
   height of the house buttons beside them. A box of several lines is left to grow. */
.ax-page select,
.ax-page input:not([type]),
.ax-page input[type="search"],
.ax-page input[type="text"],
.ax-page input[type="date"],
.ax-page input[type="time"],
.ax-page input[type="datetime-local"],
.ax-page input[type="email"],
.ax-page input[type="password"],
.ax-page input[type="tel"],
.ax-page input[type="url"],
.ax-page input[type="number"] {
    box-sizing: border-box !important;
    height: 40px !important;
    min-height: 40px !important;
    padding-top: 0 !important;
    padding-bottom: 0 !important;
}

.ax-page select option {
    background: var(--color-surface);
    color: var(--color-charcoal);
}

.ax-page select:focus,
.ax-page input:focus,
.ax-page textarea:focus {
    outline: none !important;
    border-color: var(--color-primary) !important;
    box-shadow: 0 0 0 3px rgba(242, 108, 33, 0.12) !important;
}

/* ONE SEARCH BOX (5 October 2026, feedback #252: "so many as still all over the place"). A search box with its
   magnifier is a <label> holding the icon and the input, and five pages drew it five ways. On Projects, Users and the
   Action Centre the label was a box and the rule above drew a second box round the input inside it; People put a "⌕"
   character beside a box; Compliance put the word "Search" there. Found by measuring every page for a typing box
   inside another box. Now the label is the box - the same border, corners, height and orange focus as every other
   box you type in - with the magnifier inside it, and the input in it is bare. */
.ax-page .ax-search,
.ax-page label.search-box {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 8px;
    box-sizing: border-box;
    height: 40px;
    min-height: 0;
    min-width: min(260px, 100%);
    padding: 0 14px;
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-component);
    background: var(--color-surface);
    box-shadow: none;
    color: var(--color-gunmetal);
    cursor: text;
}

.ax-page .ax-search:focus-within,
.ax-page label.search-box:focus-within {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(242, 108, 33, 0.12);
}

.ax-page .ax-search svg,
.ax-page label.search-box svg {
    width: 17px;
    height: 17px;
    flex: none;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
}

.ax-page .ax-search input,
.ax-page label.search-box input,
.ax-page .ax-search input:focus,
.ax-page label.search-box input:focus {
    flex: 1 1 auto;
    width: 100%;
    min-width: 0;
    height: 100% !important;
    min-height: 0;
    padding: 0 !important;
    border: 0 !important;
    border-radius: 0 !important;
    background: transparent !important;
    box-shadow: none !important;
    outline: none !important;
}

/* TYPE ON A DARK SURFACE KEEPS ITS OWN COLOUR (23 September 2026).
   The heading rules below are written for the cream canvas and carry !important, so any heading on
   a dark panel rendered charcoal on charcoal - invisible. Adam Deane, of the landing band: "can see
   some text as its dark and the background is dark." A surface that sets its own dark background
   marks itself .ax-on-dark, and the ink rules step aside for everything inside it. */
.ax-page .ax-on-dark h1,
.ax-page .ax-on-dark h2,
.ax-page .ax-on-dark h3,
.ax-page .ax-on-dark h4 {
    color: inherit !important;
}

/* Headings — small, present, out of the way. Focus goes to the work. */
.ax-page h1 {
    font-family: var(--font-heading) !important;
    font-size: 1.45rem !important;
    font-weight: 700 !important;
    color: var(--color-charcoal) !important;
    letter-spacing: 0 !important;
}

.ax-page h2 {
    font-family: var(--font-heading) !important;
    font-size: 1.05rem !important;
    font-weight: 700 !important;
    color: var(--color-charcoal) !important;
}

.ax-page h3 {
    font-family: var(--font-heading) !important;
    font-size: 0.95rem !important;
    font-weight: 600 !important;
}

.ax-page .eyebrow {
    color: var(--color-primary) !important;
    font-size: 0.66rem !important;
    font-weight: 800 !important;
    letter-spacing: 0.14em !important;
}

/* Primary actions — always brand orange, never page-local greens/blues */
.ax-page .primary-action,
.ax-page .primary-button,
.ax-page .hero-action:not(.secondary),
.ax-page .action-button {
    background: var(--color-primary) !important;
    color: #fff !important;
    border: none !important;
    border-radius: var(--radius-component) !important;
    font-weight: 650 !important;
    cursor: pointer;
    transition: background var(--motion-duration) var(--motion-easing),
                transform var(--motion-duration) var(--motion-easing);
}

.ax-page .primary-action:hover,
.ax-page .primary-button:hover,
.ax-page .hero-action:not(.secondary):hover,
.ax-page .action-button:hover {
    background: var(--color-primary-dark) !important;
    transform: translateY(-1px);
}

/* Secondary / quiet buttons — warm neutral, thin border.

   WHERE A BUTTON SITS DOES NOT OUTRANK WHAT IT IS (21 September 2026). Two of these selectors
   name a CONTEXT — any button inside a row-actions group or a section heading — and both this
   rule and the primary one are !important, so for a .primary-button inside a section heading the
   context won on source order. Resources drew "New assignment" in brand orange and "Allocate
   resource", the same class in a heading, in white. The three classes that mean "this is the
   main action here" are now excluded from the context selectors, so the class decides. */
.ax-page .secondary-button,
.ax-page .row-actions button:not(.primary-button):not(.primary-action):not(.action-button),
.ax-page .section-heading button:not(.primary-button):not(.primary-action):not(.action-button),
.ax-page .hero-action.secondary,
.ax-page button.quiet {
    background: var(--color-surface) !important;
    color: var(--color-charcoal) !important;
    border: 1px solid var(--color-divider) !important;
    border-radius: var(--radius-component) !important;
    cursor: pointer;
    transition: border-color var(--motion-duration) var(--motion-easing),
                color var(--motion-duration) var(--motion-easing);
}

.ax-page .secondary-button:hover,
.ax-page .row-actions button:not(.primary-button):not(.primary-action):not(.action-button):hover,
.ax-page .section-heading button:not(.primary-button):not(.primary-action):not(.action-button):hover,
.ax-page .hero-action.secondary:hover,
.ax-page button.quiet:hover {
    border-color: var(--color-primary) !important;
    color: var(--color-primary-dark) !important;
}

/* Accent text that pages painted green/teal/blue → brand copper */
.ax-page .workflow-card span,
.ax-page .project-identity small,
.ax-page .record-number,
.ax-page .connector-type,
.ax-page .project-type {
    color: var(--color-primary-dark) !important;
}

/* Status pills — tokenised, quiet */
.ax-page .readiness-list span,
.ax-page .status,
.ax-page .status-pill,
.ax-page .mapping-pill {
    border-radius: 999px !important;
    font-size: 0.7rem !important;
    font-weight: 700 !important;
    background: var(--color-panel) !important;
    color: var(--color-gunmetal) !important;
}

.ax-page .readiness-list .ready,
.ax-page .status.complete,
.ax-page .status-pill.active {
    background: rgba(46, 125, 50, 0.12) !important;
    color: var(--color-success) !important;
}

.ax-page .readiness-list .attention,
.ax-page .status.review,
.ax-page .status-pill.warning {
    background: rgba(249, 168, 37, 0.16) !important;
    color: #8a5a00 !important;
}

/* Readable width — long full-screen rows are hard to scan */
.ax-page {
    max-width: 1440px;
    margin-inline: auto;
    width: 100%;

    /* MEASURED, 24 Aug 2026: without this the page scrolled sideways at every
       width. .ax-page carries `width: 100%` AND `padding: var(--space-4)`, and
       there is no global box-sizing reset — only .ax-authinput sets it. As
       content-box the border-box width became 100% + 48px, `margin-inline: auto`
       resolved to a NEGATIVE right margin, and the document overflowed by 40px
       (scrollWidth 1305 vs clientWidth 1265). Every page using .ax-page was
       affected, which is why it never looked like one page's bug. */
    box-sizing: border-box;
}

/* Tab / filter rows: never overlap — wrap instead */
.ax-page .job-filters,
.ax-page .view-switch,
.ax-page [role="group"] {
    display: flex !important;
    flex-wrap: wrap !important;
    gap: 6px !important;
}

/* THE HAMMER — every button on every page (front page excluded) gets the
   brand look, regardless of what its page own stylesheet says.
   Primary/action classes stay orange via the rules above.

   .axcal-day is excluded because a calendar day is a button only so that it can be reached from
   the keyboard, not because it is a control. The hammer gave all thirty-five of them a border and
   an 8px radius, which turned the month into a tray of rounded boxes; the exception is stated here,
   where the rule is, rather than fought with a louder !important in the component. */
/* A CHOSEN CONTROL IS EXCLUDED, not argued with. The "selected tab / active filter = orange"
   rule below scores three classes; this hammer scores seven, and both carry !important - so the
   hammer has been winning since it was written and NO button inside .ax-page has been able to show
   that it is the chosen one. The Library filter chips rendered white-on-white: the selected filter
   was invisible and so was its count. Excluding the three chosen-state classes here is the fix;
   raising the other rule to eight classes would only move the argument.

   .ax-list-button is excluded for the reason .axcal-day is (21 September 2026). An email in the
   mailbox list and a folder in its folder tree are buttons only so they can be reached from the
   keyboard; they are ROWS, and a list of rows each boxed with a border and a radius stops reading
   as a list. The hammer boxed every email and all 169 Outlook folders, and the owner looked at the
   result and said the inbox was "nothing like an email place". The row is styled by the list it
   belongs to, and the exception is stated here, where the rule is. */
.ax-page:not(.activity-page) button:not(.action-button):not(.primary-button):not(.primary-action):not(.hero-action):not(.close-button):not(.axcal-day):not(.ax-list-button):not(.active):not(.selected):not(.is-on) {
    background: var(--color-surface) !important;
    color: var(--color-charcoal) !important;
    border: 1px solid var(--color-divider) !important;
    border-radius: var(--radius-component) !important;
    font-family: var(--font-body) !important;
    transition: border-color var(--motion-duration) var(--motion-easing),
                color var(--motion-duration) var(--motion-easing),
                background var(--motion-duration) var(--motion-easing);
}

.ax-page:not(.activity-page) button:not(.action-button):not(.primary-button):not(.primary-action):not(.hero-action):not(.axcal-day):not(.ax-list-button):not(.active):not(.selected):not(.is-on):hover:not(:disabled) {
    border-color: var(--color-primary) !important;
    color: var(--color-primary-dark) !important;
}

/* Selected tab / active filter = orange, everywhere.

   .is-on IS IN THIS LIST because the hammer above forces every button to the surface colour with
   !important, so a page that writes its own selected state loses it silently. The Library filter
   chips set `background: var(--color-primary-dark)` for .is-on and rendered WHITE, with a white
   count on a white chip - the selected filter was invisible and so was its number. Four pages use
   .is-on this way. A page inventing a fifth name for "chosen" will lose it the same way, which is
   an argument for these three and not a fourth. */
.ax-page:not(.activity-page) button.active,
.ax-page:not(.activity-page) button.selected,
.ax-page:not(.activity-page) button.is-on,
.ax-page:not(.activity-page) .summary-card.selected {
    background: var(--color-primary) !important;
    color: #fff !important;
    border-color: var(--color-primary) !important;
}

/* Catch-all for stray coloured chips: anything named pill/badge/tag/chip */
.ax-page:not(.activity-page) :is([class*="pill"], [class*="badge"], [class*="-tag"], [class*="chip"]) {
    background: var(--color-panel) !important;
    color: var(--color-gunmetal) !important;
    border-radius: 999px !important;
}

/* Accent text painted green/teal by page stylesheets → brand copper */
.ax-page:not(.activity-page) .project-identity small,
.ax-page:not(.activity-page) .record-number,
.ax-page:not(.activity-page) .workflow-card span,
.ax-page:not(.activity-page) .register-heading strong,
.ax-page:not(.activity-page) .map-register strong {
    color: var(--color-primary-dark) !important;
}

.ax-page .summary-card,
.ax-page .summary-grid article {
    background: var(--color-surface) !important;
    border: 1px solid var(--color-divider) !important;
    color: var(--color-charcoal) !important;
    padding: var(--space-3) !important;
    border-radius: var(--radius-component) !important;
}

.ax-page .summary-card strong,
.ax-page .summary-grid article strong {
    color: var(--color-primary) !important;
    font-size: 1.5rem;
}

.ax-page button:not(.action-button):not(.primary-button):not(.axcal-day) {
    background: var(--color-surface);
    border: 1px solid var(--color-divider);
    color: var(--color-charcoal);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-component);
    cursor: pointer;
    font-size: 0.9rem;
    transition: all 150ms ease-in-out;
}

.ax-page button:not(.action-button):not(.primary-button):not(.axcal-day):hover {
    border-color: var(--color-primary);
    color: var(--color-primary);
}

/* A LINK DRESSED AS A BUTTON HAS THE SAME CORNERS (5 October 2026, feedback #252). An <a class="ax-btn"> kept .ax-btn's
   12px corners while every <button> on the page took 8px from the rule above, so "New project" (a link) and "Save
   changes" (a button) were different shapes - found by measuring the main button on every page. */
.ax-page a.ax-btn { border-radius: var(--radius-component); }

.ax-page .hero-action {
    background: var(--color-surface) !important;
    border: 1px solid var(--color-divider) !important;
    color: var(--color-charcoal) !important;
    padding: var(--space-2) var(--space-3) !important;
}

.ax-page .hero-action:not(.secondary):hover {
    background: var(--color-primary) !important;
    color: white !important;
}

.ax-page .status-pill {
    background: var(--color-panel) !important;
    color: var(--color-charcoal) !important;
}

.ax-page .workflow-card {
    background: var(--color-surface) !important;
    border: 1px solid var(--color-divider) !important;
    color: var(--color-charcoal) !important;
    padding: var(--space-4) !important;
    border-radius: var(--radius-component) !important;
    text-align: left !important;
}

.ax-page .workflow-card:hover:not(:disabled) {
    border-color: var(--color-primary) !important;
    transform: translateY(-2px);
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
}

.ax-page .workflow-card span {
    color: var(--color-primary) !important;
    font-size: 1.2rem !important;
    font-weight: 700 !important;
}

.ax-page .eyebrow {
    color: var(--color-primary) !important;
}

@media (max-width: 850px) {
    .ax-page { padding: var(--space-3); gap: var(--space-3); }
    .page-header { flex-direction: column; }
    .projects-grid { grid-template-columns: 1fr; }
}

/* ---- WR-61 slice 2: intake review, sponsor and parties ------------------- */
.sponsor-status { padding: 4px 12px; border-radius: 999px; font-size: .78rem;
  font-weight: 600; letter-spacing: .01em; white-space: nowrap; }
.sponsor-status.verified { background: #e6f4e4; color: #2f6b30; }
.sponsor-status.blocked { background: #fbe6e2; color: #a03626; }
.sponsor-status.attention { background: #fdf1d8; color: #8a6316; }
.sponsor-status.pending { background: #eee9e2; color: #6a6157; }

.review-warning { border: 1px solid #e0b64f; background: #fdf7e6; border-radius: 10px;
  padding: 14px 16px; margin: 14px 0; }
.review-warning strong { display: block; margin-bottom: 4px; }
.review-warning ul { margin: 6px 0 0; padding-left: 20px; }

/* Evidence must never be cut off by a narrow pane - it scrolls instead. */
.verification-scroll { overflow-x: auto; margin-top: 12px; }
.verification-table { width: 100%; min-width: 720px; border-collapse: collapse;
  font-size: .84rem; }
.verification-table th { text-align: left; padding: 8px 10px; border-bottom: 2px solid #e2d9cd;
  color: #6a6157; font-weight: 600; }
.verification-table td { padding: 8px 10px; border-bottom: 1px solid #f0eae1;
  vertical-align: top; }
.verification-table tr.party-empty td { color: #a49a8d; }

.outcome-buttons { display: flex; flex-direction: column; gap: 8px; align-items: stretch; }
.outcome-buttons button { width: 100%; }
.danger-button { background: #a03626; color: #fff; border: 1px solid #8c2f21;
  border-radius: 8px; padding: 10px 16px; font-weight: 600; cursor: pointer; }
.danger-button:disabled { opacity: .5; cursor: not-allowed; }

/* A blocked action must LOOK blocked. An enabled-looking button that silently
   does nothing teaches people the interface is broken rather than that the
   decision is gated. */
.outcome-buttons button:disabled { opacity: .45; cursor: not-allowed; filter: grayscale(1); }

/* On a phone the sponsor status must wrap rather than run off the edge — a
   half-visible "Legal sponsor verified — natural per…" is worse than two lines. */
@media (max-width: 640px) {
  .sponsor-status { white-space: normal; display: inline-block; margin-top: 6px; }
}

/* A missing verification basis is the thing a reviewer must not skim past. */
.basis-missing { color: #a03626; }
.basis-notes { font-weight: 400; font-size: .86rem; line-height: 1.45; }

/* ---- WR-62 slice 3: activity-area review -------------------------------- */
.review-map { height: 460px; border: 1px solid #e2d9cd; border-radius: 10px;
  background: #f6f2ec; margin: 12px 0; }
.map-layer-toggles { display: flex; gap: 16px; font-size: .84rem; color: #6a6157; }
.map-layer-toggles label { display: flex; align-items: center; gap: 6px; }

.map-legend { display: flex; flex-wrap: wrap; gap: 18px; font-size: .84rem;
  color: #4a4238; margin: 8px 0 16px; }
.map-legend span { display: flex; align-items: center; gap: 7px; }
.map-legend .swatch { width: 16px; height: 12px; border-radius: 2px; display: inline-block; }
.swatch.property { background: #ffffff; border: 1px dashed #4a4a4a; }
.swatch.activity { background: rgba(217,43,43,.35); border: 1px solid #c01c1c; }
.swatch.added    { background: rgba(240,165,0,.45); border: 1px solid #b37700; }
.swatch.removed  { background: rgba(122,47,176,.40); border: 1px solid #7a2fb0; }
.swatch.excluded { background: rgba(150,150,150,.18); border: 1px dashed #8a8a8a; }

.area-summary .off-property { color: #b37700; }
.area-summary .hash, td.hash { font-family: Consolas, monospace; font-size: .78rem; }

/* The 13 pre-generation questions. */
.works-grid { display: grid; gap: 2px; margin: 14px 0; }
.works-row { display: grid; grid-template-columns: minmax(200px, 1fr) auto;
  align-items: center; gap: 12px; padding: 7px 10px; border-radius: 6px; }
.works-row:nth-child(odd) { background: #faf7f2; }
.works-label { font-size: .9rem; }
.works-answers { display: flex; gap: 6px; }
.works-option { display: flex; align-items: center; gap: 5px; padding: 4px 10px;
  border: 1px solid #ded4c6; border-radius: 999px; font-size: .82rem; cursor: pointer;
  background: #fff; white-space: nowrap; }
.works-option.chosen { border-color: var(--color-primary-dark); background: var(--color-primary-light); font-weight: 600; }
.works-notes { display: block; margin-top: 14px; }
.works-notes textarea { display: block; width: 100%; margin-top: 6px; }

/* One frontage, one decision. */
.frontage { border: 1px solid #e2d9cd; border-left-width: 5px; border-radius: 10px;
  padding: 14px 16px; margin: 12px 0; }
.frontage.included  { border-left-color: #b37700; background: #fffaf0; }
.frontage.excluded  { border-left-color: #b0b0b0; background: #fafafa; }
.frontage.unsure    { border-left-color: #e0b64f; background: #fdfaf0; }
.frontage.undecided { border-left-color: #ded4c6; }
.frontage-head { display: flex; justify-content: space-between; align-items: flex-start;
  gap: 16px; }
.frontage-head h3 { margin: 0 0 2px; font-size: 1rem; }
.frontage-reason { font-size: .88rem; line-height: 1.5; color: #4a4238; margin: 8px 0; }
.frontage-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.frontage .source { font-size: .74rem; color: #8a8178; margin-top: 8px; }

.decision-pill { padding: 3px 11px; border-radius: 999px; font-size: .76rem;
  font-weight: 600; white-space: nowrap; }
.decision-pill.included  { background: #fdf1e0; color: #8a5a00; }
.decision-pill.excluded  { background: #efefef; color: #666; }
.decision-pill.unsure    { background: #fdf6e0; color: #8a6316; }
.decision-pill.undecided { background: #f4efe8; color: #6a6157; }

.review-warning.difference { border-color: #9ec7e8; background: #f2f8fd; }
.upload-label { display: block; font-size: .84rem; color: #4a4238; margin-top: 6px; }
.upload-label input { display: block; margin-top: 5px; }

.check-pass { color: #2f6b30; font-weight: 600; }
.check-fail { color: #a03626; font-weight: 600; }
tr.superseded { opacity: .58; }
tr.superseded td:first-child::after { content: " (superseded)"; font-weight: 400;
  font-size: .74rem; color: #8a8178; }

/* The difference map draws added area green and removed purple. The legend has to
   agree with the map: an amber swatch next to a green polygon is worse than no
   legend at all. */
.swatch.diff-added   { background: rgba(31,138,59,.45); border: 1px solid #1f8a3b; }
.swatch.diff-removed { background: rgba(122,47,176,.40); border: 1px solid #7a2fb0; }

/* The breadcrumb above a workspace header. Used by several pages and never
   actually styled — it has been rendering as bare inline text with no spacing. */
.breadcrumb-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: .82rem; color: #8a8178; margin-bottom: 6px; }
.breadcrumb-row .back-link { color: var(--color-primary-dark); text-decoration: none; }
.breadcrumb-row .back-link:hover { text-decoration: underline; }
.breadcrumb-row strong { color: #4a4238; font-weight: 600; }

/* WR-63 slice 4 — the preliminary screening gate, shown on the enquiry workspace
   immediately above the commercial document. It lives here rather than in a scoped
   sheet because EnquiryWorkspace.razor has none. Amber until the screen has been
   confirmed, green once a fee proposal is permitted: the state a person needs to
   read is "may I quote yet", not "is there a screen". */
.screen-gate { padding: 12px 14px; border-radius: 9px; margin: 4px 0 0;
  border-left: 5px solid #c8862a; background: #fffaf1; font-size: .88rem;
  line-height: 1.55; color: #4a4238; }
.screen-gate.is-open { border-left-color: #2f7d44; background: #f5fbf6; }
.screen-gate strong { display: block; margin-bottom: 4px; color: #3a332c; }

/* WR-64 slice 5 — the promotion conditions, shown all together.
   Every condition is listed, met and unmet alike, because the shape of what is
   outstanding is as useful as the list of it: someone who can see nine ticks and
   one cross knows they are nearly there. Unmet rows carry their reason inline
   rather than in a tooltip nobody opens. */
.promotion-conditions { list-style: none; padding: 0; margin: 12px 0 0; }
.promotion-conditions li { display: grid;
  grid-template-columns: 20px minmax(220px, auto) 1fr; gap: 4px 10px;
  align-items: baseline; padding: 7px 10px; border-radius: 7px; font-size: .87rem; }
.promotion-conditions li.met { color: #4a4238; }
.promotion-conditions li.unmet { background: #fff6f4; }
.promotion-conditions .mark { font-weight: 700; }
.promotion-conditions li.met .mark { color: #2f7d44; }
.promotion-conditions li.unmet .mark { color: #a52a1e; }
.promotion-conditions li.unmet .name { font-weight: 600; }
.promotion-conditions .why { grid-column: 3; color: #7a2318; font-size: .82rem;
  line-height: 1.5; }

/* The way back, on the shared page header. Eighteen pages had grown their own .back-link with
   their own arrow, spacing and colour; this is that need met once. */
.ax-os-back {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 10px;
    color: var(--color-gunmetal);
    font-size: var(--archex-text-sm, 13.5px);
    font-weight: 700;
    text-decoration: none;
}

.ax-os-back:hover { color: var(--color-primary-dark); }

.ax-os-back:focus-visible {
    outline: 3px solid var(--color-primary);
    outline-offset: 3px;
    border-radius: 4px;
}

/* ================================================================================================
   THE SHARED PAGE HEADER WINS, WHEREVER IT IS (20 September 2026)
   ------------------------------------------------------------------------------------------------
   AxOperatingHeader was rendering two different ways depending on the page's root class, which is
   the opposite of what a shared header is for:

       inside .ax-page     title 23.2px, eyebrow grey,   margin 16px
       everywhere else     title 36px,   eyebrow orange, margin 24px

   Two causes, both above in this file:

     1. `.ax-page h1 { font-size: 1.45rem !important }` catches the header's own title along with
        every other h1 on the page.

     2. `.ax-page .ax-os-header p:not(.eyebrow)` was written to spare the eyebrow and does not,
        because the shared header renders class="ax-os-eyebrow" — which is not "eyebrow", so the
        selector matches it and greys out the very thing it was meant to skip.

   Rather than unpick two !important rules that dozens of pages still lean on, this restores the
   header's own styling inside them. It is placed last so it wins on order, and it is scoped to the
   header so nothing else on those pages moves.
   ============================================================================================== */

.ax-page .ax-os-heading h1,
.ax-workspace .ax-os-heading h1 {
    font-size: var(--archex-text-2xl) !important;
    line-height: 1.12 !important;
    letter-spacing: -.02em !important;
}

/* The `p` in these two selectors is NOT redundant, and removing it silently reverts the eyebrow to
   grey. The rule being overridden is `.ax-page .ax-os-header p:not(.eyebrow)`, which scores three
   classes PLUS an element; a three-class selector loses to it however late it appears and however
   many !importants it carries. Measured, not guessed: the first attempt here omitted the `p` and
   the eyebrow stayed grey while the browser reported this rule as matching. */
.ax-page .ax-os-header p.ax-os-eyebrow,
.ax-workspace .ax-os-header p.ax-os-eyebrow {
    margin: 0 0 8px !important;
    color: var(--color-primary-dark) !important;
    font-size: .7rem !important;
    font-weight: 800 !important;
    letter-spacing: .16em !important;
    text-transform: uppercase !important;
}

.ax-page .ax-os-header p.ax-os-subtitle,
.ax-workspace .ax-os-header p.ax-os-subtitle {
    margin: 8px 0 0 !important;
    color: var(--color-gunmetal) !important;
    font-size: var(--archex-text-base) !important;
    max-width: 78ch;
}

.ax-page .ax-os-header,
.ax-workspace .ax-os-header {
    align-items: flex-end !important;
    margin: 0 0 var(--space-4) !important;
}

/* The way back sits above the eyebrow and must not be caught by the p:not(.eyebrow) rule either. */
.ax-page .ax-os-back,
.ax-workspace .ax-os-back {
    font-size: var(--archex-text-sm) !important;
    color: var(--color-gunmetal) !important;
}

/* The breadcrumb trail on the shared page header. Four pages had each grown their own
   .breadcrumb-row with its own separator and spacing; this is that need met once. */
.ax-os-crumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin: 0 0 10px;
    color: var(--archex-faint, var(--color-gunmetal));
    font-size: var(--archex-text-sm, 13.5px);
    font-weight: 600;
}

.ax-os-crumbs a {
    color: var(--color-gunmetal);
    text-decoration: none;
    font-weight: 700;
}

.ax-os-crumbs a:hover { color: var(--color-primary-dark); text-decoration: underline; text-underline-offset: 3px; }

.ax-os-crumbs a:focus-visible {
    outline: 3px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: 3px;
}

/* Same specificity trap as the eyebrow above: inside .ax-page these would otherwise be caught by
   `.ax-page .ax-os-header p:not(.eyebrow)` and by the blanket link colours. */
.ax-page .ax-os-header .ax-os-crumbs,
.ax-workspace .ax-os-header .ax-os-crumbs {
    margin: 0 0 10px !important;
    font-size: var(--archex-text-sm) !important;
}

/* ================================================================================================
   THE STACKED HEADER STAYS INSIDE THE SCREEN (20 September 2026)
   ------------------------------------------------------------------------------------------------
   Below 850px the shared header stacks. Stacking on its own is not enough: two rules further up
   this file set `align-items: center !important` and then `align-items: flex-end !important` on
   `.ax-page .ax-os-header`, and in a column that sizes each child to its own content. A long
   subtitle therefore made the heading 946px wide inside a 360px phone, and Permissions, Audit and
   Governance could be dragged 833px sideways while every screenshot of it looked correct — what
   overflowed was off the side of the picture.

   This block has to carry !important to reach past those two, and it has to come last. It is the
   only place in this stylesheet where the phone layout is stated. */
@media (max-width: 850px) {
    .ax-os-header,
    .ax-page .ax-os-header,
    .ax-workspace .ax-os-header {
        flex-direction: column !important;
        align-items: stretch !important;
    }

    .ax-os-header > *,
    .ax-page .ax-os-header > *,
    .ax-workspace .ax-os-header > * {
        max-width: 100% !important;
        min-width: 0 !important;
    }

    .ax-os-header-actions { justify-content: flex-start !important; }
}

/* ================================================================================================
   A BUTTON IS THE SIZE OF A BUTTON (20 September 2026)
   ------------------------------------------------------------------------------------------------
   The rules above give .primary-button, .action-button and .secondary-button the brand colour, the
   border and the radius — and say nothing about their SIZE. A page that used the class without also
   styling it therefore got an orange control with the browser's own `padding: 1px 6px`: "New
   enquiry" on the enquiry register rendered 18px tall. Coloured correctly, and too small to press.

   Stated here, beside the rules that made the class mean something, rather than in each page.

   A FLOOR WAS NOT ENOUGH (21 September 2026). This began as a minimum, and said so: "anything that
   sets its own padding still wins". Measured across ten routes, the same two classes rendered at
   ten different heights — 36, 38, 39, 40, 42, 43, 44, 45, 47 and 50px — because twenty scoped
   sheets set their own padding or min-height, and the ones below the floor were on pages that
   never carried .ax-page at all, so none of this reached them.

   So it is now a ruler, and no longer gated on .ax-page. Two consequences worth understanding:

   The height is var(--archex-control-h), the same token .ax-btn uses. The application had two
   button systems — .ax-btn/.ax-btn-primary and .primary-button/.secondary-button, roughly half the
   pages each — and this at least makes them the same size.

   The declarations are !important because a scoped sheet's `.primary-button[b-xyz]` and a plain
   `.primary-button` here have equal specificity, and scoped CSS is served after this file. Without
   it the twenty local paddings win, which is exactly the state being corrected.
   ============================================================================================== */
.primary-action,
.primary-button,
.hero-action,
.action-button,
.secondary-button,
button.quiet {
    min-height: var(--archex-control-h) !important;
    padding: 0 12px !important;
    font-size: var(--archex-text-base);
}

/* A LINK DRESSED AS A BUTTON READS AS ONE (3 October 2026). "Run the preliminary screen" on the
   enquiry page is an <a class="primary-button">: at phone width the card stretches it full width and
   44px tall, and its words sat against the top edge, underlined like a link in a paragraph. A button
   holds its label in the middle and is not underlined. */
a.primary-action,
a.primary-button,
a.action-button,
a.secondary-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
}

/* A DELIBERATE SMALLER ONE. .secondary-button.compact is written on eight buttons and was 34px in
   ProjectWorkspace's own sheet. An explicit modifier is a decision, not drift, so it is honoured
   here rather than flattened — the same treatment .empty-state.compact gets. Under a thumb it
   still goes to 44px with everything else. */
.secondary-button.compact {
    min-height: 32px !important;
    padding: 0 12px !important;
    font-size: var(--archex-text-sm);
}

/* TOUCH. On a tablet or a phone the finger, not the cursor, is the instrument: 38px is comfortable
   with a mouse and small under a thumb. pointer:coarse is exactly the question being asked, so the
   dense desktop layout is left alone. The classes are named rather than every button, because a
   blanket rule would stretch the inline links inside prose to 44px as well. */
@media (pointer: coarse) {
    /* Ungated and !important for the same reason the rule above is: half the pages never carried
       .ax-page, and the desktop height above is now !important, which this has to outrank. */
    .primary-action,
    .primary-button,
    .hero-action,
    .action-button,
    .secondary-button,
    button.quiet,
    .text-button,
    .status-pill {
        min-height: 44px !important;
    }

    /* The pill's word in the middle of that height (3 October 2026). As an inline span it was
       44px of pill with "Reviewing" at the top and an empty rounded block hanging below it. */
    .status-pill {
        display: inline-flex;
        align-items: center;
    }
    /* .ax-btn's touch size lives beside .ax-btn itself, in the foundation: a class is declared in
       one stylesheet, and there is a check that says so. */

    /* The map zoom controls are OpenLayers own, and 20px square. A map is the thing most likely to
       be used on a tablet in the field, so they are the last controls that should stay mouse-sized. */
    .ol-zoom .ol-zoom-in,
    .ol-zoom .ol-zoom-out {
        width: 40px;
        height: 40px;
        font-size: 1.3rem;
    }

    /* An icon-only control is square, so it needs the width as well as the height. */
    .ax-page .ax-icon-btn,
    .ax-page .staff-menu-button,
    .ax-page .period-arrow,
    .ax-page .close-button {
        min-width: 44px;
        min-height: 44px;
    }
}

/* ================================================================================================
   EVERYTHING WRITTEN ON A CHOSEN CONTROL TAKES ITS COLOUR (20 September 2026)
   ------------------------------------------------------------------------------------------------
   The selected rule colours the control. Its CHILDREN kept whatever the page had given them, so the
   selected summary card on Reports became an orange fill with an orange number on it and the
   selected entry on the map register had an orange CHMP number on orange — both invisible.

   THIS BLOCK IS LAST IN THE FILE ON PURPOSE. Several accent rules above also carry !important at
   the same specificity — "accent text that pages painted green → brand copper" is one — and among
   equal !important declarations the last one wins. Written earlier in the file it lost, and the
   map register's CHMP number stayed orange-on-orange.

   A chip with its own fill inside a chosen control is given the translucent treatment instead of
   inheriting, because inheriting made the schedule's tab icon white on its own white square.
   ============================================================================================== */
.ax-page:not(.activity-page) button.active *,
.ax-page:not(.activity-page) button.selected *,
.ax-page:not(.activity-page) button.is-on *,
.ax-page:not(.activity-page) .summary-card.selected * {
    color: inherit !important;
}

.ax-page:not(.activity-page) button.active .tab-icon,
.ax-page:not(.activity-page) button.selected .tab-icon,
.ax-page:not(.activity-page) button.is-on .tab-icon {
    background: rgba(255, 255, 255, .18) !important;
    border-color: rgba(255, 255, 255, .38) !important;
    color: #fff !important;
}

/* ================================================================================================
   FILTER CHIPS — .ax-chips / .ax-chip / .ax-chip-count          (20 September 2026)
   ------------------------------------------------------------------------------------------------
   ONE CONTROL, WRITTEN ONCE. Seven pages had drawn their own row of "show me only these" chips:
   Tasks (.filter), Library (.lib-filter), People (.filter-chip), OrganisationWorkspace
   (.project-filter-row button), Reports (.filter-button), Field records (.filter-row button) and
   the project diary (.ax-diary-filters button). Tasks and Library were byte-for-byte identical
   apart from the class name.

   They diverged because each lived in that page's SCOPED stylesheet, where no other component can
   reach it — so the only way to reuse the design was to paste it. Heights had drifted from 31px to
   48px for the same control, and three of them sat under the 40px touch target the rest of the
   application keeps. Selected state had three different treatments.

   WHY EVERY DECLARATION IS !important. Two rules above this one already govern any button inside
   .ax-page: the hammer forces unchosen buttons to the surface colour, and the stray-chip catch-all
   matches [class*="chip"] — which .ax-chip is. Without !important the catch-all wins and an
   unselected chip renders in panel grey; worse, `button.is-on *` forces a selected chip's count to
   `color: inherit` while the catch-all holds its background at panel, which is white on light grey.
   That is the same collision that made the Library chips invisible before, so it is spelled out
   here rather than rediscovered.

   Both .is-on and .active select a chip. Supporting the two names means a page migrating to this
   pattern changes only its container and base class, never the Razor conditional that writes the
   state — and those conditionals are where the attribute quote trap bites.
   ============================================================================================== */

.ax-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: var(--space-3, 16px);
}

.ax-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 40px;
    padding: 0 14px;
    border: 1px solid var(--color-divider) !important;
    border-radius: 999px;
    background: var(--color-surface) !important;
    color: var(--color-gunmetal) !important;
    font: inherit;
    font-weight: 700;
    white-space: nowrap;
    cursor: pointer;
}

.ax-chip:hover:not(:disabled) { border-color: var(--color-primary) !important; }

.ax-chip.is-on,
.ax-chip.active {
    background: var(--color-primary) !important;
    border-color: var(--color-primary) !important;
    color: #fff !important;
}

/* ONE SHAPE PER ROW OF CHIPS (5 October 2026, feedback #252). The chosen chip was round-ended and the others in the same
   row had square-ish corners, on seven pages (Library, Tasks, People, Field records, Spatial, Enquiries, a job's field
   records). The catch-all above makes anything named chip or pill round, but the button rule further up - which beats
   it - squares every button that isn't chosen, and the chosen one is exempt from that rule. This puts the round ends
   back on the unchosen ones; its selector is the button rule's, with the chip named, so it is the one more specific. */
.ax-page:not(.activity-page) button:is([class*="chip"], [class*="pill"]):not(.action-button):not(.primary-button):not(.primary-action):not(.hero-action):not(.close-button):not(.axcal-day):not(.ax-list-button):not(.active):not(.selected):not(.is-on) {
    border-radius: 999px !important;
}

.ax-chip .ax-chip-count {
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--color-panel) !important;
    color: var(--color-gunmetal) !important;
    font-size: var(--archex-text-xs, 12px);
    font-variant-numeric: tabular-nums;
}

/* Prefixed with .ax-page so this beats `button.is-on *`, which would otherwise force the count to
   inherit white while the catch-all held its background grey.

   The badge DARKENS rather than lightens. Both pages this replaced used a 26% white wash, which
   puts white digits on pale orange: measured on the Tasks chips at 2.35:1, under the 2.4 this
   application holds itself to. An 18% black wash over the same chip measures 4.26:1, and reads as
   inset rather than floating. */
.ax-page .ax-chip.is-on .ax-chip-count,
.ax-page .ax-chip.active .ax-chip-count,
.ax-chip.is-on .ax-chip-count,
.ax-chip.active .ax-chip-count {
    background: rgba(0, 0, 0, .18) !important;
    color: #fff !important;
}

/* ================================================================================================
   ONE PAGE GUTTER  (21 September 2026)
   ------------------------------------------------------------------------------------------------
   Measured across twelve routes, the page root's padding was 24, 26, 28, 30, 32, 40 and 51.2px —
   seven values. Moving between pages, the content stepped in and out from the rail each time. It
   is the kind of difference nobody names and everybody feels.

   Stated once, by the workspace, about whatever it holds. Naming the two shared root classes left
   Knowledge out -- its root carries neither -- and adding it by name would have been the eighth
   number in a different disguise. !important because each of
   those values is written in that page's own scoped sheet, which is served after this file and has
   equal specificity.

   Pages that must reach the edge — a map, a full-bleed canvas — opt out with .ax-full-bleed rather
   than by writing their own number again.
   ============================================================================================== */
.ax-app-workspace > *:not(.ax-full-bleed) {
    padding: var(--archex-page-gutter) !important;
}

/* ================================================================================================
   BETWEEN PAGES  (21 September 2026)
   ------------------------------------------------------------------------------------------------
   There was no page-loading indication anywhere in the application. You clicked, nothing changed,
   and the only way to know ArchEx had heard you was that the page eventually arrived. On a slow
   query that reads as a broken button, and people click again.

   A compass rose rather than a generic spinner: this is a mapping application. The needle turns,
   the card does not, which is how a compass actually behaves.
   ============================================================================================== */
.ax-navigating {
    position: absolute;
    inset-inline: 0;
    top: 0;
    z-index: 5;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--archex-gap-3);
    padding: var(--archex-gap-4);
    background: color-mix(in srgb, var(--color-background) 86%, transparent);
    backdrop-filter: blur(2px);
    color: var(--color-gunmetal);
    font-weight: 700;
}

.ax-navigating-mark { width: 32px; height: 32px; flex: 0 0 32px; overflow: visible; }

/* Shared ink for every mark: filled shapes in brand orange, quiet shapes in gunmetal, and
   anything that is a line stays a line. */
.ax-navigating-mark .ax-mark-strong { fill: var(--color-primary); stroke: none; }
.ax-navigating-mark .ax-mark-quiet  { fill: var(--color-gunmetal); stroke: none; }
.ax-navigating-mark .ax-mark-ring,
.ax-navigating-mark .ax-mark-line   { fill: none; stroke: var(--color-gunmetal); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.ax-navigating-mark rect.ax-mark-strong,
.ax-navigating-mark rect.ax-mark-quiet { stroke: none; }

/* Three movements, shared out across the kit so no two consecutive marks feel identical. */
.ax-mark-spin { transform-origin: 24px 24px; animation: ax-compass 1.1s cubic-bezier(.6, 0, .4, 1) infinite; }
.ax-mark-rock { transform-origin: 24px 34px; animation: ax-rock 1.25s ease-in-out infinite; }
.ax-mark-bob  { transform-origin: 24px 24px; animation: ax-bob 1.1s ease-in-out infinite; }

@keyframes ax-rock {
    0%, 100% { transform: rotate(-11deg); }
    50%      { transform: rotate(11deg); }
}

@keyframes ax-bob {
    0%, 100% { transform: translateY(-2.5px); }
    50%      { transform: translateY(2.5px); }
}

@keyframes ax-compass {
    0%   { transform: rotate(0deg); }
    55%  { transform: rotate(340deg); }
    75%  { transform: rotate(330deg); }
    100% { transform: rotate(360deg); }
}

/* A compass that spins for a reader who has asked for less motion is just a distraction. */
@media (prefers-reduced-motion: reduce) {
    .ax-mark-spin,
    .ax-mark-rock,
    .ax-mark-bob { animation: none; }
}

/* ------------------------------------------------------------------------------------------- */
/* WHAT THE APPLICATION SAYS BACK (21 September 2026)                                           */
/* ------------------------------------------------------------------------------------------- */
/* One appearance for an outcome, replacing ".save-message", which was defined three times and
   looked different in each: white with a red border in LibraryReview, blue on a hard-coded 7px
   radius in the intake sheet, and panel-with-green-text in OrganisationWorkspace — where it had
   no error variant at all, so a refusal there rendered in the colour of success.

   The refusal deliberately matches .ax-error, which the same application already used for the
   same idea. Two shapes for "this did not happen" was one too many. */
.ax-outcome {
    display: flex;
    flex-direction: column;
    gap: var(--archex-gap-2);
    margin: var(--archex-gap-4) 0;
    padding: var(--archex-gap-4) var(--archex-gap-5);
    border: 1px solid var(--color-divider);
    border-left-width: 3px;
    border-radius: var(--archex-radius-small);
    font-size: var(--archex-text-base);
}

.ax-outcome:focus { outline: none; }
.ax-outcome:focus-visible { outline: 2px solid var(--archex-ochre); outline-offset: 2px; }

.ax-outcome-title {
    font-family: var(--archex-font-heading);
    font-size: var(--archex-text-md);
    font-weight: 700;
}

.ax-outcome-body { margin: 0; }
.ax-outcome-actions { display: flex; gap: var(--archex-gap-3); flex-wrap: wrap; }

.ax-outcome-refusal {
    background: rgba(198, 40, 40, .05);
    border-color: rgba(198, 40, 40, .26);
    color: #7F1D1D;
}

.ax-outcome-done {
    background: rgba(46, 125, 50, .06);
    border-color: rgba(46, 125, 50, .28);
    color: #1B5E20;
}

/* Amber, not the brand ochre: .ax-notice already uses the ochre tint for standing information,
   and a caution has to be tellable from a note at a glance. #6B4A00 on this tint is 6.8:1. */
.ax-outcome-caution {
    background: rgba(180, 120, 0, .07);
    border-color: rgba(180, 120, 0, .30);
    color: #6B4A00;
}

.ax-outcome-note {
    background: var(--color-panel);
    border-color: var(--color-divider);
    color: var(--color-gunmetal);
}

/* ------------------------------------------------------------------------------------------- */
/* WHERE THINGS ARE KEPT (21 September 2026)                                                    */
/* ------------------------------------------------------------------------------------------- */
/* Three stores, two of them calling their contents "documents", and no page saying the other
   two existed — so a library of 19 sitting beside a register of 748 read as 729 lost files.
   This band is the sentence that was missing. It is navigation, not a filter: each count is the
   place that holds it, so it is built from links and reads as links. */
.ax-holdings {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--archex-gap-3);
    margin: var(--archex-gap-4) 0;
}

.ax-holdings .ax-holding {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--archex-gap-3) var(--archex-gap-4);
    border: 1px solid var(--color-divider);
    border-radius: var(--archex-radius-small);
    background: #fff;
    color: inherit;
    text-decoration: none;
}

.ax-holdings a.ax-holding:hover,
.ax-holdings a.ax-holding:focus-visible { border-color: var(--archex-ochre); }

/* The shelf you are standing on is stated, not offered. */
.ax-holdings .ax-holding.is-here { background: var(--color-panel); }

.ax-holdings .ax-holding strong {
    font-family: var(--archex-font-heading);
    font-size: var(--archex-text-xl);
    line-height: 1.1;
}

.ax-holdings .ax-holding > span {
    font-size: var(--archex-text-sm);
    font-weight: 700;
    color: var(--color-gunmetal);
}

.ax-holdings .ax-holding small {
    color: var(--color-gunmetal);
    font-size: var(--archex-text-sm);
    line-height: 1.4;
}

@media (max-width: 820px) {
    .ax-holdings { grid-template-columns: 1fr; }
}

/* Inside a card, beside the control that caused it: the same tones, less room. An upload refused
   under its own file picker does not need a page-sized box to be noticed. */
.ax-outcome.ax-outcome-compact {
    margin: var(--archex-gap-2) 0;
    padding: var(--archex-gap-2) var(--archex-gap-3);
    gap: 2px;
    font-size: var(--archex-text-sm);
}

/* ------------------------------------------------------------------------------------------- */
/* PRINTING (21 September 2026)                                                                  */
/* ------------------------------------------------------------------------------------------- */
/* The application had no print rules, so printing any page printed the brand bar, the top bar and
   the whole navigation rail beside a squeezed page. The SWMS is meant to be printed or saved as a
   PDF for the job file, and it is not the only page that will be. On paper, only the page. */
/* The shell's own print rules live with the shell, in archex-foundation.css. Only two things are here:
   classes this sheet owns, and the page gutter — which this sheet sets with !important, so its print
   override has to be here too. */
@media print {
    .ax-navigating,
    .no-print {
        display: none !important;
    }

    .ax-app-workspace > *:not(.ax-full-bleed) {
        padding: 0 !important;
        margin: 0 !important;
    }
}

/* ================================================================================================
   THE CARD THAT SAYS WHAT TO DO (24 September 2026)

   SHARED, NOT PASTED. It began life inside EnquiryWorkspace.razor.css, and the moment the
   screening page needed the same card the choice was to copy it or to move it here. Seven pages in
   this application each drew their own filter chip that way, and no two of them ended up the same
   — which is exactly the complaint this card exists to answer. Adam Deane: "nothing is the same".

   Any page can now open with one thing to do, and every one of them will look identical.
   ================================================================================================ */
/* ---- THE CARD THAT SAYS WHAT TO DO -------------------------------------------------------------

   BIGGER THAN EVERYTHING ELSE ON PURPOSE. It is the answer to "what do I do with this", which is
   the question somebody opens an enquiry to ask, and the page's whole failure was that the answer
   was the same size as nine things that were not the answer. */

.next-card {
    padding: 22px 24px;
    border-left: 4px solid var(--archex-ochre, #F26C21);
}

.next-eyebrow {
    margin: 0;
    color: var(--archex-ochre-strong, #C9541A);
    font-size: 0.68rem;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
}

.next-title {
    margin: 6px 0 0;
    font-family: var(--archex-font-heading, inherit);
    font-size: 1.45rem;
    line-height: 1.2;

    /* SET, NOT INHERITED. A global h1-h6 colour rule is why headings on tinted surfaces elsewhere
       in the application rendered near-black on near-black; this one names its own colour so a
       later change to the waiting or done tint cannot swallow it. */
    color: var(--archex-text, #2B2B2B);
}

.next-why {
    max-width: 62ch;
    margin: 10px 0 0;
    color: var(--archex-muted, #3B3B3B);
    line-height: 1.55;
}

.next-do {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 18px;
}

/* THE BRIEF (3 October 2026): whether a CHMP is required, in the next-step card, worked out by ArchEx.
   The answer is the card's title; the reasons are short lines under it, the assumptions quieter. */
.brief-reasons {
    margin: 12px 0 0;
    padding-left: 20px;
    line-height: 1.55;
}

.brief-reasons li + li { margin-top: 4px; }

.brief-label {
    margin: 14px 0 4px;
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: var(--archex-muted, #3B3B3B);
}

.brief-assumed {
    margin: 0;
    padding-left: 20px;
    font-size: 0.92rem;
    line-height: 1.5;
    color: var(--archex-muted, #3B3B3B);
}

.brief-source {
    margin: 12px 0 0;
    font-size: 0.85rem;
    color: var(--archex-muted, #3B3B3B);
}

.brief-working {
    margin: 14px 0 0;
    font-weight: 600;
}

/* A number the brief needs, typed in place. */
.brief-ask { margin: 8px 0 0; }

.brief-ask > label {
    display: block;
    margin-bottom: 6px;
    font-weight: 600;
}

.brief-ask-row {
    display: flex;
    gap: 10px;
    align-items: center;
}

.brief-ask-row input {
    width: 7rem;
    min-height: 44px;
    padding: 8px 10px;
    border: 1px solid var(--archex-border, #E3DCD1);
    border-radius: 8px;
    font-size: 16px;
}

/* Recorded by ArchEx itself, shown at the top of the estimate step it unlocked. */
.brief-recorded {
    margin: 14px 0 18px;
    padding: 14px 16px;
    border-radius: 10px;
    background: var(--archex-panel, #F2EDE6);
}

.brief-recorded .brief-label:first-child { margin-top: 0; }

.brief-answer {
    margin: 2px 0 0;
    font-size: 1.15rem;
    font-weight: 700;
}

/* The two values side by side while the reason is being given. Somebody answering "why did this
   change" needs to see what it changed from without scrolling to find it. */
.next-change {
    margin: 14px 0 0;
    padding: 12px 14px;
    border-radius: 6px;
    background: var(--archex-panel, #F2EDE6);
    line-height: 1.6;
}

/* A secure link is read aloud down a phone as often as it is clicked, so it wraps rather than
   scrolling sideways and it is never truncated. */
.next-link {
    margin: 14px 0 0;
}

.next-link code {
    display: block;
    padding: 10px 12px;
    border: 1px solid var(--archex-border, #E3DCD1);
    border-radius: 6px;
    background: var(--archex-panel, #F2EDE6);
    font-size: 0.85rem;
    overflow-wrap: anywhere;
}

/* The four tones. Waiting is deliberately the quiet one: a card that shouts when the honest answer
   is "nothing, they have not come back to you" trains everybody to stop reading the loud ones. */
.next-card.is-doing { border-left-color: var(--archex-ochre, #F26C21); }

.next-card.is-attention {
    border-left-color: #C9541A;
    background: #FFF8F3;
}

.next-card.is-waiting {
    border-left-color: var(--archex-border, #E3DCD1);
}

.next-card.is-waiting .next-eyebrow {
    color: var(--archex-muted, #3B3B3B);
}

.next-card.is-done {
    border-left-color: var(--archex-success, #2E7D32);
}

.next-card.is-done .next-eyebrow {
    color: var(--archex-success, #2E7D32);
}


@media (max-width: 700px) {
    .next-card { padding: 18px 16px; }
    .next-title { font-size: 1.25rem; }

    /* Full-width buttons under a thumb. A next-step card usually has one button and it is the
       thing the page exists for, so it gets the width rather than sitting in a corner. */
    .next-do > * { flex: 1 1 auto; }
}

/* ---- The client's acceptance and their details, one line each (4 October 2026) ---------------------
   Adam Deane: "it should say somewhere that she accepted our term and conditions and a link to view it".
   A tick, the fact in plain words, and the two links - inside the next-step card, where he looks first. */
.acceptance-line {
    display: grid;
    grid-template-columns: 22px 1fr;
    gap: 10px;
    align-items: start;
    margin: 10px 0 0;
    padding: 10px 12px;
    border-radius: 10px;
    background: #F1F8F3;
    border: 1px solid #B9DCC4;
    font-size: .92rem;
    line-height: 1.45;
}

.acceptance-tick {
    color: var(--archex-success, #2E7D32);
    font-weight: 800;
    font-size: 1.05rem;
    line-height: 1.3;
}

.acceptance-line a { font-weight: 600; white-space: nowrap; }

.automatic-waiting {
    margin: 10px 0 0;
    padding: 10px 14px 10px 30px;
    border-radius: 10px;
    background: #FFF8F3;
    border: 1px solid #F0C9A8;
    font-size: .92rem;
}

.automatic-waiting li + li { margin-top: 4px; }

/* The acceptance record: the kept text as it was kept, and what checking it found, in words. */
.acceptance-card h2 { font-size: 1.05rem; margin: 0 0 10px; }
.acceptance-ok, .acceptance-bad { margin: 6px 0; padding: 8px 12px; border-radius: 8px; font-size: .92rem; }
.acceptance-ok { background: #F1F8F3; border: 1px solid #B9DCC4; }
.acceptance-bad { background: #FDECEA; border: 1px solid #E8A39B; font-weight: 600; }
.acceptance-text {
    white-space: pre-wrap;
    word-break: break-word;
    margin: 14px 0;
    padding: 14px 16px;
    background: #FBF8F2;
    border: 1px solid #E6DDCE;
    border-radius: 10px;
    font-size: .86rem;
    line-height: 1.5;
    max-height: none;
}
.acceptance-meta code { font-size: .78rem; word-break: break-all; }

/* ---- PHOTOS AND FILES IN STAFF MESSAGES (4 October 2026, feedback #186) ------------------------------------
   MessageBody: the words as written, line breaks kept; photos as pictures; any other file as its name and size.
   Shared by the phone's chat, the office's Messages page and the top bar's chat. */
.msg-words { white-space: pre-wrap; overflow-wrap: anywhere; }
.msg-files { display: flex; flex-direction: column; gap: 6px; }
.msg-words + .msg-files { margin-top: 8px; }
.msg-photo {
    display: block;
    width: min(260px, 100%);
    border-radius: 12px;
    overflow: hidden;
    background: rgba(0, 0, 0, .06);
}
.msg-photo img { display: block; width: 100%; height: auto; max-height: 340px; object-fit: cover; }
.msg-file {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    padding: 9px 11px;
    border-radius: 10px;
    background: rgba(0, 0, 0, .06);
    color: inherit;
    text-decoration: none;
}
/* On the phone a Word or Excel file is a button that opens the phone's reader (feedback #189). */
button.msg-file { width: 100%; border: 0; font: inherit; text-align: left; cursor: pointer; }
.msg-file-icon { flex: none; display: flex; }
.msg-file-icon svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linejoin: round; }
.msg-file-text { display: flex; flex-direction: column; min-width: 0; }
.msg-file-name { font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-file-size { font-size: .8em; opacity: .75; }

/* The office's composer: a paperclip beside the box, and the chosen files listed above it. */
.composer-attach { flex: none; cursor: pointer; }
.composer-file-input { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.composer-files { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 12px 0; }
.composer-file {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 999px;
    background: var(--color-panel, #f3efe8);
    font-size: .8rem;
}
.composer-problem { color: #b42318; font-size: .8rem; }

/* ==== SIGNING IN (4 October 2026, feedback #193) ===========================================================
   Adam Deane: "The 'heritage and archaeology' on the sign in page has a white buffer which makes it look funny.
   Fix it. Audit it, do what we did on the other pages. This is the first thing people see. Make it sexy."

   THE WHITE BUFFER. Both official logo files were cut from a white background, and the cut leaves a white edge
   round every letter - invisible on white, a white outline round HERITAGE & ARCHAEOLOGY on anything else. The
   card was 96% white with a blur over the beige page, so the outline showed. The logo now always sits on pure,
   opaque white, where it was drawn to sit; the files themselves are used exactly as supplied (brand/README).

   THE PHONE'S FRAME. The rest is the phone app's own look, so signing in feels like the app it opens: charcoal
   with a faint survey contour, one white card, big fields that don't make an iPhone zoom (17px), and the one
   thing to press in hi-vis yellow.

   NOT AN .ax-page. The three sign-in pages wear .ax-signin instead, on purpose: .ax-page carries the office
   pages' blanket corrections, one of which forces every button white with !important at twelve classes - it had
   turned the Sign in button plain white, and nothing short of a thirteenth class could win. The sign-in page is
   its own design; it takes what it needs of .ax-page here. */
.ax-signin {
    /* The phone app's own type: San Francisco on an iPhone, Segoe on the office's machines. */
    --signin-font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI Variable Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    position: relative;
    min-height: 100dvh;
    overflow: clip;
    isolation: isolate;
    font-family: var(--signin-font);
    background:
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='480' height='260' viewBox='0 0 480 260'%3E%3Cg fill='none' stroke='%23ffffff' stroke-opacity='.075' stroke-width='1.3'%3E%3Cpath d='M-20 52c70-34 130 30 210 6s150-58 310-18'/%3E%3Cpath d='M-20 80c70-34 130 30 210 6s150-58 310-18'/%3E%3Cpath d='M-20 108c70-34 130 30 210 6s150-58 310-18'/%3E%3Cpath d='M-20 136c70-34 130 30 210 6s150-58 310-18'/%3E%3Cpath d='M-20 164c70-34 130 30 210 6s150-58 310-18'/%3E%3Cpath d='M-20 192c70-34 130 30 210 6s150-58 310-18'/%3E%3Cpath d='M-20 220c70-34 130 30 210 6s150-58 310-18'/%3E%3Cellipse cx='372' cy='58' rx='34' ry='15'/%3E%3Cellipse cx='372' cy='58' rx='62' ry='29'/%3E%3Cellipse cx='96' cy='206' rx='26' ry='12'/%3E%3Cellipse cx='96' cy='206' rx='50' ry='24'/%3E%3C/g%3E%3C/svg%3E") center top / 560px auto repeat,
        radial-gradient(circle at 50% 0%, rgba(255, 204, 0, .10), transparent 46%),
        #16191C;
    color: #FFFFFF;
}

.ax-signin .ax-page-contours { display: none; }

.ax-signin .ax-centered-shell {
    justify-content: center;
    gap: 22px;
    padding: calc(env(safe-area-inset-top, 0px) + 28px) 16px calc(env(safe-area-inset-bottom, 0px) + 22px);
}

.ax-signin .ax-authcard {
    width: min(100%, 440px);
    padding: 30px 22px 24px;
    border: 0;
    border-radius: 28px;
    background: #FFFFFF;
    box-shadow: 0 30px 70px rgba(0, 0, 0, .5), 0 2px 8px rgba(0, 0, 0, .3);
    backdrop-filter: none;
    color: #111315;
}

.ax-signin .ax-brand-heading { gap: 22px; margin-bottom: 22px; }
.ax-signin .ax-brand-logo { width: min(100%, 290px); max-height: none; }
.ax-signin .ax-heading-group { gap: 6px; }
.ax-signin .ax-title { color: #111315; font-family: var(--signin-font); font-size: 28px; font-weight: 800; letter-spacing: -.02em; }
.ax-signin .ax-subtitle { color: #5B6168; font-size: 16px; line-height: 1.45; }
.ax-signin .ax-authfield > label,
.ax-signin .ax-authinput,
.ax-signin .ax-checkbox-option,
.ax-signin .ax-link,
.ax-signin .ax-form button.ax-button-primary { font-family: var(--signin-font); }

.ax-signin .ax-form { gap: 14px; }
.ax-signin .ax-authfield { gap: 6px; }
.ax-signin .ax-authfield + .ax-authfield { margin-top: 0; }
.ax-signin .ax-authfield > label { color: #111315; font-size: 15px; font-weight: 700; }

.ax-signin .ax-authinput {
    height: 54px;
    padding: 0 16px;
    border: 1.5px solid #CDCDC7;
    border-radius: 14px;
    background: #FFFFFF;
    color: #111315;
    font-size: 17px;
}
.ax-signin .ax-authinput:hover { border-color: #9A9A93; }
.ax-signin .ax-authinput:focus { border-color: #111315; box-shadow: 0 0 0 4px rgba(255, 204, 0, .6); }
.ax-signin .ax-authinput::placeholder { color: #8A8F95; }

/* The six-digit code: big, spaced and centred, as the authenticator app shows it. */
.ax-signin .ax-authinput[autocomplete="one-time-code"] {
    height: 62px;
    font-size: 26px;
    font-weight: 700;
    letter-spacing: .3em;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
.ax-signin .ax-authinput[autocomplete="one-time-code"]::placeholder { font-size: 17px; font-weight: 400; letter-spacing: 0; }

.ax-signin .ax-form-options {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 16px;
    margin: 2px 0 4px;
}
.ax-signin .ax-checkbox-option { color: #111315; font-size: 16px; gap: 10px; }
.ax-signin .ax-checkbox {
    flex: none;
    width: 24px;
    height: 24px;
    border: 1.5px solid #CDCDC7;
    border-radius: 7px;
    background: #FFFFFF;
}
.ax-signin .ax-checkbox:checked {
    border-color: #111315;
    background: #FFCC00 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5.5 12.5l4.2 4.2L18.5 8' fill='none' stroke='%23111315' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 18px no-repeat;
}
.ax-signin .ax-checkbox:focus-visible { outline: 3px solid rgba(255, 204, 0, .9); outline-offset: 2px; }

.ax-signin .ax-link,
.ax-signin .ax-link:link,
.ax-signin .ax-link:visited {
    color: #111315;
    text-decoration: underline;
    text-decoration-color: rgba(17, 19, 21, .3);
    text-decoration-thickness: 2px;
    text-underline-offset: 4px;
}
.ax-signin .ax-link:hover,
.ax-signin .ax-link:focus-visible { text-decoration-color: #FFCC00; }

/* The one thing to press: a button in a form, or a link where the next step is another page ("Sign in",
   "Send a new link"). */
.ax-signin .ax-authcard .ax-form button.ax-button-primary,
.ax-signin .ax-authcard .ax-form a.ax-button-primary {
    box-sizing: border-box;
    width: 100%;
    height: 56px;
    min-height: 56px;
    margin-top: 6px;
    padding: 0 18px;
    border: 0;
    border-radius: 16px;
    background: #FFCC00;
    color: #111315;
    font-size: 18px;
    font-weight: 800;
    letter-spacing: -.01em;
    box-shadow: inset 0 -3px 0 rgba(0, 0, 0, .14);
}
.ax-signin .ax-authcard .ax-form a.ax-button-primary {
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--signin-font);
    text-decoration: none;
}
.ax-signin .ax-authcard .ax-form .ax-button-primary:hover { background: #F5C400; color: #111315; }
.ax-signin .ax-authcard .ax-form .ax-button-primary:active { background: #EDBA00; transform: translateY(1px); box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .14); }
.ax-signin .ax-authcard .ax-form .ax-button-primary:focus-visible { outline: 3px solid #111315; outline-offset: 3px; }

.ax-signin .ax-secondary-actions { padding-top: 4px; }
.ax-signin .ax-secondary-actions .ax-link { color: #5B6168; font-size: 14px; font-weight: 600; text-decoration-color: rgba(91, 97, 104, .35); }
.ax-signin .ax-form > .ax-subtitle { font-size: 14px; text-align: center; }

.ax-signin .alert { border-radius: 12px; font-family: var(--signin-font); font-size: 15px; }
.ax-signin .ax-authinput.invalid { border-color: #D0281E; }
.ax-signin .ax-validation { font-size: 15px; }

/* Each field says what it needs under itself; the list above the form said it all again. It stays for a
   screen reader, which hears it as one alert. */
.ax-signin .ax-validation-summary {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

.ax-signin .ax-page-footer { margin-top: 0; color: rgba(255, 255, 255, .55); font-size: 13px; }
