/* ===========================================================================
   ArchEx Foundation - the single source of truth for the ArchEx interface
   Iteration two.
   ===========================================================================

   Load order is set in App.razor. This file is the sole owner of every
   --archex-* token; no other stylesheet may declare one. It carries no
   specificity overrides at all - a regression test asserts that.

   Canonical brand colours, recorded once:

     Burnt orange   var(--color-primary)   primary action, active state, brand accent
     Orange dark    var(--color-primary-dark)   hover / pressed
     Charcoal       #1F1F1F   primary text, dark surfaces
     Gunmetal       #3B3B3B   secondary text
     Background     #F8F8F6   application canvas
     Surface        #FFFFFF   cards, panels, tables
     Panel          #F2EDE6   inset panels
     Sandstone      var(--color-primary-light)   secondary accent
     Divider        #D8D8D8   borders

   ITERATION TWO CHANGES
     * Type scale raised throughout. Iteration one was 14px base with 11px
       labels, which read as a dense admin console rather than a product.
     * The navigation rail collapses to a 68px icon rail, toggled by a
       hamburger in the top bar, remembered per browser.
     * Below 1180px the rail becomes an overlay drawer with a backdrop.
     * Controls no longer resemble default browser widgets.
   =========================================================================== */

/* ---- 1. Tokens ---------------------------------------------------------- */

:root {
    /* Brand */
    --archex-ochre: var(--color-primary);
    --archex-ochre-strong: var(--color-primary-dark);
    --archex-ochre-soft: var(--color-primary-light);
    --archex-copper: var(--color-primary-dark);
    --archex-sandstone: var(--color-sandstone);

    /* Surfaces */
    --archex-canvas: var(--color-background);
    --archex-white: var(--color-surface);
    --archex-panel: var(--color-panel);
    --archex-charcoal: var(--color-charcoal);
    --archex-charcoal-soft: #2B312D;
    --archex-cream: var(--color-background);
    --archex-rail-bg: #1C1916;
    --archex-rail-hover: rgba(255, 255, 255, .08);

    /* Ink */
    --archex-text: var(--color-charcoal);
    --archex-muted: var(--color-gunmetal);
    --archex-faint: #6E6E6E;
    --archex-on-dark: #EDEAE5;
    --archex-on-dark-muted: #9C9791;

    /* Lines */
    --archex-border: var(--color-divider);
    --archex-border-soft: #E6E3DE;
    --archex-eucalyptus: #60786B;

    /* Status */
    --archex-success: var(--color-success);
    --archex-warning: var(--color-warning);
    --archex-danger: var(--color-danger);
    --archex-info: var(--color-info);

    /* Type. Brand faces first, then a native stack. */
    --archex-font-ui: Lato, "Segoe UI Variable Text", "Segoe UI", Inter, system-ui, -apple-system, Arial, sans-serif;
    --archex-font-heading: Montserrat, "Segoe UI Variable Display", "Segoe UI Semibold", "Segoe UI", Inter, system-ui, Arial, sans-serif;
    --archex-font-mono: "Cascadia Mono", Consolas, "SF Mono", Menlo, monospace;

    /* Raised in iteration two. Metadata is the smallest thing on screen at
       12px; nothing is smaller than that anywhere. */
    --archex-text-xs: 12px;     /* labels, eyebrows, badges */
    --archex-text-sm: 13.5px;   /* metadata, secondary rows */
    --archex-text-base: 15px;   /* body, navigation, controls */
    --archex-text-md: 17px;     /* card titles */
    --archex-text-lg: 22px;     /* section headings */
    --archex-text-xl: 28px;     /* metric values */
    --archex-text-2xl: 36px;    /* page title */

    /* Rhythm */
    --archex-gap-1: 4px;
    --archex-gap-2: 8px;
    --archex-gap-3: 12px;
    --archex-gap-4: 18px;
    --archex-gap-5: 26px;
    --archex-gap-6: 34px;
    --archex-gap-7: 52px;

    --archex-radius-small: 12px;
    --archex-radius-medium: 20px;
    --archex-radius-large: 28px;
    --archex-radius-pill: 999px;

    --archex-shadow: 0 1px 2px rgba(31, 24, 16, .05), 0 10px 28px -8px rgba(31, 24, 16, .14);
    --archex-shadow-hover: 0 3px 6px rgba(31, 24, 16, .08), 0 24px 52px -12px rgba(31, 24, 16, .24);
    --archex-focus-ring: 0 0 0 3px rgba(242, 108, 33, .30);

    /* Shell geometry */
    --archex-topbar-h: 64px;
    --archex-rail-w: 244px;
    --archex-rail-collapsed-w: 68px;
    --archex-gutter: 30px;

    /* One page gutter for every screen in the workspace: page roots had drifted to seven
       different values, so content jumped in and out as you moved between them. */
    --archex-page-gutter: clamp(20px, 2.2vw, 34px);
    --archex-workspace-max: 2100px;
    --archex-control-h: 40px;
}

/* ---- 2. Base ------------------------------------------------------------ */

html { box-sizing: border-box; -webkit-text-size-adjust: 100%; }
*, *::before, *::after { box-sizing: inherit; }

/* A GRID THAT NEVER STATED ITS COLUMNS STILL HAS ONE (20 September 2026).

   A grid with no grid-template-columns places its items in an IMPLICIT column, and an implicit
   column is sized to its content. On a phone that meant a 555px email card sat in a 328px section
   and the whole page could be dragged 210px sideways - and, because the column was as wide as the
   card, nothing in the layout measured wrong. grid-auto-columns governs exactly those implicit
   columns, so stating it once here gives every such grid a column that fills the container and
   cannot exceed it. It has no effect on any other kind of element, and no stylesheet in this
   application sets grid-auto-columns or grid-auto-flow:column, so nothing is being overridden. */
* { grid-auto-columns: minmax(0, 1fr); }

/* THE PAGE TITLE STEPS DOWN ON A PHONE (20 September 2026).

   36px is right on a desktop and wrong in a hand. The field day page is the one the crew opens on
   a phone, and at 332px a site address set at 36px took four lines before the page had said
   anything. Every page that had hand-rolled its own title used to shrink it in its own media
   query; the shared header is one component, so the step-down belongs to the token, where all
   sixty-odd pages that adopted the header get it at once. */
@media (max-width: 720px) {
    :root { --archex-text-2xl: 28px; }
}

@media (max-width: 430px) {
    :root { --archex-text-2xl: 25px; }
}

body {
    margin: 0;
    background: var(--archex-canvas);
    color: var(--archex-text);
    font-family: var(--archex-font-ui);
    font-size: var(--archex-text-base);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;

    /* A LONG NAME DOES NOT DRAG THE PAGE SIDEWAYS (20 September 2026).

       The activity feed prints file names like project-1_NOI_Lodgement_Package_v1.zip. An
       underscored name offers no place to break, so a 446px word sat in a 208px column and every
       page in the application could be dragged 210px sideways on a phone. Nothing looked broken:
       no element was mispositioned and the layout measured correct, because it was the text inside
       a correctly sized box that overflowed. break-word only breaks a word that would otherwise
       overflow, so ordinary prose is unaffected. */
    overflow-wrap: break-word;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--archex-font-heading);
    color: var(--archex-text);
    letter-spacing: -0.012em;
    margin: 0;
}

a { color: var(--archex-ochre-strong); }

:focus-visible {
    outline: none;
    box-shadow: var(--archex-focus-ring);
    border-radius: var(--archex-radius-small);
}

/* ---- 3. Application shell ----------------------------------------------- */

.ax-app {
    display: grid;
    grid-template-columns: var(--archex-rail-w) minmax(0, 1fr);
    grid-template-rows: var(--archex-topbar-h) minmax(0, 1fr);
    grid-template-areas:
        "brandbar topbar"
        "rail     workspace";
    min-height: 100vh;
    background: var(--archex-canvas);
}

/* The hamburger swaps the rail between full labels and a 68px icon rail. */
.ax-app[data-rail="collapsed"] { --archex-rail-w: var(--archex-rail-collapsed-w); }

.ax-app-brandbar {
    grid-area: brandbar;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 var(--archex-gap-3);
    background: var(--archex-white);
    overflow: hidden;
}

/* Official asset, used exactly as supplied - never recoloured or redrawn.
   An explicit height is required: an SVG with height:auto inside a flex item
   collapses to zero. */
.ax-app-brandbar img {
    display: block;
    height: 34px;
    width: auto;
    max-width: 100%;
}

.ax-app[data-rail="collapsed"] .ax-app-brandbar img { height: 26px; }

/* ONE UNBROKEN WHITE BAR ACROSS THE TOP (21 September 2026).
   The brand block and the top bar are separate grid areas, and each drew its own 1px border —
   so a vertical rule ran between the logo and the search, boxing the logo into a corner tile.
   The border is gone from both and stated once here, as a soft edge on the pair rather than a
   hard rule: content passing under it reads as depth instead of a seam. */
/* One unbroken white bar across the top. The vertical rule between the brand block and the bar is
   gone; both sit on white and share a single soft edge, so content passes under it as depth rather
   than hitting a seam. */
.ax-app-brandbar,
.ax-app-topbar {
    box-shadow: 0 1px 0 rgba(31, 24, 16, .06), 0 6px 16px -10px rgba(31, 24, 16, .18);
    z-index: 2;
}

/* THE BAR FOLLOWS YOU (23 September 2026). Adam Deane: "When you scroll down the top menu doesnt
   follow you." Search, the job button, the inbox and the clock left the screen the moment anyone
   read past the first fold, and the navigation rail went with them. Both rows are grid items, so
   they stick where they sit: the bar at the top, the rail directly under it, each keeping its own
   scrollbar. Nothing is repositioned or duplicated to achieve it. */
.ax-app-brandbar,
.ax-app-topbar {
    position: sticky;
    top: 0;
}

.ax-app-rail {
    position: sticky;
    top: var(--archex-topbar-h);
    align-self: start;
    height: calc(100vh - var(--archex-topbar-h));
}

.ax-app-topbar {
    grid-area: topbar;
    display: flex;
    align-items: center;
    gap: var(--archex-gap-3);
    padding: 0 var(--archex-gutter) 0 var(--archex-gap-4);
    background: var(--archex-white);
}

.ax-app-rail {
    grid-area: rail;
    display: flex;
    flex-direction: column;
    gap: var(--archex-gap-4);
    padding: var(--archex-gap-4) var(--archex-gap-3) var(--archex-gap-7);
    background: var(--archex-rail-bg);
    color: var(--archex-on-dark);
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: thin;
    scrollbar-color: #3A3D40 transparent;
}

.ax-app-workspace { grid-area: workspace; min-width: 0; background: var(--archex-canvas); }

/* ---- 4. Navigation ------------------------------------------------------ */

.ax-nav-group { display: flex; flex-direction: column; gap: 2px; }

.ax-nav-title {
    font-size: var(--archex-text-xs);
    font-weight: 700;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--archex-on-dark-muted);
    padding: 0 var(--archex-gap-3) var(--archex-gap-2);
    white-space: nowrap;
}

/* THE SELECTED PAGE IS A FILLED PILL, NOT A TINTED STRIP (21 September 2026).
   It was a 17%-opacity wash with a 3px bar down the left edge — the convention of an admin
   console, and at that opacity you had to look for it. A solid pill in the brand orange says
   where you are from the far side of the room, and is what a touch interface does. The 3px
   border is gone rather than made transparent: it was shifting every label 3px and buying
   nothing. */
.ax-nav-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--archex-gap-3);
    padding: 10px var(--archex-gap-3);
    border-radius: var(--archex-radius-small);
    color: var(--archex-on-dark);
    text-decoration: none;
    font-size: var(--archex-text-base);
    white-space: nowrap;
    transition: background 120ms ease, color 120ms ease;
}

.ax-nav-link:hover { background: var(--archex-rail-hover); color: #FFF; }

.ax-nav-link.active {
    background: var(--archex-ochre);
    color: #FFF;
    font-weight: 700;
    box-shadow: 0 6px 16px -6px rgba(242, 108, 33, .7);
}

.ax-nav-link.active:hover { background: var(--archex-ochre-strong); color: #FFF; }

.ax-nav-icon { flex: 0 0 20px; width: 20px; height: 20px; display: block; }
.ax-nav-icon svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.ax-nav-text { overflow: hidden; text-overflow: ellipsis; }

/* Collapsed icon rail: labels hide, icons centre, and the label returns as a
   tooltip so nothing becomes unidentifiable. */
.ax-app[data-rail="collapsed"] .ax-nav-text,
.ax-app[data-rail="collapsed"] .ax-nav-title,
.ax-app[data-rail="collapsed"] .ax-devsection > summary .ax-nav-text { display: none; }

.ax-app[data-rail="collapsed"] .ax-nav-link { justify-content: center; padding-left: 0; padding-right: 0; }

.ax-app[data-rail="collapsed"] .ax-nav-group { padding-top: var(--archex-gap-2); border-top: 1px solid rgba(255, 255, 255, .07); }
.ax-app[data-rail="collapsed"] .ax-nav-group:first-child { border-top: none; padding-top: 0; }

.ax-app[data-rail="collapsed"] .ax-nav-link[data-label]:hover::after,
.ax-app[data-rail="collapsed"] .ax-nav-link[data-label]:focus-visible::after {
    content: attr(data-label);
    position: absolute;
    left: calc(100% + 10px);
    top: 50%;
    transform: translateY(-50%);
    z-index: 80;
    padding: 6px 10px;
    border-radius: var(--archex-radius-small);
    background: var(--archex-charcoal);
    color: #FFF;
    font-size: var(--archex-text-sm);
    font-weight: 600;
    white-space: nowrap;
    box-shadow: var(--archex-shadow-hover);
    pointer-events: none;
}

/* Administrator-only Development section, collapsed by default. */
.ax-devsection { border-top: 1px solid rgba(255, 255, 255, .08); padding-top: var(--archex-gap-3); }

.ax-devsection > summary {
    display: flex;
    align-items: center;
    gap: var(--archex-gap-3);
    padding: 9px var(--archex-gap-3);
    border-radius: var(--archex-radius-small);
    color: var(--archex-on-dark-muted);
    font-size: var(--archex-text-xs);
    font-weight: 700;
    letter-spacing: .11em;
    text-transform: uppercase;
    cursor: pointer;
    list-style: none;
    white-space: nowrap;
}

.ax-devsection > summary::-webkit-details-marker { display: none; }
.ax-devsection > summary:hover { background: var(--archex-rail-hover); color: var(--archex-on-dark); }
.ax-devsection[open] > summary { color: var(--archex-on-dark); }
.ax-devsection .ax-nav-link { font-size: var(--archex-text-sm); color: var(--archex-on-dark-muted); }
.ax-devsection .ax-nav-link:hover, .ax-devsection .ax-nav-link.active { color: #FFF; }

.ax-devnote {
    padding: var(--archex-gap-2) var(--archex-gap-3) var(--archex-gap-3);
    font-size: var(--archex-text-xs);
    line-height: 1.45;
    color: var(--archex-on-dark-muted);
    white-space: normal;
}

.ax-app[data-rail="collapsed"] .ax-devnote { display: none; }

/* ---- 5. Drawer on tablet and phone -------------------------------------- */

.ax-rail-backdrop { display: none; }

@media (max-width: 1180px) {
    .ax-app {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: var(--archex-topbar-h) minmax(0, 1fr);
        grid-template-areas:
            "topbar"
            "workspace";
    }

    .ax-app-brandbar { display: none; }

    .ax-app-rail {
        position: fixed;
        inset: 0 auto 0 0;
        z-index: 90;
        width: min(300px, 84vw);
        padding-top: var(--archex-gap-5);
        transform: translateX(-100%);
        transition: transform 180ms ease;
        box-shadow: none;
    }

    .ax-app[data-drawer="open"] .ax-app-rail { transform: translateX(0); box-shadow: 0 0 40px rgba(0, 0, 0, .4); }

    .ax-app[data-drawer="open"] .ax-rail-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 85;
        background: rgba(20, 20, 20, .45);
        border: none;
    }

    /* On a small screen the rail is always the labelled version. */
    .ax-app[data-rail="collapsed"] .ax-nav-text,
    .ax-app[data-rail="collapsed"] .ax-nav-title { display: initial; }
    .ax-app[data-rail="collapsed"] .ax-nav-link { justify-content: flex-start; padding-left: var(--archex-gap-3); padding-right: var(--archex-gap-3); }
}

@media (prefers-reduced-motion: reduce) {
    .ax-app-rail { transition: none; }
}

/* ---- 6. Top bar controls ------------------------------------------------ */

.ax-hamburger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    flex-shrink: 0;
    border: 1px solid transparent;
    border-radius: var(--archex-radius-small);
    background: transparent;
    color: var(--archex-text);
    cursor: pointer;
}

.ax-hamburger:hover { background: var(--archex-panel); }
.ax-hamburger svg { width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }

.ax-topsearch {
    display: flex;
    align-items: center;
    gap: var(--archex-gap-2);
    flex: 0 1 520px;
    min-width: 200px;
    height: var(--archex-control-h);
    padding: 0 var(--archex-gap-4);
    border: 1px solid var(--archex-border);
    border-radius: var(--archex-radius-pill);
    background: var(--archex-canvas);
    color: var(--archex-faint);
    transition: border-color 120ms ease, background 120ms ease;
}

.ax-topsearch:focus-within { border-color: var(--archex-ochre); background: var(--archex-white); box-shadow: var(--archex-focus-ring); }
.ax-topsearch svg { width: 17px; height: 17px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 2; }

.ax-topsearch-input {
    flex: 1 1 auto;
    min-width: 0;
    border: none;
    background: transparent;
    font: inherit;
    font-size: var(--archex-text-base);
    color: var(--archex-text);
}

.ax-topsearch-input:focus { outline: none; }

.ax-icon-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    flex-shrink: 0;
    border: 1px solid transparent;
    border-radius: var(--archex-radius-small);
    background: transparent;
    color: var(--archex-muted);
    cursor: pointer;
}

.ax-icon-btn:hover { background: var(--archex-panel); color: var(--archex-text); }
.ax-icon-btn svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

.ax-dot { position: absolute; top: 8px; right: 9px; width: 7px; height: 7px; border-radius: 50%; background: var(--archex-ochre); }

/* The mailbox Inbox action. Its original styling lived in NavMenu.razor.css
   behind a .desktop-shell ancestor, so once it moved into this top bar it
   rendered completely unstyled - a solid black rectangle with a filled SVG.
   The shell owns it now. */
.ax-app-topbar > a.toolbar-inbox,
.ax-app-topbar > a.toolbar-inbox:link,
.ax-app-topbar > a.toolbar-inbox:visited {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--archex-gap-2);
    height: var(--archex-control-h);
    min-height: 0;
    padding: 0 var(--archex-gap-4);
    border: 1px solid var(--archex-border);
    border-radius: var(--archex-radius-small);
    background: var(--archex-white);
    color: var(--archex-text);
    font-size: var(--archex-text-base);
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    flex-shrink: 0;
}

.ax-app-topbar > a.toolbar-inbox:hover { background: var(--archex-panel); border-color: var(--archex-ochre); color: var(--archex-ochre-strong); }

.ax-app-topbar > a.toolbar-inbox svg {
    width: 18px;
    height: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.ax-app-topbar > a.toolbar-inbox .toolbar-inbox-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: var(--archex-radius-pill);
    background: var(--archex-ochre);
    color: #FFF;
    font-size: var(--archex-text-xs);
    font-weight: 700;
}

.ax-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--archex-ochre);
    color: #FFF;
    font-size: var(--archex-text-sm);
    font-weight: 700;
}

.ax-usermenu { position: relative; flex-shrink: 0; }

.ax-usermenu > summary {
    display: flex;
    align-items: center;
    gap: var(--archex-gap-2);
    padding: 3px 8px 3px 3px;
    border-radius: var(--archex-radius-pill);
    cursor: pointer;
    list-style: none;
}

.ax-usermenu > summary::-webkit-details-marker { display: none; }
.ax-usermenu > summary:hover { background: var(--archex-panel); }
.ax-usermenu-copy { display: flex; flex-direction: column; line-height: 1.2; }
.ax-usermenu-copy strong { font-size: var(--archex-text-sm); }
.ax-usermenu-copy small { font-size: var(--archex-text-xs); color: var(--archex-faint); }
.ax-chev { width: 15px; height: 15px; color: var(--archex-faint); fill: none; stroke: currentColor; stroke-width: 2; }

.ax-usermenu-panel {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 95;
    min-width: 236px;
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding: 7px;
    background: var(--archex-white);
    border: 1px solid var(--archex-border-soft);
    border-radius: var(--archex-radius-medium);
    box-shadow: var(--archex-shadow-hover);
}

.ax-usermenu-panel a,
.ax-usermenu-panel button {
    appearance: none;
    display: flex;
    align-items: center;
    gap: var(--archex-gap-3);
    text-align: left;
    padding: 9px var(--archex-gap-3);
    border: none;
    border-radius: var(--archex-radius-small);
    background: transparent;
    color: var(--archex-text);
    font: inherit;
    font-size: var(--archex-text-base);
    text-decoration: none;
    cursor: pointer;
}

.ax-usermenu-panel a:hover, .ax-usermenu-panel button:hover { background: var(--archex-panel); }
.ax-usermenu-panel hr { margin: 5px 2px; border: none; border-top: 1px solid var(--archex-border-soft); }
.ax-usermenu-panel form { display: flex; }
.ax-usermenu-panel form button { width: 100%; color: var(--archex-danger); font-weight: 600; }

@media (max-width: 860px) {
    .ax-usermenu-copy { display: none; }
    .ax-app-topbar > a.toolbar-inbox span:not(.toolbar-inbox-badge) { display: none; }
    .ax-app-topbar > a.toolbar-inbox { padding: 0 var(--archex-gap-3); }
}

/* ---- 7. Page shell ------------------------------------------------------ */

.ax-workspace {
    width: 100%;
    max-width: var(--archex-workspace-max);
    margin: 0 auto;
    padding: var(--archex-gap-5) var(--archex-gutter) var(--archex-gap-7);
    display: flex;
    flex-direction: column;
    gap: var(--archex-gap-5);
}

.ax-pagehead {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--archex-gap-5);
    flex-wrap: wrap;
}

.ax-pagehead-text { min-width: 0; display: flex; flex-direction: column; gap: 3px; }

.ax-eyebrow {
    font-size: var(--archex-text-xs);
    font-weight: 700;
    letter-spacing: .15em;
    text-transform: uppercase;
    color: var(--archex-ochre-strong);
    margin: 0;
}

.ax-h1 { font-size: var(--archex-text-2xl); font-weight: 700; line-height: 1.12; }
.ax-h2 { font-size: var(--archex-text-lg); font-weight: 700; line-height: 1.25; }
.ax-h3 { font-size: var(--archex-text-md); font-weight: 700; line-height: 1.3; }

.ax-sub { color: var(--archex-muted); font-size: var(--archex-text-base); margin: 0; max-width: 84ch; }

.ax-pagehead-actions { display: flex; align-items: center; gap: var(--archex-gap-3); flex-shrink: 0; }

/* ---- 8. Tabs ------------------------------------------------------------ */

.ax-tabs {
    display: flex;
    align-items: stretch;
    gap: 2px;
    border-bottom: 1px solid var(--archex-border);
    overflow-x: auto;
    scrollbar-width: thin;
    /* A flex or grid item is, by default, never smaller than its content, so a tab strip that
       already knew how to scroll still pushed New project and New opportunity 37px sideways on a
       phone. overflow-x on its own is not enough; the item has to be allowed to be narrow. */
    min-width: 0;
}

.ax-tab {
    appearance: none;
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    padding: 11px var(--archex-gap-4);
    font: inherit;
    font-size: var(--archex-text-base);
    font-weight: 600;
    color: var(--archex-muted);
    white-space: nowrap;
    cursor: pointer;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: var(--archex-gap-2);
    transition: color 120ms ease, border-color 120ms ease;
}

.ax-tab:hover { color: var(--archex-text); }
.ax-tab.active, .ax-tab[aria-selected="true"] { color: var(--archex-text); border-bottom-color: var(--archex-ochre); }

.ax-tab-count {
    font-size: var(--archex-text-xs);
    font-weight: 700;
    background: var(--archex-panel);
    color: var(--archex-muted);
    border-radius: var(--archex-radius-pill);
    padding: 2px 8px;
}

/* ---- 9. Buttons --------------------------------------------------------- */

.ax-btn {
    appearance: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--archex-gap-2);
    height: var(--archex-control-h);
    padding: 0 var(--archex-gap-4);
    border-radius: var(--archex-radius-small);
    border: 1px solid var(--archex-border);
    background: var(--archex-white);
    color: var(--archex-text);
    font: inherit;
    font-size: var(--archex-text-base);
    font-weight: 600;
    line-height: 1;
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;
    transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}

.ax-btn:hover { background: var(--archex-panel); border-color: var(--archex-border); }
.ax-btn svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

.ax-btn-primary { background: var(--archex-ochre); border-color: var(--archex-ochre); color: #FFF; }
.ax-btn-primary:hover { background: var(--archex-ochre-strong); border-color: var(--archex-ochre-strong); }

.ax-btn-quiet { background: transparent; border-color: transparent; color: var(--archex-muted); }
.ax-btn-quiet:hover { background: var(--archex-panel); color: var(--archex-text); }

.ax-btn-sm { height: 32px; padding: 0 var(--archex-gap-3); font-size: var(--archex-text-sm); }
.ax-btn:disabled, .ax-btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

/* ---- 10. Inputs --------------------------------------------------------- */

.ax-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }

.ax-label {
    font-size: var(--archex-text-xs);
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--archex-muted);
}

.ax-input, .ax-select, .ax-textarea {
    width: 100%;
    height: var(--archex-control-h);
    padding: 0 var(--archex-gap-4);
    border: 1px solid var(--archex-border);
    border-radius: var(--archex-radius-small);
    background: var(--archex-white);
    color: var(--archex-text);
    font: inherit;
    font-size: var(--archex-text-base);
    transition: border-color 120ms ease, box-shadow 120ms ease;
}

.ax-textarea { height: auto; min-height: 96px; padding: var(--archex-gap-3) var(--archex-gap-4); resize: vertical; }

.ax-input:focus, .ax-select:focus, .ax-textarea:focus {
    outline: none;
    border-color: var(--archex-ochre);
    box-shadow: var(--archex-focus-ring);
}

.ax-input::placeholder { color: var(--archex-faint); }

/* Not a default browser dropdown. */
.ax-select {
    appearance: none;
    padding-right: 40px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%233B3B3B' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='m8 10 4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 17px;
    cursor: pointer;
}

/* Search input with a leading glyph, used in page toolbars. */
.ax-search {
    display: flex;
    align-items: center;
    gap: var(--archex-gap-2);
    height: var(--archex-control-h);
    padding: 0 var(--archex-gap-4);
    border: 1px solid var(--archex-border);
    border-radius: var(--archex-radius-small);
    background: var(--archex-white);
    color: var(--archex-faint);
    min-width: 0;
}

.ax-search:focus-within { border-color: var(--archex-ochre); box-shadow: var(--archex-focus-ring); }
.ax-search svg { width: 17px; height: 17px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 2; }
.ax-search input { flex: 1 1 auto; min-width: 0; border: none; background: transparent; font: inherit; font-size: var(--archex-text-base); color: var(--archex-text); }
.ax-search input:focus { outline: none; }

/* ---- 11. Toolbars ------------------------------------------------------- */
/* One compact horizontal strip. Replaces floating filter cards. */

.ax-toolbar {
    display: flex;
    align-items: center;
    gap: var(--archex-gap-3);
    flex-wrap: wrap;
    padding: var(--archex-gap-3) var(--archex-gap-4);
    background: var(--archex-white);
    border: 1px solid var(--archex-border-soft);
    border-radius: var(--archex-radius-medium);
}

.ax-toolbar .ax-search { flex: 1 1 360px; }
.ax-toolbar .ax-select { width: auto; min-width: 190px; flex: 0 0 auto; }

.ax-toolbar-count {
    display: inline-flex;
    align-items: baseline;
    gap: 5px;
    font-size: var(--archex-text-sm);
    color: var(--archex-muted);
    white-space: nowrap;
}

.ax-toolbar-count strong { font-size: var(--archex-text-base); color: var(--archex-text); }

.ax-toolbar-divider { width: 1px; height: 26px; background: var(--archex-border-soft); flex-shrink: 0; }

/* ---- 12. Cards and grids ------------------------------------------------ */

.ax-card {
    background: var(--archex-white);
    border: 1px solid var(--archex-border-soft);
    border-radius: var(--archex-radius-medium);
    box-shadow: var(--archex-shadow);
    padding: var(--archex-gap-5);
    min-width: 0;
}

.ax-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--archex-gap-4);
    margin-bottom: var(--archex-gap-4);
    /* A card heading and the control beside it do not both fit across a 206px card on a phone,
       and without this they simply hang off the side of it. */
    flex-wrap: wrap;
}

.ax-card-tight { padding: var(--archex-gap-4); }

.ax-grid { display: grid; gap: var(--archex-gap-4); }
/* min(track, 100%): auto-fit keeps the stated minimum even when the container is narrower than it,
   so a 340px column inside a 246px card pushed New project 37px sideways on a phone. Wrapping the
   minimum in min() lets the track fall back to the container width and changes nothing on a
   desktop, where the container is always the wider of the two. */
.ax-grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr)); }
.ax-grid-3 { grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); }
.ax-grid-4 { grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); }

.ax-metric {
    display: flex;
    flex-direction: column;
    gap: 3px;
    background: var(--archex-white);
    border: 1px solid var(--archex-border-soft);
    border-radius: var(--archex-radius-medium);
    padding: var(--archex-gap-4);
}

.ax-metric-label {
    font-size: var(--archex-text-xs);
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--archex-muted);
}

.ax-metric-value { font-family: var(--archex-font-heading); font-size: var(--archex-text-xl); font-weight: 700; line-height: 1.1; }
.ax-metric-note { font-size: var(--archex-text-sm); color: var(--archex-faint); }

/* ---- 13. Tables --------------------------------------------------------- */

.ax-tablewrap {
    background: var(--archex-white);
    border: 1px solid var(--archex-border-soft);
    border-radius: var(--archex-radius-medium);
    overflow: hidden;
}

.ax-table { width: 100%; border-collapse: collapse; font-size: var(--archex-text-base); }

/* A WIDE TABLE SCROLLS INSIDE ITSELF ON A PHONE (20 September 2026).

   The determination and fact-set review pages carry a two-column comparison that needs about
   1,015px. On a 332px phone that made the whole page slide sideways, so the heading, the decision
   and every other section moved together whenever the reader dragged the table. Below the tablet
   breakpoint the table becomes its own scrolling box: the reader drags the comparison and nothing
   else moves. display:block is what gives a table an overflow box of its own. */
@media (max-width: 720px) {
    .ax-table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
    .ax-table thead, .ax-table tbody, .ax-table tfoot { width: max-content; min-width: 100%; }
}

.ax-table thead th {
    text-align: left;
    font-size: var(--archex-text-xs);
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--archex-muted);
    background: var(--archex-panel);
    padding: 11px var(--archex-gap-4);
    border-bottom: 1px solid var(--archex-border-soft);
    white-space: nowrap;
}

.ax-table tbody td { padding: 14px var(--archex-gap-4); border-bottom: 1px solid var(--archex-border-soft); vertical-align: middle; }
.ax-table tbody tr:last-child td { border-bottom: none; }

/* A cell breaks its content rather than widening the table. An auto-layout table is never narrower
   than the sum of its cells min-content widths, so one long email address in a six-column table
   took the governance table 42px past the panel it sits in at desktop width. break-word is not
   enough here: only `anywhere` reduces the min-content width that the table is measured from. */
.ax-table th, .ax-table td { overflow-wrap: anywhere; }
.ax-table tbody tr:hover { background: var(--archex-canvas); }
.ax-table a { color: inherit; text-decoration: none; font-weight: 600; }
.ax-table a:hover { color: var(--archex-ochre-strong); }

.ax-cell-strong { font-weight: 700; }
.ax-cell-quiet { color: var(--archex-faint); font-size: var(--archex-text-sm); }
.ax-cell-mono { font-family: var(--archex-font-mono); font-size: var(--archex-text-sm); }

/* ---- 14. Badges --------------------------------------------------------- */

.ax-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 11px;
    border-radius: var(--archex-radius-pill);
    font-size: var(--archex-text-xs);
    font-weight: 700;
    letter-spacing: .03em;
    background: var(--archex-panel);
    color: var(--archex-muted);
    white-space: nowrap;
}

.ax-badge-active   { background: rgba(46, 125, 50, .13);  color: #24631F; }
.ax-badge-progress { background: rgba(242, 108, 33, .15); color: var(--color-primary-dark); }
.ax-badge-hold     { background: rgba(198, 40, 40, .13);  color: #96201F; }
.ax-badge-muted    { background: var(--archex-panel);     color: var(--archex-faint); }

.ax-priority-high   { background: rgba(198, 40, 40, .13);  color: #96201F; }
.ax-priority-medium { background: rgba(249, 168, 37, .20); color: #8A5A00; }
.ax-priority-low    { background: var(--archex-panel);     color: var(--archex-muted); }

/* ---- 15. Empty, loading and error states -------------------------------- */

.ax-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--archex-gap-2);
    text-align: center;
    padding: var(--archex-gap-7) var(--archex-gap-5);
    background: var(--archex-white);
    border: 1px dashed var(--archex-border);
    border-radius: var(--archex-radius-medium);
    color: var(--archex-muted);
}

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

.ax-loading { display: flex; align-items: center; gap: var(--archex-gap-3); padding: var(--archex-gap-5); color: var(--archex-muted); }

.ax-skeleton {
    background: linear-gradient(90deg, var(--archex-panel) 25%, #EDE8E1 37%, var(--archex-panel) 63%);
    background-size: 400% 100%;
    animation: ax-shimmer 1.3s ease infinite;
    border-radius: var(--archex-radius-small);
    height: 15px;
}

@keyframes ax-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) { .ax-skeleton { animation: none; } }

/* Structured failure: a plain summary, with the diagnostics folded away. */
.ax-error {
    display: flex;
    flex-direction: column;
    gap: var(--archex-gap-3);
    padding: var(--archex-gap-4) var(--archex-gap-5);
    background: rgba(198, 40, 40, .05);
    border: 1px solid rgba(198, 40, 40, .26);
    border-left-width: 3px;
    border-radius: var(--archex-radius-small);
    color: #7F1D1D;
}

.ax-error-title { display: flex; align-items: center; gap: var(--archex-gap-2); font-family: var(--archex-font-heading); font-size: var(--archex-text-md); font-weight: 700; }
.ax-error-body { margin: 0; color: #7F1D1D; font-size: var(--archex-text-base); }
.ax-error-actions { display: flex; gap: var(--archex-gap-3); flex-wrap: wrap; }

.ax-details { border-top: 1px solid rgba(198, 40, 40, .2); padding-top: var(--archex-gap-3); }

.ax-details > summary {
    cursor: pointer;
    font-size: var(--archex-text-sm);
    font-weight: 700;
    color: #7F1D1D;
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.ax-details > summary::-webkit-details-marker { display: none; }
.ax-details > summary::before { content: "▸"; font-size: 11px; }
.ax-details[open] > summary::before { content: "▾"; }

.ax-details pre {
    margin: var(--archex-gap-3) 0 0;
    padding: var(--archex-gap-3);
    background: var(--archex-white);
    border: 1px solid var(--archex-border-soft);
    border-radius: var(--archex-radius-small);
    font-family: var(--archex-font-mono);
    font-size: var(--archex-text-sm);
    color: var(--archex-text);
    overflow-x: auto;
    white-space: pre-wrap;
    word-break: break-word;
}

.ax-notice {
    display: flex;
    align-items: center;
    gap: var(--archex-gap-3);
    padding: var(--archex-gap-3) var(--archex-gap-4);
    background: rgba(242, 108, 33, .07);
    border: 1px solid rgba(242, 108, 33, .24);
    border-left-width: 3px;
    border-radius: var(--archex-radius-small);
}

/* ---- 16. Dashboard command centre --------------------------------------- */
/* A deliberate grid, not floating cards. */

.ax-dash {
    display: grid;
    grid-template-columns: minmax(0, 2.05fr) minmax(0, 1fr);
    gap: var(--archex-gap-4);
    align-items: start;
}

.ax-dash-main, .ax-dash-side { display: flex; flex-direction: column; gap: var(--archex-gap-4); min-width: 0; }

@media (max-width: 1320px) {
    .ax-dash { grid-template-columns: minmax(0, 1fr); }
}

/* Grouped operational issue: one row per KIND of problem, not per project. */
.ax-issue {
    display: flex;
    align-items: center;
    gap: var(--archex-gap-4);
    padding: var(--archex-gap-3) var(--archex-gap-4);
    border: 1px solid var(--archex-border-soft);
    border-radius: var(--archex-radius-small);
    background: var(--archex-white);
    color: inherit;
    text-decoration: none;
    transition: border-color 120ms ease, background 120ms ease;
}

.ax-issue:hover { border-color: var(--archex-ochre); background: var(--archex-canvas); }
.ax-issue-count { font-family: var(--archex-font-heading); font-size: var(--archex-text-lg); font-weight: 700; min-width: 34px; }
.ax-issue-copy { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.ax-issue-copy strong { font-size: var(--archex-text-base); }
.ax-issue-copy small { font-size: var(--archex-text-sm); color: var(--archex-faint); }
.ax-issue-go { color: var(--archex-faint); flex-shrink: 0; }

/* Recent job card */
.ax-recentjob {
    display: flex;
    flex-direction: column;
    gap: var(--archex-gap-2);
    align-items: flex-start;
    text-decoration: none;
    color: inherit;
    transition: border-color 120ms ease, box-shadow 120ms ease;
}

.ax-recentjob:hover { border-color: var(--archex-ochre); box-shadow: var(--archex-shadow-hover); }
.ax-recentjob-top { display: flex; align-items: center; justify-content: space-between; gap: var(--archex-gap-2); width: 100%; }
.ax-recentjob-meta { display: flex; flex-direction: column; gap: 2px; width: 100%; font-size: var(--archex-text-sm); color: var(--archex-muted); }
.ax-recentjob-meta span { display: flex; gap: 6px; }
.ax-recentjob-meta b { color: var(--archex-faint); font-weight: 600; flex: 0 0 62px; }
.ax-recentjob-next { width: 100%; margin-top: 2px; padding-top: var(--archex-gap-2); border-top: 1px solid var(--archex-border-soft); font-size: var(--archex-text-sm); color: var(--archex-ochre-strong); font-weight: 600; }

/* ---- 17. Project shell -------------------------------------------------- */
/* One header, one tab bar, one content region - shared by every project page. */

.ax-projecthead { display: flex; flex-direction: column; gap: var(--archex-gap-4); }
.ax-projecthead-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--archex-gap-5); flex-wrap: wrap; }
.ax-projecthead-id { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.ax-projecthead-title { display: flex; align-items: center; gap: var(--archex-gap-3); flex-wrap: wrap; }

.ax-projectfacts { display: flex; flex-wrap: wrap; gap: var(--archex-gap-5); margin: 0; }
.ax-projectfacts div { display: flex; flex-direction: column; gap: 2px; }
.ax-projectfacts dt { font-size: var(--archex-text-xs); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--archex-muted); }
.ax-projectfacts dd { margin: 0; font-size: var(--archex-text-base); font-weight: 600; }

/* The folded Client and Site address, for pages that set ProjectShell's CompactFacts. A summary
   that reads as a fact label rather than as a button, because that is what is behind it. */
.ax-projectfacts-more > details > summary { cursor: pointer; font-size: var(--archex-text-xs); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--archex-muted); }
.ax-projectfacts-more > details[open] > summary { margin-bottom: 4px; }
.ax-projectfacts-more span { display: block; font-size: var(--archex-text-sm); max-width: 62ch; }
.ax-projectfacts-more strong { color: var(--archex-muted); font-weight: 700; margin-right: 6px; }

/* ---- 18. Spatial workspace ---------------------------------------------- */
/* The map is the working surface, so it gets the room. */

.ax-maplayout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 330px;
    gap: var(--archex-gap-4);
    align-items: stretch;
    min-height: min(74vh, 820px);
}

.ax-maplayout > .ax-mapsurface { min-height: min(74vh, 820px); border-radius: var(--archex-radius-medium); overflow: hidden; border: 1px solid var(--archex-border-soft); position: relative; background: var(--archex-panel); }
.ax-mapaside { display: flex; flex-direction: column; gap: var(--archex-gap-3); min-width: 0; overflow-y: auto; max-height: min(74vh, 820px); }

@media (max-width: 1180px) {
    .ax-maplayout { grid-template-columns: minmax(0, 1fr); min-height: 0; }
    .ax-mapaside { max-height: none; }
    .ax-maplayout > .ax-mapsurface { min-height: 460px; }
}

/* ---- WHAT A MAP FEATURE SAYS WHEN YOU TAP IT ------------------------------------------------
   THESE LIVE HERE, GLOBALLY, AND MUST NOT BE MOVED INTO A PAGE'S SCOPED SHEET. The popup's
   contents are written by archex-spatial-map.js with innerHTML, so those elements never carry the
   b-<hash> attribute the Blazor build adds to markup - and a scoped rule is rewritten to require
   exactly that attribute. A scoped ".map-popup-heading" therefore matches nothing, silently, and
   looks perfectly correct in the stylesheet while having no effect on the page. */

.map-popup-heading {
    display: block;
    font-size: .92rem;
    line-height: 1.25;
    margin-bottom: 6px;
    color: var(--archex-ink, #1d2b26);
}

.map-popup-fields { display: grid; gap: 2px; margin: 0; }

.map-popup-field {
    display: grid;
    grid-template-columns: minmax(70px, auto) minmax(0, 1fr);
    gap: 10px;
    align-items: baseline;
    padding: 2px 0;
}

    .map-popup-field + .map-popup-field { border-top: 1px solid var(--archex-border-soft); }

    .map-popup-field dt {
        margin: 0;
        font-size: .68rem;
        letter-spacing: .04em;
        text-transform: uppercase;
        color: var(--archex-muted, #5d6b66);
        white-space: nowrap;
    }

    .map-popup-field dd {
        margin: 0;
        font-size: .8rem;
        /* A survey easting is long and a collector is an email address: both must wrap rather
           than stretch the popup off the edge of a phone. */
        overflow-wrap: anywhere;
    }

.map-popup-empty { font-size: .8rem; color: var(--archex-muted, #5d6b66); }

/* The photograph itself, inside the popup. Capped so a portrait shot cannot grow the popup taller
   than the map it is sitting on, and so a phone still sees the pin it tapped. */
.map-popup-photo {
    display: block;
    margin: -4px -4px 8px;
    border-radius: var(--archex-radius-small);
    overflow: hidden;
    line-height: 0;
    background: var(--archex-panel, #f4f1ea);
}

    .map-popup-photo img {
        display: block;
        width: 100%;
        max-width: 280px;
        max-height: 220px;
        object-fit: cover;
    }

/* A thousand pins is a lot of popup; keep it to a sensible width on a phone. */
.map-popup { max-width: min(300px, 82vw); }

/* Says only what is actually missing. The alert it sits beside keeps its meaning that way. */
.map-basemap-note {
    position: absolute;
    inset: auto 12px 12px 12px;
    padding: 8px 12px;
    border-radius: var(--archex-radius-small);
    background: var(--archex-panel, #f4f1ea);
    border: 1px solid var(--archex-border-soft);
    color: var(--archex-muted, #5d6b66);
    font-size: .78rem;
}

.ax-panel {
    background: var(--archex-white);
    border: 1px solid var(--archex-border-soft);
    border-radius: var(--archex-radius-medium);
    overflow: hidden;
}

.ax-panel > summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--archex-gap-3);
    padding: var(--archex-gap-3) var(--archex-gap-4);
    cursor: pointer;
    list-style: none;
    font-family: var(--archex-font-heading);
    font-size: var(--archex-text-base);
    font-weight: 700;
}

.ax-panel > summary::-webkit-details-marker { display: none; }
.ax-panel > summary:hover { background: var(--archex-canvas); }
.ax-panel > summary::after { content: "▾"; color: var(--archex-faint); font-size: 12px; }
.ax-panel:not([open]) > summary::after { content: "▸"; }
.ax-panel-body { padding: 0 var(--archex-gap-4) var(--archex-gap-4); }

/* ---- 19. Helpers -------------------------------------------------------- */

.ax-row { display: flex; align-items: center; gap: var(--archex-gap-3); flex-wrap: wrap; }
.ax-row-tight { display: flex; align-items: center; gap: var(--archex-gap-2); }
.ax-spacer { flex: 1 1 auto; }
.ax-stack { display: flex; flex-direction: column; gap: var(--archex-gap-4); }
.ax-stack-tight { display: flex; flex-direction: column; gap: var(--archex-gap-2); }
.ax-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; max-width: 100%; }
.ax-muted { color: var(--archex-muted); }
.ax-faint { color: var(--archex-faint); }
.ax-small { font-size: var(--archex-text-sm); }
.ax-visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ---- 20. Clock and docked feedback -------------------------------------- */

.ax-clock { display: flex; flex-direction: column; line-height: 1.2; text-align: right; flex-shrink: 0; }
.ax-clock-date { font-size: var(--archex-text-xs); color: var(--archex-faint); }
.ax-clock-time { font-size: var(--archex-text-sm); font-weight: 700; }

@media (max-width: 1100px) { .ax-clock { display: none; } }

/* Feedback was a fixed orange pill floating over every page. It now lives in
   the profile menu. Its own scoped rule is .feedback-fab[b-...] (0,2,0), so the
   element selector here lifts specificity to 0,2,1 and wins on merit rather
   than with an override keyword. The widget's dialog is position:fixed and so
   still escapes this panel correctly. */
.ax-usermenu-panel > button.feedback-fab {
    position: static;
    display: flex;
    align-items: center;
    gap: var(--archex-gap-3);
    width: 100%;
    height: auto;
    inset: auto;
    padding: 9px var(--archex-gap-3);
    border: none;
    border-radius: var(--archex-radius-small);
    background: transparent;
    color: var(--archex-text);
    font: inherit;
    font-size: var(--archex-text-base);
    font-weight: 400;
    box-shadow: none;
    z-index: auto;
}

.ax-usermenu-panel > button.feedback-fab:hover { background: var(--archex-panel); color: var(--archex-text); }
.ax-usermenu-panel > button.feedback-fab > span:first-child { font-size: 17px; color: var(--archex-ochre); }
.ax-usermenu-panel > button.feedback-fab .feedback-fab-label { display: inline; }

/* ---- 21. Project register ----------------------------------------------- */
/* The register is the page's working surface, so it fills the workspace. Its
   own .ax-jobs grid is unchanged; this only frames it consistently and lifts
   the row rhythm to the iteration-two scale. */

.ax-workspace .ax-jobs {
    background: var(--archex-white);
    border: 1px solid var(--archex-border-soft);
    border-radius: var(--archex-radius-medium);
    overflow: hidden;
    width: 100%;
}

.ax-workspace .ax-jobs-head {
    font-size: var(--archex-text-xs);
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--archex-muted);
    background: var(--archex-panel);
    border-bottom: 1px solid var(--archex-border-soft);
}

.ax-workspace .ax-jobs-row { font-size: var(--archex-text-base); border-bottom: 1px solid var(--archex-border-soft); }
.ax-workspace .ax-jobs-row:last-child { border-bottom: none; }
.ax-workspace .ax-jobs-row:hover { background: var(--archex-canvas); }
.ax-workspace .ax-jobs-ref { font-family: var(--archex-font-mono); font-size: var(--archex-text-sm); color: var(--archex-muted); }
.ax-workspace .ax-jobs-name b { font-size: var(--archex-text-base); font-weight: 700; }
.ax-workspace .ax-jobs-cell { font-size: var(--archex-text-sm); color: var(--archex-muted); }

/* ---- 22. Recent jobs grid ----------------------------------------------- */
/* Four across on a desktop, because the requirement is four visible jobs.
   auto-fit with a 240px floor wrapped to three at 1010px. */

.ax-grid-jobs { grid-template-columns: repeat(2, minmax(0, 1fr)); }

@media (min-width: 1500px) {
    .ax-grid-jobs { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

@media (min-width: 1100px) and (max-width: 1499px) {
    .ax-grid-jobs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 620px) {
    .ax-grid-jobs { grid-template-columns: minmax(0, 1fr); }
}

/* ---- 23. New job ---------------------------------------------------------- */
/* Shared form furniture. These live here, not on the page, because the design
   baseline says the foundation owns every shared .ax- component. */

.ax-newjob {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 380px;
    gap: var(--archex-gap-4);
    align-items: start;
}

.ax-newjob-side { position: sticky; top: calc(var(--archex-topbar-h) + var(--archex-gap-4)); min-width: 0; }

@media (max-width: 1180px) {
    .ax-newjob { grid-template-columns: minmax(0, 1fr); }
    .ax-newjob-side { position: static; }
}

.ax-req {
    margin-left: 6px;
    font-size: var(--archex-text-xs);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: none;
    color: var(--archex-ochre-strong);
}

.ax-hint { display: block; margin-top: 5px; font-size: var(--archex-text-sm); color: var(--archex-faint); }
.ax-centre { text-align: center; }
.ax-mt { margin-top: var(--archex-gap-4); }
.ax-full { width: 100%; }

/* A nested block that appears when "add new" is chosen. */
.ax-subform {
    margin-top: var(--archex-gap-3);
    padding: var(--archex-gap-4);
    background: var(--archex-canvas);
    border: 1px solid var(--archex-border-soft);
    border-left: 3px solid var(--archex-ochre);
    border-radius: var(--archex-radius-small);
    display: flex;
    flex-direction: column;
    gap: var(--archex-gap-3);
}

.ax-problem-list { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 4px; }
.ax-problem-list li { font-size: var(--archex-text-base); }

.ax-summary { display: flex; flex-direction: column; gap: var(--archex-gap-3); margin: 0 0 var(--archex-gap-5); }
.ax-summary div { display: flex; flex-direction: column; gap: 2px; }
.ax-summary dt { font-size: var(--archex-text-xs); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--archex-muted); }
.ax-summary dd { margin: 0; font-size: var(--archex-text-base); font-weight: 600; overflow-wrap: anywhere; }

/* ---- 24. Opportunity: contacts, property search and the map -------------- */
/* WR-60 slice 1. Shared components, so the quote-request form and the intake
   screens reuse exactly these rather than growing their own. */

.ax-stack { display: flex; flex-direction: column; gap: var(--archex-gap-4); min-width: 0; }
.ax-grow { flex: 1 1 auto; min-width: 0; }

/* A row of controls that sit on one line and wrap together on a phone. */
.ax-searchrow { display: flex; gap: var(--archex-gap-3); align-items: flex-end; flex-wrap: wrap; }
.ax-searchrow .ax-btn { flex: 0 0 auto; }

.ax-check { display: inline-flex; align-items: center; gap: 8px; font-size: var(--archex-text-base); cursor: pointer; }
.ax-check input { width: 16px; height: 16px; accent-color: var(--archex-ochre); cursor: pointer; }

/* Contacts: one block per person, because a person is not a table row - they
   carry six fields and a role, and squeezing that into columns made the whole
   thing unreadable below 1400px. */
.ax-contacts { display: flex; flex-direction: column; gap: var(--archex-gap-3); margin: var(--archex-gap-3) 0; }

.ax-contact-row {
    display: flex;
    gap: var(--archex-gap-3);
    align-items: flex-start;
    padding: var(--archex-gap-3);
    background: var(--archex-canvas);
    border: 1px solid var(--archex-border-soft);
    border-radius: var(--archex-radius-small);
}

.ax-contact-grid {
    flex: 1 1 auto;
    min-width: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--archex-gap-3);
}

.ax-contact-actions {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: flex-start;
    padding-top: 22px;
}

@media (max-width: 720px) {
    .ax-contact-row { flex-direction: column; }
    .ax-contact-actions { flex-direction: row; padding-top: 0; }
}

/* Address candidates. A list of things to pick, not a dropdown: the operator
   has to be able to read the whole matched address before choosing one. */
.ax-pickerlist { list-style: none; margin: var(--archex-gap-3) 0 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }

.ax-pickeritem {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--archex-gap-3);
    padding: 10px var(--archex-gap-3);
    background: var(--archex-white);
    border: 1px solid var(--archex-border-soft);
    border-radius: var(--archex-radius-small);
    font-family: inherit;
    font-size: var(--archex-text-base);
    text-align: left;
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease;
}

.ax-pickeritem:hover { background: var(--archex-panel); border-color: var(--archex-ochre); }
.ax-pickeritem:focus-visible { outline: 3px solid rgba(242, 108, 33, .3); outline-offset: 1px; }
.ax-pickeritem-main { font-weight: 600; }
.ax-pickeritem-note { font-size: var(--archex-text-xs); color: var(--archex-faint); white-space: nowrap; }

/* The map itself. */
.ax-maphead {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--archex-gap-3);
    flex-wrap: wrap;
    margin-top: var(--archex-gap-4);
    margin-bottom: 6px;
}

.ax-map {
    width: 100%;
    height: 460px;
    border: 1px solid var(--archex-border);
    border-radius: var(--archex-radius-small);
    background: var(--archex-panel);
    overflow: hidden;
}

@media (max-width: 720px) { .ax-map { height: 340px; } }

.ax-maplegend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--archex-gap-3);
    margin-top: 8px;
    font-size: var(--archex-text-sm);
    color: var(--archex-muted);
}

.ax-maplegend span { display: inline-flex; align-items: center; gap: 6px; }

.ax-swatch { width: 14px; height: 12px; border-radius: 2px; display: inline-block; }
.ax-swatch-candidate { border: 1px solid #6B6B6B; background: rgba(120, 120, 120, .1); }
.ax-swatch-selected { border: 2px solid var(--archex-ochre-strong); background: rgba(242, 108, 33, .22); }
.ax-swatch-activity { border: 2px dashed var(--archex-charcoal); background: rgba(31, 31, 31, .14); }
.ax-swatch-sensitivity { border: 1px solid #7A5CA8; background: rgba(122, 92, 168, .45); }

.ax-table tr.is-selected { background: rgba(242, 108, 33, .08); }

/* ---- 25. Property identification ---------------------------------------- */
/* WR-60 slice 1 correction. A property is a candidate to be checked and accepted,
   so it gets a card with room for the identifiers a person actually compares. */

.ax-mb { margin-bottom: var(--archex-gap-3); }

.ax-tabs-sm .ax-tab { padding: 7px 12px; font-size: var(--archex-text-sm); }

.ax-searchpanel {
    padding: var(--archex-gap-3);
    background: var(--archex-canvas);
    border: 1px solid var(--archex-border-soft);
    border-top: none;
    border-radius: 0 0 var(--archex-radius-small) var(--archex-radius-small);
    margin-bottom: var(--archex-gap-3);
}

.ax-propertycard {
    margin-top: var(--archex-gap-3);
    padding: var(--archex-gap-4);
    background: var(--archex-white);
    border: 1px solid var(--archex-border);
    border-left: 4px solid var(--archex-border);
    border-radius: var(--archex-radius-small);
}

.ax-propertycard.is-confirmed { border-left-color: var(--archex-ochre); background: var(--archex-panel); }

.ax-propertycard-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--archex-gap-3);
    margin-bottom: var(--archex-gap-3);
    flex-wrap: wrap;
}

/* Identifier grid. Fixed columns so PFI and council number line up between the
   candidate and the report, which is how a person spots a mismatch. */
.ax-facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: var(--archex-gap-3);
    margin: 0 0 var(--archex-gap-3);
}

.ax-facts div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ax-facts dt { font-size: var(--archex-text-xs); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--archex-muted); }
.ax-facts dd { margin: 0; font-size: var(--archex-text-base); font-weight: 600; overflow-wrap: anywhere; }

.ax-spilist {
    list-style: none;
    margin: var(--archex-gap-3) 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 6px;
}

.ax-spilist li {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    padding: 6px 10px;
    background: var(--archex-canvas);
    border: 1px solid var(--archex-border-soft);
    border-radius: var(--archex-radius-small);
}

.ax-spilist code { font-size: var(--archex-text-sm); font-weight: 700; }

.ax-reconcile {
    margin-top: var(--archex-gap-3);
    padding: var(--archex-gap-4);
    background: var(--archex-white);
    border: 1px solid var(--archex-border);
    border-radius: var(--archex-radius-small);
}

/* HAVE WE BEEN HERE BEFORE (23 September 2026). Sits with the confirmed property and answers
   without being asked. Quiet when the answer is "nothing"; marked in ochre when it is not, because
   an earlier job 400 m away changes how the next one is quoted. */
.ax-nearby {
    margin-top: var(--archex-gap-3);
    padding: var(--archex-gap-4);
    background: var(--archex-white);
    border: 1px solid var(--archex-border);
    border-left: 4px solid var(--archex-border);
    border-radius: var(--archex-radius-small);
}

.ax-nearby.has-history { border-left-color: var(--archex-ochre); background: var(--archex-panel); }

.ax-nearby-list {
    list-style: none;
    margin: var(--archex-gap-3) 0;
    padding: 0;
    display: grid;
    gap: 8px;
}

.ax-nearby-list li {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--archex-gap-3);
    flex-wrap: wrap;
    padding: 8px 12px;
    background: var(--archex-white);
    border: 1px solid var(--archex-border-soft);
    border-radius: var(--archex-radius-small);
}

.ax-nearby-list a { font-weight: 700; overflow-wrap: anywhere; }
.ax-nearby-list .ax-hint { margin: 0; text-align: right; }

/* The source's own words, never paraphrased. */
.ax-quote {
    margin: var(--archex-gap-3) 0;
    padding: var(--archex-gap-3) var(--archex-gap-4);
    background: var(--archex-panel);
    border-left: 3px solid var(--archex-sandstone);
    border-radius: 0 var(--archex-radius-small) var(--archex-radius-small) 0;
    font-size: var(--archex-text-md);
    font-style: italic;
}

/* PHONE WIDTHS (14 September 2026). At 375 px the top bar came to 550 px, so every page scrolled
   sideways on a phone: the search box would not shrink below 200 px, New Job kept its label, and the
   panel of the closed profile menu still took a box. The search, New Job, notifications and the
   profile menu all stay; they are made to fit. */
.ax-usermenu:not([open]) > .ax-usermenu-panel { display: none; }

@media (max-width: 600px) {
    .ax-app-topbar { gap: var(--archex-gap-2); }
    .ax-topsearch { flex: 1 1 auto; min-width: 0; padding: 0 var(--archex-gap-3); }
    .ax-app-topbar > .ax-spacer { display: none; }
    .ax-app-topbar > .ax-btn-primary > span { display: none; }
    .ax-usermenu-panel { max-width: calc(100vw - 24px); }
}

/* ================================================================================================
   NAVIGATION PROGRESS - the range pole across the top of the window
   ------------------------------------------------------------------------------------------------
   Enhanced navigation swaps pages without a browser page load, so the tab spinner and the address
   bar never move and a click on a slow page was indistinguishable from a click that did nothing.
   Driven by js/archex-progress.js. Banded like a surveyor's range pole, in the brand colour,
   because a generic blue stripe would be somebody else's application.
   ============================================================================================== */

#ax-nav-progress {
    position: fixed;
    inset: 0 0 auto 0;
    z-index: 4000;              /* above the rail and any page header, below a modal backdrop */
    height: 3px;
    overflow: hidden;
    pointer-events: none;       /* it is a report, never a target */
    opacity: 0;
    transition: opacity 180ms ease-out;
}

#ax-nav-progress.is-active {
    opacity: 1;
}

#ax-nav-progress span {
    position: absolute;
    /* Wider than the window on both sides so the marching bands never reveal an end. */
    inset: 0 -48px;
    display: block;
    background: repeating-linear-gradient(
        90deg,
        var(--color-primary) 0 18px,
        var(--color-primary-dark) 18px 24px,
        var(--color-surface) 24px 36px);
    animation: ax-nav-march 900ms linear infinite;
}

@keyframes ax-nav-march {
    to { transform: translateX(-36px); }
}

/* Reduced motion: still says "working", without anything travelling across the eye. */
@media (prefers-reduced-motion: reduce) {
    #ax-nav-progress span {
        animation: ax-nav-breathe 1.4s ease-in-out infinite;
        background: var(--color-primary);
    }

    @keyframes ax-nav-breathe {
        0%, 100% { opacity: .35; }
        50%      { opacity: 1; }
    }
}

/* TOUCH. The named controls in archex-components.css go to 44px under a thumb; .ax-btn is declared
   here, so its touch size is stated here too — a class belongs to one stylesheet, and there is a
   check that says so. min-height outranks the 40px height token without needing !important, which this
   stylesheet does not use. */
@media (pointer: coarse) {
    .ax-btn { min-height: 44px; }
}

/* ---- Printing (21 September 2026) ----------------------------------------------------------- */
/* The application had no print rules, so printing any page printed the brand bar, the top bar and the
   whole rail beside a squeezed page. On paper, only the page. Placed last so that source order does
   what !important would — this sheet keeps none. */
@media print {
    .ax-app-brandbar,
    .ax-app-topbar,
    .ax-app-rail,
    .ax-tabs { display: none; }

    .ax-app { display: block; }
    .ax-app-workspace { padding: 0; margin: 0; background: #fff; }

    /* No break-inside: avoid here. A card taller than a page cannot avoid breaking; told to, the
       browser pushed the whole SWMS onto page 2 and printed page 1 with nothing but the heading. */
    .ax-card { box-shadow: none; }

    body { background: #fff; }
}

/* ---- 24. THE TOP BAR ON A PHONE (29 September 2026) ---------------------------------------------

   Adam Deane, with ArchEx open on his handset for the first time: "i dont know how to add it to the
   phone, however it clearly needs fixing also."

   The bar is one flex row with a gap and had no narrow-width rules at all, because until today
   nothing had ever opened it on a 375 px screen. Search, New Job, the inbox, the chat icon, the
   notification bell, a clock and the user menu do not fit across a phone, so they overlapped: the
   search field collapsed underneath the New Job button and the two drew on top of each other.

   The rule is what a phone actually needs rather than a shrunken desktop. Search keeps its icon and
   opens when tapped; New Job keeps its plus and loses its words; the clock goes, because a phone
   puts the time in its own status bar two centimetres above. Nothing is removed that cannot be
   reached another way. */
@media (max-width: 720px) {
    .ax-app-topbar {
        gap: var(--archex-gap-2);
        padding: 0 var(--archex-gap-3);
    }

    /* The words go, the plus stays. It is the one control on this bar people press every day. */
    .ax-app-topbar .ax-btn-primary > span { display: none; }

    .ax-app-topbar .ax-btn-primary {
        padding-left: var(--archex-gap-3);
        padding-right: var(--archex-gap-3);
    }

    /* The phone shows the time in its own status bar; a second clock is just width. */
    .ax-app-topbar .ax-clock { display: none; }

    /* The name and role beside the avatar. The avatar itself stays, and the menu behind it is
       unchanged - that is where signing out lives. */
    .ax-app-topbar .ax-usermenu-copy { display: none; }

    /* Search shrinks to its icon and expands on focus rather than fighting for room it has not got.
       Without a min-width of 0 a flex item refuses to shrink below its content, which is what let
       it overlap the button beside it. */
    .ax-app-topbar .ax-globalsearch,
    .ax-app-topbar form {
        min-width: 0;
        flex: 0 1 auto;
    }

    .ax-app-topbar input[type="search"],
    .ax-app-topbar input[type="text"] {
        min-width: 0;
        width: 100%;
    }
}
