/* ===========================================================================
   SalesFlow

   The visual language is borrowed from the product itself. PPE lives under the
   ISO 7010 safety-sign standard, where a blue disc with a white pictogram means
   "mandatory - wear this" and yellow means "warning". Those signs are what a rep
   walks past all day in a customer's plant, so the category checklist is built
   out of them: blue disc = we supply this category, yellow ring = a competitor
   does. Everything else stays quiet so the checklist is the thing you remember.

   Built for a phone held one-handed in a warehouse: light ground for sunlight
   legibility, 48px minimum touch targets, and nothing that depends on hover.
   =========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,75..125,400..800;1,75..125,400..700&family=IBM+Plex+Mono:wght@400;500;600&display=swap');

:root {
    /* Safety-standard palette. These are the actual signage colours, not
       decorative approximations. */
    --concrete:      #eef0ee;   /* ground - cool grey, like a swept plant floor */
    --concrete-deep: #dfe2df;
    --surface:       #ffffff;
    --ink:           #14171a;
    --ink-soft:      #565f66;
    --ink-faint:     #8b959c;
    --hairline:      #d6dad7;

    --mandatory:     #005eb8;   /* ISO blue: "you must wear this" */
    --mandatory-dim: #e4eefa;
    --hazard:        #ffb81c;   /* ISO yellow: warning */
    --hazard-dim:    #fff5e0;
    --caution:       #c95000;   /* safety orange, deepened so white text on it stays readable */
    --signal:        #c8102e;   /* ISO red: prohibition / danger */
    --signal-dim:    #fdeaec;
    --safe:          #00843d;   /* ISO green: safe condition */
    --safe-dim:      #e3f3ea;

    --radius:     10px;
    --radius-sm:  6px;
    --tap:        48px;         /* minimum target - a gloved thumb, not a mouse */

    --shadow-card: 0 1px 2px rgb(20 23 26 / .06), 0 2px 8px rgb(20 23 26 / .04);
    --shadow-lift: 0 4px 16px rgb(20 23 26 / .12);

    --font-body: 'Archivo', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-code: 'IBM Plex Mono', ui-monospace, 'Cascadia Mono', monospace;

    --header-h:     56px;
    --header-gap:   10px;   /* concrete moat around the floating bars */
    --header-stick: 10px;   /* how far below the viewport top a stuck bar rests */
    --tabs-h:       62px;
}

/* Archivo is a variable font with a width axis. Widening it for labels gives
   the stencilled, machine-marked feel of equipment labelling without loading a
   second family. */
.signage {
    font-family: var(--font-body);
    font-variation-settings: 'wdth' 118;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .09em;
}

* { box-sizing: border-box; }

html {
    -webkit-text-size-adjust: 100%;
    -webkit-tap-highlight-color: transparent;
}

body {
    margin: 0;
    background: var(--concrete);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: 16px;              /* never smaller - iOS zooms the page on focus below 16 */
    line-height: 1.45;
    overscroll-behavior-y: contain;
}

h1, h2, h3 { margin: 0; line-height: 1.15; }

code, .code, .mono {
    font-family: var(--font-code);
    font-size: .875em;
    letter-spacing: -.01em;
}

/* Tabular numerals everywhere money and quantities appear, so columns line up. */
.num { font-variant-numeric: tabular-nums; }

a { color: var(--mandatory); }

:focus-visible {
    outline: 3px solid var(--mandatory);
    outline-offset: 2px;
    border-radius: 3px;
}
/* Blazor focuses each page's h1 after navigation (FocusOnNavigate) for screen readers.
   That focus is not something the user did, so it gets no ring - it boxed the login logo. */
h1[tabindex="-1"]:focus, h1[tabindex="-1"]:focus-visible { outline: none; }

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

.shell {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
}

/* The header is a floating dark bar rather than a white strip welded to the top of
   the screen. Ink is the same ground the sign-in screen uses, so the app reads as one
   product from the login onward, and it separates hard from the concrete body.

   The box-shadow is not a shadow - it is a solid concrete ring. A rounded sticky bar
   would otherwise show slivers of the page scrolling through its corner cut-outs; the
   ring paints a moat around the bar so content disappears cleanly underneath it. */
.topbar {
    position: sticky;
    top: calc(var(--header-stick) + env(safe-area-inset-top));
    z-index: 40;
    height: var(--header-h);
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 16px;
    /* The ring has no layout footprint, so the gap it paints over the following
       content has to be reserved here or it clips the top of the first card. */
    margin-bottom: var(--header-gap);
    border-radius: var(--radius);
    background: var(--ink);
    color: #fff;
    box-shadow: 0 0 0 var(--header-gap) var(--concrete);
}

/* Actions on the dark bar pick up the hazard yellow from the sign-in wordmark. */
.topbar .btn--quiet {
    color: var(--hazard);
}

.topbar .muted,
.topbar .faint {
    color: #9aa4ab;
}

.topbar__title {
    flex: 1;
    min-width: 0;
    font-size: 1.0625rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.topbar__back {
    width: 40px;
    height: 40px;
    margin-left: -10px;
    display: grid;
    place-items: center;
    border: 0;
    background: none;
    color: inherit;
    cursor: pointer;
}

.main {
    flex: 1;
    padding: calc(var(--header-gap) + env(safe-area-inset-top)) 14px
             calc(var(--tabs-h) + env(safe-area-inset-bottom) + 24px);
    max-width: 780px;
    width: 100%;
    margin-inline: auto;
}

/* ---------------------------------------------------------------------------
   Bottom navigation - thumb territory, so it lives at the bottom
   --------------------------------------------------------------------------- */

.tabs {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 50;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    background: var(--surface);
    border-top: 1px solid var(--hairline);
    padding-bottom: env(safe-area-inset-bottom);
}

.tab {
    min-height: var(--tabs-h);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    border: 0;
    background: none;
    color: var(--ink-soft);
    font: inherit;
    font-size: .6875rem;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    position: relative;
}

.tab.active { color: var(--mandatory); }

/* The active marker is a rule at the top edge, echoing the floor-marking tape
   that separates walkways from work areas. */
.tab.active::before {
    content: '';
    position: absolute;
    inset: 0 22% auto 22%;
    height: 3px;
    background: var(--mandatory);
}

.tab__badge {
    position: absolute;
    top: 6px;
    left: 50%;
    margin-left: 6px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    display: grid;
    place-items: center;
    border-radius: 9px;
    background: var(--hazard);
    color: var(--ink);
    font-size: .625rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   Cards and lists
   --------------------------------------------------------------------------- */

.card {
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
}

.card + .card { margin-top: 10px; }

.card__pad { padding: 14px; }

.section {
    margin-block: 26px 12px;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

.section:first-child { margin-top: 4px; }

.section__label {
    font-family: var(--font-body);
    font-variation-settings: 'wdth' 118;
    font-weight: 700;
    letter-spacing: .01em;
    font-size: .875rem;
    color: var(--ink-soft);
}

.section__hint {
    font-size: .75rem;
    color: var(--ink-faint);
}

/* Tappable list row */
.row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-height: var(--tap);
    padding: 12px 14px;
    background: var(--surface);
    border: 0;
    border-bottom: 1px solid var(--hairline);
    color: inherit;
    font: inherit;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}

.row:last-child { border-bottom: 0; }
.row:active { background: var(--concrete); }

.row__body { flex: 1; min-width: 0; }

.row__title {
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.row__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 10px;
    margin-top: 2px;
    font-size: .8125rem;
    color: var(--ink-soft);
}

.row__chevron { color: var(--ink-faint); flex-shrink: 0; }

.list { border-radius: var(--radius); overflow: hidden; }

/* ---------------------------------------------------------------------------
   Buttons
   --------------------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: var(--tap);
    padding: 0 20px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: var(--mandatory);
    color: #fff;
    font: inherit;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    cursor: pointer;
    text-decoration: none;
}

.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn:active:not(:disabled) { transform: translateY(1px); }

.btn--block { width: 100%; }
.btn--ghost { background: var(--surface); color: var(--ink); border-color: var(--hairline); }
.btn--quiet { background: none; color: var(--mandatory); min-height: 40px; padding: 0 8px; }
.btn--danger { background: var(--signal); }
.btn--safe   { background: var(--safe); }
.btn--caution { background: var(--caution); }

/* A destructive action should read as a warning, not as a call to action. Transparent with
   red text keeps Delete from competing with the primary button sitting right above it -
   and the confirm dialog, not the button, is what carries the weight. Two classes so this
   beats .btn--danger's solid fill regardless of source order. */
.btn--quiet.btn--danger { background: none; color: var(--signal); }
/* Outlined danger: a secondary action that destroys something - white, red text and edge. */
.btn--ghost.btn--danger { background: var(--surface); color: var(--signal); border-color: var(--signal); }
.btn--lg { min-height: 56px; font-size: 1.0625rem; }

/* ---------------------------------------------------------------------------
   Fields
   --------------------------------------------------------------------------- */

.field { margin-bottom: 16px; }

.field__label {
    display: block;
    margin-bottom: 6px;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--ink-soft);
}

.field__hint {
    margin-top: 5px;
    font-size: .75rem;
    color: var(--ink-faint);
}

.input, .textarea, .select {
    width: 100%;
    min-height: var(--tap);
    padding: 12px 14px;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--ink);
    font: inherit;
    font-size: 1rem;
}

.textarea { min-height: 96px; resize: vertical; line-height: 1.5; }

.input:focus, .textarea:focus, .select:focus {
    border-color: var(--mandatory);
    outline: 2px solid var(--mandatory-dim);
    outline-offset: 0;
}

.input.invalid, .textarea.invalid { border-color: var(--signal); }

/* An input with a button sitting inside its right edge - the show/hide password eye.
   The input is padded so long text never runs underneath the button. */
.input-with-action {
    position: relative;
}

.input-with-action .input {
    padding-right: 52px;
}

.input-action {
    position: absolute;
    top: 0;
    right: 0;
    /* Visually a 44px square, but stretched to the full field height so the tap target
       is the whole right end of the input rather than a small icon. */
    height: 100%;
    width: 48px;
    display: grid;
    place-items: center;
    border: 0;
    background: none;
    color: var(--ink-faint);
    cursor: pointer;
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

.input-action:hover { color: var(--ink-soft); }

.input-action[aria-pressed='true'] { color: var(--mandatory); }

/* On the dark sign-in screen the icon needs to lift off the near-black field. */
.login .input-action { color: #6a747b; }
.login .input-action:hover { color: #9aa4ab; }
.login .input-action[aria-pressed='true'] { color: var(--hazard); }

.validation-message { color: var(--signal); font-size: .8125rem; margin-top: 5px; }

/* ---------------------------------------------------------------------------
   Signature element: mandatory-action signage for product categories
   --------------------------------------------------------------------------- */

/* minmax(0, 1fr), not 1fr. A bare 1fr is minmax(auto, 1fr), so the column refuses to
   shrink below its content's min-content width - which pushed the category rows past
   the card edge and gave the whole page a horizontal scroll at 375px. */
.cat {
    display: grid;
    grid-template-columns: 52px minmax(0, 1fr);
    gap: 12px;
    padding: 14px;
    border-bottom: 1px solid var(--hairline);
}

.cat > * { min-width: 0; }

.cat:last-child { border-bottom: 0; }

/* The disc. Blue and filled means we supply this category, exactly as a blue
   mandatory sign means the PPE is required. Yellow ring means somebody else
   supplies it - a warning state, because that is what it is commercially. */
.cat__disc {
    width: 52px;
    height: 52px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    border: 3px solid var(--hairline);
    background: var(--surface);
    color: var(--ink-faint);
    transition: background-color .18s ease, border-color .18s ease, color .18s ease;
}

.cat__disc svg { width: 26px; height: 26px; display: block; }

.cat__disc--initials {
    font-variation-settings: 'wdth' 118;
    font-weight: 800;
    font-size: .9375rem;
    letter-spacing: .02em;
}

.cat[data-state='yes'] .cat__disc {
    background: var(--mandatory);
    border-color: var(--mandatory);
    color: #fff;
}

.cat[data-state='no'] .cat__disc {
    background: var(--hazard-dim);
    border-color: var(--hazard);
    color: #6b4a00;
}

.cat__name {
    font-variation-settings: 'wdth' 115;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .07em;
    font-size: .875rem;
}

.cat__history {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-top: 2px;
    font-size: .75rem;
    color: var(--safe);
    font-weight: 600;
}

/* Three-state control. "Not asked" is a real answer and stays available, because
   a rep who never raised the subject has not learned that the customer says no. */
.tri {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    margin-top: 10px;
}

/* Unselected sits recessed on a grey ground rather than white-on-white, so a filled
   answer reads as filled at a glance - in sunlight, at arm's length, mid-conversation. */
.tri__btn {
    min-height: 46px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-sm);
    background: var(--concrete);
    color: var(--ink-faint);
    font: inherit;
    font-weight: 700;
    /* Sized so BUYS FROM US plus the selected-state tick still fits one line in a
       half-width column - at the old size the tick pushed the label onto two rows. */
    font-size: .75rem;
    letter-spacing: .02em;
    white-space: nowrap;
    padding: 0 4px;
    text-transform: uppercase;
    cursor: pointer;
    transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}

/* A tick as well as a colour. Colour alone fails in glare and fails for anyone who
   cannot separate the blue from the yellow. */
.tri__btn[aria-pressed='true']::before {
    content: '';
    width: 13px;
    height: 13px;
    flex-shrink: 0;
    background: currentColor;
    -webkit-mask: var(--tick) center / contain no-repeat;
    mask: var(--tick) center / contain no-repeat;
}

:root {
    --tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4.5 12.5 5 5 10-11'/%3E%3C/svg%3E");
}

.tri__btn[aria-pressed='true'] {
    box-shadow: 0 1px 3px rgb(20 23 26 / .18);
}

.tri__btn[aria-pressed='true'][data-value='yes'] {
    background: var(--mandatory);
    border-color: var(--mandatory);
    color: #fff;
}

.tri__btn[aria-pressed='true'][data-value='no'] {
    background: var(--hazard);
    border-color: #d99500;
    color: #3d2a00;
}

/* A neutral negative, for plain yes/no questions where "no" carries no warning. */
.tri__btn[aria-pressed='true'][data-value='plain'] {
    background: var(--ink);
    border-color: var(--ink);
    color: #fff;
}

.cat__comment { margin-top: 10px; }

/* ---------------------------------------------------------------------------
   Action items

   Global rather than page-scoped: these render both inside the visit report and on
   My day. A <style> block in a .razor page only exists in the DOM while that page
   is rendered, so keeping them there would leave the tick boxes unstyled for anyone
   who opened My day without visiting a report first.
   --------------------------------------------------------------------------- */

.action {
    display: grid;
    grid-template-columns: 40px minmax(0, 1fr);
    align-items: start;
    gap: 8px;
    /* Matches .card__pad on the right and bottom so the fields line up with every other
       card in the form. The left is tighter only because the tick column carries its own
       space. */
    padding: 12px 14px;
    border-bottom: 1px solid var(--hairline);
}

.action:last-of-type { border-bottom: 0; }

.action--done .action__text { text-decoration: line-through; color: var(--ink-faint); }

/* A 44px target for something tapped with a thumb, often in gloves. */
.action__tick {
    position: relative;
    width: 40px;
    height: 44px;
    display: grid;
    place-items: center;
    border: 0;
    background: none;
    cursor: pointer;
    color: #fff;
    flex-shrink: 0;
}

.action__tick::before {
    content: '';
    position: absolute;
    width: 24px;
    height: 24px;
    border: 2px solid var(--hairline);
    border-radius: 6px;
    background: var(--surface);
}

.action__tick[aria-pressed='true']::before {
    background: var(--safe);
    border-color: var(--safe);
}

.action__tick svg { position: relative; }

.action__body { min-width: 0; }

/* A real bordered field rather than a borderless line. The borderless version only
   looked editable once it had focus, and sat flush against the edges - which read as
   cramped even when the spacing was technically correct. */
.action__text {
    min-height: 44px;
    padding: 10px 12px;
    font-size: .9375rem;
}

.action__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 8px; }

/* The due date shows as a small chip - icon plus "24 Aug" - with the real date
   input stretched invisibly over it. Tapping the chip therefore taps the input, which
   opens the platform's own picker; opacity rather than display:none because iOS will
   not open a picker for an input it considers hidden. */
.action__datechip {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    min-height: 38px;
    padding: 6px 10px;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-sm);
    font-size: .8125rem;
    color: var(--ink-soft);
    cursor: pointer;
    white-space: nowrap;
}

.action__datechip select,
.action__datechip input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

.action__remove {
    margin-left: auto;
    color: var(--ink-faint);
    min-height: 38px;
    flex-shrink: 0;
}

/* ---------------------------------------------------------------------------
   Status pills and banners
   --------------------------------------------------------------------------- */

.pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    white-space: nowrap;
}

.pill--quote  { background: var(--mandatory-dim); color: #00417f; }
.pill--order  { background: var(--safe-dim);      color: #005c2a; }
.pill--warn   { background: var(--hazard-dim);    color: #6b4a00; }
.pill--danger { background: var(--signal-dim);    color: #8f0b21; }
.pill--muted  { background: var(--concrete-deep); color: var(--ink-soft); }
/* Whose visit it is - only ever shown to managers, Marketing and admins, on other people's. */
.pill--owner  { background: var(--ink); color: #fff; }

.banner {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    border-radius: var(--radius-sm);
    font-size: .875rem;
    margin-bottom: 14px;
}

.banner--warn   { background: var(--hazard-dim); color: #5c3f00; }
.banner--danger { background: var(--signal-dim); color: #8f0b21; }
.banner--info   { background: var(--mandatory-dim); color: #00417f; }
.banner--safe   { background: var(--safe-dim); color: #005c2a; }

/* Hazard tape. Used in exactly one place - the offline bar - because that is
   the one moment the rep needs to stop and read. Anywhere else it would be
   decoration pretending to be information. */
/* Sits below the header with the same moat between them, so two ink bars read as two
   separate things rather than one dark slab. */
.offline-bar {
    position: sticky;
    top: calc(var(--header-stick) + env(safe-area-inset-top) + var(--header-h) + var(--header-gap));
    z-index: 39;
    margin-top: var(--header-gap);
    padding: 11px 16px 9px;
    border-radius: var(--radius);
    background: var(--ink);
    color: #fff;
    font-size: .8125rem;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 8px;
    overflow: hidden;
    box-shadow: 0 0 0 var(--header-gap) var(--concrete);
    margin-bottom: var(--header-gap);
}

.offline-bar::before {
    content: '';
    position: absolute;
    inset: 0 0 auto 0;
    height: 4px;
    background: repeating-linear-gradient(
        45deg,
        var(--hazard) 0 10px,
        var(--ink) 10px 20px
    );
}

/* ---------------------------------------------------------------------------
   Empty and loading states
   --------------------------------------------------------------------------- */

.empty {
    padding: 44px 24px;
    text-align: center;
    color: var(--ink-soft);
}

.empty__title { font-weight: 600; color: var(--ink); margin-bottom: 6px; }
.empty__body { font-size: .875rem; }

.skeleton {
    height: 62px;
    border-radius: var(--radius);
    background: linear-gradient(90deg, var(--concrete-deep) 25%, #e9ebe9 50%, var(--concrete-deep) 75%);
    background-size: 200% 100%;
    animation: sweep 1.3s linear infinite;
}

.skeleton + .skeleton { margin-top: 8px; }

@keyframes sweep {
    to { background-position: -200% 0; }
}

/* ---------------------------------------------------------------------------
   Login - the one screen that is not inside the shell
   --------------------------------------------------------------------------- */

.login {
    min-height: 100dvh;
    display: grid;
    grid-template-rows: 1fr;
    padding: 32px 22px calc(24px + env(safe-area-inset-bottom));
    /* The photographic background flipped this screen from dark to light, so every
       colour below follows. The ink fallback paints first in case the image is slow
       on mobile data. */
    background: var(--concrete) url('../Main_backround.png') center / cover no-repeat;
    color: var(--ink);
}

/* A frosted card, matching the ice in the photograph, so the form stays readable
   over the busy right-hand side of the image on wide screens. */
.login__inner {
    width: 100%;
    max-width: 380px;
    margin: auto;
    padding: 26px 22px;
    border-radius: var(--radius);
    background: rgba(255, 255, 255, .84);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    box-shadow: var(--shadow-card);
}

.login__mark {
    font-variation-settings: 'wdth' 122;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .14em;
    font-size: 1.75rem;
    line-height: 1;
}

.login__mark span { color: var(--hazard); }

/* The drawn logo. Height, not width: the SVG is 520x120, so 44px tall lands around
   190px wide - the same visual weight the typed wordmark had. */
.login__logo { display: block; height: 48px; width: auto; max-width: 100%; margin-inline: auto; }

.login__tagline {
    margin: 10px 0 30px;
    color: var(--ink-soft);
    font-size: .9375rem;
    text-align: center;
}

.login__foot {
    margin-top: 18px;
    text-align: center;
    font-size: .75rem;
    color: var(--ink-soft);
    line-height: 1.45;
}

.login__foot p { margin: 0; }

/* Sits below the offline note, quieter still and separated by a hairline: it is a
   legal notice, not something anyone signing in needs to read. */
.login__copy {
    margin-top: 12px !important;
    padding-top: 12px;
    border-top: 1px solid rgba(20, 23, 26, .15);
    font-size: .6875rem;
    color: var(--ink-soft);
    line-height: 1.5;
}

/* ---------------------------------------------------------------------------
   Utilities
   --------------------------------------------------------------------------- */

.stack > * + * { margin-top: 10px; }
.flex { display: flex; align-items: center; gap: 10px; }
.flex--between { justify-content: space-between; }
.grow { flex: 1; min-width: 0; }
.muted { color: var(--ink-soft); }
.faint { color: var(--ink-faint); }
.small { font-size: .8125rem; }
.tiny { font-size: .75rem; }
.strong { font-weight: 600; }
.right { text-align: right; }
.truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Blazor's built-in error UI */
#blazor-error-ui {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 100;
    padding: 14px 18px;
    background: var(--signal);
    color: #fff;
    display: none;
}

#blazor-error-ui .dismiss { float: right; cursor: pointer; font-weight: 700; }

.loading-progress { display: grid; place-items: center; min-height: 100dvh; color: var(--ink-soft); }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
    }
}

/* Tablet and up: the list/detail split earns its keep on a manager's laptop,
   but reps are on phones and that is what the layout is tuned for. */
@media (min-width: 700px) {
    .main { padding-left: 22px; padding-right: 22px; }
    .tri { grid-template-columns: 140px 140px; }
}

/* ---------------------------------------------------------------------------
   Metric tiles

   Shared by the customer screen and the dashboard. These lived in a <style> block
   inside CustomerPage until the dashboard needed them - a page-local style block only
   exists while that page is rendered, so the tiles came out unstyled anywhere else.
   --------------------------------------------------------------------------- */

/* Two by two. Counts on the top row, revenue and last purchase on the second - which
   is only possible because both are shortened to fit half a phone width. */
.metrics {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin: 14px 0 4px;
}

.metric {
    padding: 12px 14px;
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
    min-width: 0;   /* let the grid track shrink instead of the text forcing it wider */
}

/* The customer record has five tiles. Two a row on a phone leaves one over, so the
   last runs the full width rather than sitting alone beside a gap. */
.metrics--five > .metric:last-child { grid-column: 1 / -1; }

/* A tile that is also a way in - the visits count opens the Visits tab. */
.metric--button {
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}
.metric--button:focus-visible { outline: 2px solid var(--mandatory); outline-offset: 2px; }

/* Back orders only shout when there are some. A permanent coloured tile is wallpaper
   within a day; one that changes colour is information. */
.metric--attention {
    background: var(--hazard-dim);
    border-color: var(--hazard);
}

.metric__label {
    font-variation-settings: 'wdth' 112;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .07em;
    font-size: .6875rem;
    color: var(--ink-soft);
}

.metric__value {
    margin-top: 4px;
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.1;
}

.metric__value--sm { font-size: 1.0625rem; }

.metric__note {
    margin-top: 4px;
    font-size: .6875rem;
    color: var(--ink-soft);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 5px;
    white-space: nowrap;
}

.delta {
    font-weight: 700;
    padding: 1px 6px;
    border-radius: 999px;
    font-size: .6875rem;
}

.delta--up   { background: var(--safe-dim);   color: #005c2a; }
.delta--down { background: var(--signal-dim); color: #8f0b21; }


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

   Built to be read at arm's length on a phone: one headline number, then tiles,
   then detail. The bar chart is CSS rather than a charting library - thirteen
   bars do not justify shipping one, and this way it inherits the theme.
   --------------------------------------------------------------------------- */

.scopeline {
    font-variation-settings: 'wdth' 112;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .07em;
    font-size: .6875rem;
    color: var(--ink-soft);
    margin: 0 2px 8px;
}

.repbar { margin-bottom: 12px; }

.panel {
    padding: 14px;
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
    margin-bottom: 10px;
}

.panel__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 10px;
}

.panel__title {
    font-size: .9375rem;
    font-weight: 700;
    margin: 0;
}

/* The one number the page exists to show. */
.headline__value {
    font-size: 2.25rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -.02em;
}

.headline__notes {
    margin-top: 8px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    font-size: .75rem;
}

/* Target progress. Capped at 100% width so beating target does not run off the
   card - the percentage underneath carries the overshoot. */
.progress {
    margin-top: 12px;
    height: 8px;
    border-radius: 999px;
    background: var(--concrete);
    overflow: hidden;
}

.progress__bar { height: 100%; border-radius: 999px; }
.progress__bar--good   { background: var(--safe); }
.progress__bar--near   { background: var(--hazard); }
.progress__bar--behind { background: var(--signal); }

/* Thirteen columns, so each gets about 7% of the width. */
.trend {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 130px;
}

.trend__col {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    height: 100%;
}

.trend__stack {
    position: relative;
    flex: 1;
    display: flex;
    align-items: flex-end;
}

.trend__bar {
    width: 100%;
    background: var(--mandatory);
    border-radius: 2px 2px 0 0;
    min-height: 2px;
}

/* The month in progress is not comparable with the twelve complete ones behind it,
   so it is drawn open rather than solid. */
.trend__bar--now {
    background: repeating-linear-gradient(
        135deg,
        var(--mandatory) 0 4px,
        var(--mandatory-dim) 4px 8px
    );
}

.trend__target {
    position: absolute;
    left: 0;
    right: 0;
    height: 0;
    border-top: 2px dashed var(--ink-soft);
    opacity: .55;
}

.trend__label {
    margin-top: 4px;
    text-align: center;
    font-size: .5625rem;
    color: var(--ink-soft);
    overflow: hidden;
}

/* ---------------------------------------------------------------------------
   Tables

   Only the dashboard uses one. A table beats stacked cards here because the whole
   point is comparing reps down a column.
   --------------------------------------------------------------------------- */

.tablewrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    margin: 0 -14px;
    padding: 0 14px;
}

.table {
    width: 100%;
    border-collapse: collapse;
    font-size: .8125rem;
    white-space: nowrap;
}

.table th {
    text-align: left;
    font-variation-settings: 'wdth' 112;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    font-size: .625rem;
    color: var(--ink-soft);
    padding: 0 8px 6px 0;
    border-bottom: 1px solid var(--hairline);
}

.table td {
    padding: 9px 8px 9px 0;
    border-bottom: 1px solid var(--hairline);
    vertical-align: middle;
}

.table th.num, .table td.num { text-align: right; padding-right: 0; }
.table tr:last-child td { border-bottom: 0; }

.table__name { display: block; font-weight: 600; white-space: normal; }

.table__row--tap { cursor: pointer; }
.table__row--tap:active { background: var(--concrete); }

.mono { font-family: var(--font-mono, ui-monospace, monospace); }

/* The revenue headline shares its card with the margin block. Flex with the margin
   pushed to the far edge - hugging the revenue left a field of dead space on anything
   wider than a phone. On a narrow phone it wraps below the revenue instead of crushing
   it, still anchored right. */
.headline { display: flex; flex-wrap: wrap; gap: 16px 28px; align-items: flex-start; }
.headline__main { flex: 1 1 220px; min-width: 0; }

.headline__side {
    flex: 0 1 auto;
    margin-left: auto;
    padding-top: 4px;
    text-align: right;
}

.headline__side .metric__note { justify-content: flex-end; }

.headline__sidevalue {
    margin-top: 4px;
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.1;
}

/* Ranked bar lists - top customers, top products. A list with a bar under each label
   rather than a sideways bar chart: the labels are long company and product names, and
   they matter more than the geometry. */
.rank {
    list-style: none;
    margin: 0;
    padding: 0;
    counter-reset: rankpos;
}

.rank__row { counter-increment: rankpos; }
.rank__row + .rank__row { border-top: 1px solid var(--hairline); }

.rank__link {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 9px 0;
    color: inherit;
    text-decoration: none;
}

/* The position number comes from the counter, so the markup stays a plain list. */
.rank__body::before {
    content: counter(rankpos);
    float: left;
    width: 20px;
    margin-right: 6px;
    font-variation-settings: 'wdth' 112;
    font-weight: 700;
    font-size: .6875rem;
    color: var(--ink-soft);
    line-height: 1.5;
}

.rank__body { flex: 1; min-width: 0; }

.rank__label {
    display: block;
    font-size: .8125rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.rank__track {
    display: block;
    height: 5px;
    margin-top: 5px;
    border-radius: 999px;
    background: var(--concrete);
    overflow: hidden;
}

.rank__bar {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: var(--mandatory);
}

.rank__amt {
    flex: 0 0 auto;
    font-size: .8125rem;
    font-weight: 700;
}

a.rank__link:active { background: var(--concrete); }

/* The two add buttons under the action list - side by side, sharing the width.
   Solid fills, blue for a todo and red for an issue, matching the pills the created
   items wear - the button teaches the colour code. Breathing room above so they read
   as controls for the whole list, not part of the last row. */
.action__addrow { display: flex; gap: 8px; padding-top: 14px; }
.action__addrow .btn { flex: 1; }

/* The type pill on an action row is a button (tap flips it), so it needs its
   button-chrome stripped. */
.action__type {
    border: 0;
    font: inherit;
    font-size: .6875rem;
    font-weight: 700;
    cursor: pointer;
}

/* Town headers in the by-route view of the customer list. A solid band in full ink,
   not a faint caption: on the road this is the label a rep scans for while half-looking
   at the screen, so it has to be findable at arm's length. */
.routehead {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    background: var(--concrete-deep);
    font-variation-settings: 'wdth' 112;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .07em;
    font-size: .8125rem;
    color: var(--ink);
}

.routehead + .row { border-top: 0; }

.routehead__count {
    margin-left: auto;
    min-width: 26px;
    text-align: center;
    padding: 1px 8px;
    border-radius: 999px;
    background: var(--surface);
    font-size: .75rem;
    font-weight: 700;
    color: var(--ink-soft);
}

/* Two fields sharing a row - phone and email on the prospect form. */
.two-up { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.two-up .field { min-width: 0; }

/* The prospect form's category picker borrows .tri__btn wholesale; this variant
   only relaxes the two-column grid so any number of categories can flow. Long names
   ("Hearing protection") still fit because each cell is half the card. */
.tri--wrap { grid-template-columns: 1fr 1fr; margin-top: 8px; }
.tri--wrap .tri__btn { text-transform: none; letter-spacing: 0; }

/* Office-task capture: the customer picker dropdown and the picked state. */
.pickerlist {
    margin-top: 6px;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: var(--surface);
}

.pickerlist__row {
    display: block;
    width: 100%;
    text-align: left;
    padding: 10px 12px;
    border: 0;
    background: none;
    font: inherit;
    cursor: pointer;
}

.pickerlist__row + .pickerlist__row { border-top: 1px solid var(--hairline); }
.pickerlist__row:active { background: var(--concrete); }
.pickerlist__row .tiny { display: block; margin-top: 1px; }

.picked {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-sm);
    background: var(--concrete);
}

/* Walk-in / Call / Email: three across, same recessed-to-filled buttons as everywhere. */
.tri--three { grid-template-columns: 1fr 1fr 1fr; margin-top: 8px; }
.tri--three .tri__btn { text-transform: none; letter-spacing: 0; }

/* An activity row whose left edge may hold a tick. The link takes over the row's
   flex duties so the whole remainder of the row is still one big tap target. */
.actrow { gap: 10px; }
.actrow__move { flex-shrink: 0; min-height: 40px; min-width: 40px; padding: 4px 8px; font-size: .8125rem; }
@media (max-width: 559px) { .actrow__movetext { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); } }

.actrow__link {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 12px;
    color: inherit;
    text-decoration: none;
}

/* ---------------------------------------------------------------------------
   Desktop

   The 780px column is the phone design doing its job; this layer widens only the
   screens that earn it - lists, the dashboard, the report - via .main--wide, which
   the layout applies by route. Capture forms keep their measure on purpose: an
   input stretched across a monitor is harder to use, not easier. Below 1000px
   none of this exists and phones are untouched.
   --------------------------------------------------------------------------- */
@media (min-width: 1000px) {
    .main--wide { max-width: 1360px; }

    /* Metric tiles: four across instead of two-by-two. */
    .main--wide .metrics { grid-template-columns: repeat(4, 1fr); gap: 10px; }
    .main--wide .metrics--five { grid-template-columns: repeat(5, minmax(0, 1fr)); }
    .main--wide .metrics--five > .metric:last-child { grid-column: auto; }

    /* Thirteen months get room to breathe. */
    .main--wide .trend { height: 210px; }
    .main--wide .trend__label { font-size: .6875rem; }

    /* Top customers and top products sit side by side. */
    .main--wide .panel-pair {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 10px;
        align-items: start;
    }
    .main--wide .panel-pair .panel { margin-bottom: 10px; }

    /* The headline number can afford desktop scale. */
    .main--wide .headline__value { font-size: 3rem; }

    /* A capture form embedded in a wide screen - the prospect sheet - keeps a
       form-sized measure, centred. */
    .main--wide .sheet-narrow { max-width: 720px; margin-inline: auto; }

    /* Prospect category buttons: four per row once there is room. */
    .main--wide .tri--wrap { grid-template-columns: repeat(4, 1fr); }

    /* The by-rep table stops needing to scroll sideways almost everywhere;
       give its text a touch more air while we are here. */
    .main--wide .table { font-size: .875rem; }
    .main--wide .table td { padding-top: 10px; padding-bottom: 10px; }
}

/* The check-in map on the visits report. Isolated stacking context so Leaflet's own
   z-indexes stay inside the card instead of floating over the sticky top bar. */
.visitmap {
    height: 420px;
    border: 1px solid var(--hairline);
    border-radius: var(--radius);
    overflow: hidden;
    isolation: isolate;
    z-index: 0;
    margin-bottom: 14px;
}

/* Productivity rows: name plus three metric cells, each a count over a mini-bar.
   Every bar column scales to its own maximum - visits and quotes are different
   sports, so sharing a scale would flatten whichever is smaller. */
.prod__row {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) 1fr 1fr 1fr;
    gap: 10px;
    align-items: center;
    padding: 7px 0;
    border-bottom: 1px solid var(--hairline);
}

.prod__row:last-child { border-bottom: 0; }
.prod__row--head { padding: 0 0 4px; border-bottom: 1px solid var(--hairline); }

.prod__metric {
    font-variation-settings: 'wdth' 112;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    font-size: .625rem;
    color: var(--ink-soft);
}

.prod__name {
    font-size: .8125rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.prod__cell .num { font-size: .8125rem; }

.prod__bar {
    display: block;
    height: 4px;
    margin-top: 3px;
    border-radius: 999px;
    background: var(--concrete);
    overflow: hidden;
}

.prod__bar > span { display: block; height: 100%; border-radius: 999px; background: var(--mandatory); }
.prod__bar--task > span { background: var(--hazard); }
.prod__bar--quote > span { background: var(--safe); }

/* A to-do or issue handed to someone other than the visit's rep - marked so it is
   obvious at a glance that it has left this person's list. */
.action__assign--away { background: var(--ink); color: #fff; border-color: var(--ink); }
.action__datechip select { appearance: none; -webkit-appearance: none; border: 0; }

/* ---- Pick lists ------------------------------------------------------------------
   The app's dropdown, replacing <select> everywhere: the desktop browser's list is a
   cramped grey box. Anchored under its field on wider screens (placed in script, so a
   card's overflow cannot clip it); a sheet from the bottom on a phone, where a thumb can
   reach every row. */
.picker { position: relative; display: block; }
.picker--chip { display: inline-flex; }
.picker--gap { margin-bottom: 8px; }

.picker__field {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    width: 100%; min-height: var(--tap); padding: 10px 12px 10px 14px;
    border: 1px solid var(--hairline); border-radius: var(--radius-sm);
    background: var(--surface); color: var(--ink);
    font: inherit; font-size: 1rem; text-align: left; cursor: pointer;
}
.picker__field:focus-visible, .picker__field[aria-expanded="true"] {
    border-color: var(--mandatory); outline: 2px solid var(--mandatory-dim); outline-offset: 0;
}
.picker__field:disabled { background: var(--concrete); color: var(--ink-faint); cursor: default; }
.picker__value { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.picker__value--empty { color: var(--ink-faint); }
.picker__chevron { flex-shrink: 0; color: var(--ink-soft); transition: transform .15s ease; }
.picker__field[aria-expanded="true"] .picker__chevron { transform: rotate(180deg); }

button.action__datechip { background: var(--surface); font: inherit; font-size: .8125rem; }
button.action__datechip.action__assign--away { background: var(--ink); color: #fff; }

.picker__backdrop {
    position: fixed; inset: 0; z-index: 70;
    border: 0; padding: 0; background: transparent; cursor: default;
}

.picker__menu {
    position: absolute; top: calc(100% + 6px); left: 0; z-index: 71;
    min-width: 240px; max-width: min(380px, calc(100vw - 16px));
    max-height: 460px; overflow-y: auto; overscroll-behavior: contain;
    padding: 6px;
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lift);
}
.picker__menu:focus { outline: none; }

.picker__title {
    padding: 8px 10px 6px;
    font-size: .6875rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
    color: var(--ink-faint);
}

.picker__search { min-height: 40px; padding: 8px 12px; margin: 2px 0 6px; font-size: .9375rem; }

.picker__option {
    display: flex; align-items: center; gap: 10px;
    width: 100%; min-height: 44px; padding: 6px 10px;
    border: 0; border-radius: var(--radius-sm);
    background: none; color: var(--ink);
    font: inherit; font-size: .9375rem; text-align: left; cursor: pointer;
}
.picker__option:hover, .picker__option:focus-visible { background: var(--concrete); outline: none; }
.picker__option--on { font-weight: 700; }
.picker__tick { flex-shrink: 0; color: var(--mandatory); }

.picker__avatar {
    display: inline-grid; place-items: center; flex-shrink: 0;
    width: 30px; height: 30px; border-radius: 50%;
    background: var(--concrete-deep); color: var(--ink-soft);
    font-size: .75rem; font-weight: 700; letter-spacing: .02em;
}
.picker__option--on .picker__avatar { background: var(--ink); color: #fff; }

.picker__label { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.picker__hint { font-size: .75rem; font-weight: 400; color: var(--ink-faint); }
.picker__none { padding: 12px 10px; font-size: .875rem; color: var(--ink-faint); }

@media (max-width: 559px) {
    .picker__backdrop { background: rgb(20 23 26 / .35); }
    .picker__menu {
        position: fixed; top: auto; left: 12px; right: 12px;
        bottom: calc(12px + env(safe-area-inset-bottom));
        min-width: 0; max-width: none; max-height: 65dvh;
        padding: 8px;
    }
    .picker__option { min-height: var(--tap); font-size: 1rem; }
}

/* ---- Labelled line figures: Qty / Unit Price / Extended ------------------------------
   Used on the Purchased tab and on order and quote lines. Three bare numbers in a column
   read as a puzzle; a caption over each says which is which. */
.figrow .row__body { min-width: 0; width: 100%; }
.figs {
    display: grid; grid-template-columns: minmax(0, .8fr) minmax(0, 1.1fr) minmax(0, 1.1fr);
    gap: 8px; margin: 10px 0 0; padding-top: 8px; border-top: 1px dashed var(--hairline);
}
.figs > div { min-width: 0; }
.figs dt {
    font-size: .6875rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
    color: var(--ink-faint); margin: 0 0 2px;
}
.figs dd { margin: 0; font-size: .9375rem; overflow-wrap: anywhere; }
.figs > div:last-child { text-align: right; }
.figs__range { display: block; font-size: .75rem; color: var(--ink-faint); }

.figs-total {
    display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
    padding: 12px 16px; border-top: 1px solid var(--hairline); font-size: .875rem;
}
