/* Base Styles */
/* Design tokens, copied verbatim from the walkthrough designs in specs/docs — that :root block is the
   source of truth for the app's look, so the values live here unaltered rather than approximated. */
:root {
    --blue: #2D6CB8; --lblue: #7EB3F0; --brand: #0174DA; --pill: #EAF2FC;
    --ink: #1A2331; --muted: #5C6472; --line: #E1E5EC; --line2: #EDF0F4;
    --page: #EEF1F6; --th: #F7F9FC;
    --ok: #2EA661; --warn: #E89720; --bad: #C0392B;
    --t1: #2D6CB8; --t2: #D8E8F9; --t3: #F0F6FD; --t4: #FFFFFF;
    /* subcontractor identity accent */
    --sub: #2E9E7E; --sub-soft: #6FC3A8; --sub-pill: #E9F7F2;
}

/* Padding counts INSIDE a declared width. Without this, any `width: 100%` element that also has padding
   is wider than its parent — the page shell was 48px wider than the viewport on every screen, which is
   what made content sit off-centre and the sticky header stop short of the right edge. The app had no
   box-sizing reset at all; this is the conventional baseline. */
*, *::before, *::after {
    box-sizing: border-box;
}

/* Always leave room for the scrollbar, whether or not this page needs one. The document is what
   scrolls, so on a short page the bar disappears, the viewport gets ~15px wider, and every centred thing
   on it slides sideways — clicking between a long list and a short one moved the whole page. Reserving
   the gutter is the fix rather than hiding the bar: the bar is the only thing telling anyone there is
   more below. On html alone, since that is the element doing the scrolling. */
html {
    scrollbar-gutter: stable;
}

html, body {
    height: 100%;
    margin: 0;
    /* Typeface left as-is. The designs are drawn in Open Sans, but adopting it means deciding whether to
       self-host or pull from a CDN — a call to make through the spec, not a side effect of a style pass. */
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
    /* The page sits BEHIND white cards and tables — that contrast is what gives them their edges. A white
       page flattens every card in the app against it. */
    background-color: var(--page);
    color: var(--ink);
}

/* ---- The page head, defined ONCE (walkthrough .head / .crumb / h1 / .sub) ----------------------
   Thirteen scoped stylesheets each had their own .page-title (1.5rem uppercase blue, 2rem #6b8afd,
   2rem #4A90D9, 1.5rem dark…) and their own .page-header margin, so the title moved every time you
   changed page. These live here now; per-page copies were removed so every page shares one rhythm.
   Responsive tweaks inside a page's own @media block still win, which is intended. */
.page-header {
    margin-bottom: 24px;
}

.page-header-content {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
}

/* Breadcrumb above the title, where a page has one. */
.page-crumb {
    color: var(--muted);
    font-size: 13px;
    margin-bottom: 14px;
}

.page-title {
    font-size: 30px;
    font-weight: 700;
    letter-spacing: -.01em;
    line-height: 1.15;
    color: var(--ink);
    text-transform: none;
    margin: 0;
}

.page-subtitle {
    color: var(--muted);
    margin: 6px 0 0;
    font-size: 14px;
    max-width: 860px;
}

/* Section heading inside a page (walkthrough h2). */
.section-title {
    font-size: 17px;
    font-weight: 700;
    color: var(--ink);
    margin-bottom: 12px;
}

/* ---- Loading / empty / error / status states, defined ONCE -------------------------------------
   These were copy-pasted into ~20 scoped stylesheets, so any component that used one WITHOUT owning a
   copy rendered bare — Blazor CSS isolation only matches elements inside the component the stylesheet
   belongs to. Global means every page gets them, and they can't drift apart. */
.loading-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    padding: 3rem;
    color: var(--muted);
}

.spinner {
    width: 40px;
    height: 40px;
    border: 3px solid var(--line);
    border-top-color: var(--blue);
    border-radius: 50%;
    animation: spin 1s linear infinite;
}

@keyframes spin {
    to { transform: rotate(360deg); }
}

.error-state {
    text-align: center;
    padding: 3rem;
    color: var(--muted);
}

.empty-state {
    text-align: center;
    padding: 4rem 2rem;
    background: #ffffff;
    border: 1px solid var(--line);
    border-radius: 9px;
    color: var(--muted);
}

.empty-icon {
    font-size: 3rem;
    margin-bottom: 1rem;
}

.status-message {
    margin-top: 1rem;
    padding: 0.6rem 0.8rem;
    border-radius: 7px;
    font-size: 0.875rem;
}

/* Main Header Styles */
.main-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem 2rem;
    background-color: #ffffff;
    border-bottom: 1px solid #e9ecef;
}

.header-brand {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    text-decoration: none;
}

.header-brand .brand-bar {
    width: 4px;
    height: 24px;
    background-color: #4A90D9;
    border-radius: 2px;
}

.header-brand .brand-text {
    font-size: 1.125rem;
    font-weight: 600;
    color: #1a1a1a;
    letter-spacing: 0.5px;
}

.header-right {
    display: flex;
    align-items: center;
    gap: 1rem;
}

.user-avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    background-color: #4A90D9;
    border-radius: 50%;
    text-decoration: none;
    transition: opacity 0.2s;
}

.user-avatar:hover {
    opacity: 0.85;
}

.avatar-initials {
    color: #ffffff;
    font-size: 0.875rem;
    font-weight: 500;
}

/* Profile Page Styles */
.profile-container {
    max-width: 600px;
    margin: 2rem auto;
    padding: 2rem;
}

.profile-info {
    background-color: #f8f9fa;
    padding: 1.5rem;
    border-radius: 8px;
    margin-top: 1rem;
}

.profile-info p {
    margin: 0.5rem 0;
}

.not-authorized {
    text-align: center;
    padding: 3rem;
}

.not-authorized a {
    display: inline-block;
    margin-top: 1rem;
    padding: 0.75rem 1.5rem;
    background-color: #0066cc;
    color: white;
    text-decoration: none;
    border-radius: 4px;
}

.not-authorized a:hover {
    background-color: #0052a3;
}

/* Button Styles — the walkthrough's `button` / `button.pri` pair (specs/docs). Secondary is the plain
   white button with a hairline; primary is solid --blue. The old pale #79B7FE primary and grey #6c757d
   secondary read as a different product next to the designs. */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font: inherit;
    font-size: 14px;
    padding: 10px 17px;
    border-radius: 7px;
    border: 1px solid var(--line);
    background-color: #ffffff;
    color: var(--ink);
    text-decoration: none;
    cursor: pointer;
    transition: all 0.15s ease;
}

.btn:hover {
    background-color: var(--th);
}

.btn-primary {
    background-color: var(--blue);
    border-color: var(--blue);
    color: #ffffff;
    font-weight: 600;
}

.btn-primary:hover {
    background-color: #245a9e;
}

.btn-secondary {
    background-color: #ffffff;
    border-color: var(--line);
    color: var(--ink);
}

.btn-secondary:hover {
    background-color: var(--th);
}

.btn:disabled,
.btn[disabled] {
    opacity: .35;
    cursor: not-allowed;
}

.btn-large {
    padding: 0.75rem 1.5rem;
    font-size: 1rem;
}

/* Landing Page Styles */
.landing-content {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: calc(100vh - 60px);
    padding: 2rem;
}

.hero-section {
    text-align: center;
    max-width: 600px;
}

.hero-title {
    font-size: 2.5rem;
    font-weight: 600;
    color: #1a1a1a;
    margin-bottom: 1rem;
}

.hero-subtitle {
    font-size: 1.125rem;
    color: #6c757d;
    margin-bottom: 2rem;
}

.landing-title {
    font-size: clamp(2rem, 8vw, 4rem);
    font-weight: 600;
    color: #1a1a1a;
    text-align: center;
    margin: 0;
}

/* Accessibility: no focus ring on the page heading. FocusOnNavigate (Routes.razor) focuses the <h1>
   on navigation so screen readers announce the new page; Blazor makes it focusable with tabindex="-1".
   Chromium treats that programmatic focus as "visible", so even :focus-visible drew a full-width blue
   box around every page title on load — in prod too, cleared only when the user clicked. Focus still
   moves (the announcement is preserved); the heading just isn't outlined. It isn't interactive and Tab
   moves straight off it, so keyboard users lose nothing navigable. Plain :focus on purpose — the
   :focus:not(:focus-visible) form never matches here, exactly because Chromium calls this focus visible. */
h1[tabindex="-1"]:focus { outline: none; }

/* Form validation styles */
.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

/* Error boundary */
.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE44MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

.blazor-error-boundary::after {
    content: "An error has occurred."
}

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* Global base for .form-input. Blazor scoped CSS does NOT reach elements rendered by child
   components (e.g. <InputText>), so per-page scoped `.form-input { width: 100% }` rules never match
   the actual <input>, leaving them at the browser default ~139px. This global rule fixes width (and
   a sane base) everywhere; scoped sheets still layer page-specific tweaks on top. */
.form-input {
    width: 100%;
    box-sizing: border-box;
    padding: 0.625rem 0.875rem;
    border: 1px solid #d1d5db;
    border-radius: 8px;
    /* Inherit the app's sans-serif font — browsers default <textarea> to monospace, which otherwise
       makes the description box (and any textarea.form-input) render in the wrong font. */
    font-family: inherit;
    font-size: 0.9375rem;
    color: #1e293b;
    background-color: #ffffff;
}

.form-input:focus {
    outline: none;
    border-color: #4A90D9;
    box-shadow: 0 0 0 3px rgba(74, 144, 217, 0.12);
}

.form-input[readonly],
.form-input:disabled {
    background-color: #f8fafc;
    color: #64748b;
}

/* Global base for the form-group / label pattern (label above a full-width input). Same scoped-CSS
   reasoning as .form-input — pages relied on these classes but several had no styling, leaving labels
   and inputs shrunk to content. Scoped sheets still layer page-specific tweaks. */
.form-group {
    display: flex;
    flex-direction: column;
}

.form-label {
    font-size: 0.75rem;
    font-weight: 600;
    color: #64748b;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 0.375rem;
}

/* single letter prefix on the value field */
.input-prefix { position: relative; display: flex; align-items: center; }
.input-prefix .prefix {
    position: absolute;
    left: 0.9rem;
    color: #64748b;
    font-size: 0.95rem;
    pointer-events: none;
}
.input-prefix .form-input { padding-left: 1.9rem; }

textarea.form-input,
.form-textarea {
    min-height: 90px;
    resize: vertical;
    /* Belt-and-braces: force the app font on every textarea (browsers default to monospace) so it holds
       even if a page's scoped .form-input rule breaks the inherit chain, or a textarea lacks .form-input. */
    font-family: inherit;
    font-size: 0.9375rem;
}

/* Any textarea, even without .form-input, must use the app's sans-serif font — never the browser's
   monospace default. Scoped so it doesn't fight the richer .form-input styling above. */
textarea {
    font-family: inherit;
}

/* App boot gate: shown by MembershipGate while the user's roles resolve, so no page flashes a
   guessed layout before the correct view is known. Full-viewport, centred, neutral. */
.app-boot {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    background-color: #ffffff;
}

.app-boot-spinner {
    width: 40px;
    height: 40px;
    border: 3px solid #e5e7eb;
    border-top-color: #4A90D9;
    border-radius: 50%;
    animation: app-boot-spin 0.8s linear infinite;
}

@keyframes app-boot-spin {
    to { transform: rotate(360deg); }
}


/* 020 offsite upload modal content */
.offsite-info {
    background: #eff6ff;
    color: #1e40af;
    border-radius: 10px;
    padding: 0.85rem 1rem;
    font-size: 0.9375rem;
    line-height: 1.4;
    margin-bottom: 1rem;
}
.offsite-required {
    border: 1px solid #e2e8f0;
    border-radius: 10px;
    padding: 1rem;
    margin-bottom: 1rem;
}
.offsite-required-title {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    color: #64748b;
    margin-bottom: 0.6rem;
}
.offsite-required-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.offsite-required-list li {
    position: relative;
    padding-left: 1.5rem;
    color: #334155;
    font-size: 0.9375rem;
}
.offsite-required-list li::before {
    content: "\25CB";
    position: absolute;
    left: 0;
    color: #94a3b8;
}
.offsite-dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    border: 2px dashed #bfdbfe;
    border-radius: 12px;
    background: #f8fbff;
    padding: 1.75rem 1rem;
    cursor: pointer;
    margin-bottom: 1rem;
}
.offsite-dropzone:hover { border-color: #93c5fd; background: #f1f7ff; }
/* Dragging files over the zone (class toggled by insiteproFileUpload.initDropzone). Solid border +
   stronger fill so it's clearly a live drop target, distinct from the subtler :hover state. */
.offsite-dropzone.is-dragover {
    border-style: solid;
    border-color: #3b82f6;
    background: #e6f0ff;
}
/* The children would otherwise become drag targets themselves and fire dragleave on the parent. */
.offsite-dropzone.is-dragover * { pointer-events: none; }
.offsite-dropzone-main {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    color: #2563eb;
    font-weight: 600;
}
.offsite-upload-icon { flex: none; }
.offsite-dropzone-sub { color: #94a3b8; font-size: 0.8125rem; }
/* Hide the native file input; the whole dropzone label is the click target. */
.offsite-file-input {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    border: 0;
}
.offsite-status { color: #64748b; font-size: 0.875rem; margin: 0.25rem 0; }
.offsite-error { color: #b91c1c; font-size: 0.875rem; margin: 0.25rem 0; }
.offsite-attached-title {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    color: #64748b;
    margin: 0.5rem 0 0.5rem;
}
.offsite-empty { color: #94a3b8; font-size: 0.9375rem; margin: 0; }
.offsite-attached-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.offsite-attached-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    border: 1px solid #eef1f4;
    border-radius: 10px;
    padding: 0.7rem 0.9rem;
}
.offsite-file-name { display: block; font-weight: 600; color: #1e293b; font-size: 0.9375rem; }
.offsite-file-meta { display: block; color: #94a3b8; font-size: 0.8125rem; }
.offsite-file-action {
    background: none; border: none; color: #2563eb; font-weight: 600; font-size: 0.875rem; cursor: pointer;
}
.offsite-file-action:hover { text-decoration: underline; }

/* ===== 026 subcontractors (shared across Subcontractors + SubcontractLines pages) ===== */
/* Page shell only — AppLayout already centres the content and provides the outer padding, so setting a
   second max-width + padding here boxed the page inside the shell and made it read narrower and more
   inset than the rest of the app (and than the walkthrough design). Matches .list-page-container. */
/* ---- The table skin, defined ONCE for every table in the app ---------------------------------
   Wrapper is the white card and handles overflow; the table inside it is plain. Was seven identical
   copies pasted into seven scoped stylesheets — a new table style meant seven edits, and any table
   whose component lacked a copy rendered bare. Values are the walkthrough's (specs/docs). */
.sub-table-wrap,
.claims-table-wrapper,
.projects-table-wrapper,
.data-table-wrapper,
.documents-table-wrapper,
.overview-table-wrapper {
    background: #ffffff;
    border: 1px solid var(--line);
    border-radius: 9px;
    overflow-x: auto;
    box-shadow: none;
}

.sub-table,
.claims-table,
.projects-table,
.data-table,
.documents-table,
.overview-table,
.schedule-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    background: transparent;
}

.sub-table thead,
.claims-table thead,
.projects-table thead,
.data-table thead,
.documents-table thead,
.overview-table thead,
.schedule-table thead {
    background: var(--th);
}

.sub-table th,
.claims-table th,
.projects-table th,
.data-table th,
.documents-table th,
.overview-table th,
.schedule-table th {
    text-align: left;
    font-size: 11.5px;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--muted);
    font-weight: 700;
    padding: 14px 20px;
    border-bottom: 1px solid var(--line);
    white-space: nowrap;
}

.sub-table td,
.claims-table td,
.projects-table td,
.data-table td,
.documents-table td,
.overview-table td,
.schedule-table td {
    padding: 16px 20px;
    border-bottom: 1px solid var(--line2);
    vertical-align: middle;
    font-size: 14px;
    color: var(--ink);
}

.sub-table tbody tr:last-child td,
.claims-table tbody tr:last-child td,
.projects-table tbody tr:last-child td,
.data-table tbody tr:last-child td,
.documents-table tbody tr:last-child td,
.overview-table tbody tr:last-child td,
.schedule-table tbody tr:last-child td {
    border-bottom: 0;
}

/* Right-aligned numerics, shared by every table. */
.sub-table td.num, .sub-table th.num,
.claims-table td.num, .claims-table th.num,
.data-table td.num, .data-table th.num,
.overview-table td.num, .overview-table th.num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Rows that navigate. Was defined in five scoped stylesheets, so a sixth table meant a sixth copy. */
.clickable-row {
    cursor: pointer;
    transition: background 0.1s ease;
}

tbody tr.clickable-row:hover {
    background: var(--th);
}

.sub-page { width: 100%; }
/* The invite card's fields, laid out like the walkthrough rather than one stretched full-width input. */
/* The project filter on the Subcontractors area — a control above the roster, not a page of its own. */
.sub-filter { margin-bottom: 20px; max-width: 320px; }

/* Three columns, as the walkthrough draws the invite card. Fixed rather than auto-fit so a single field
   keeps a third of the width instead of stretching across the whole card. */
.sub-grid3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
@media (max-width: 700px) { .sub-grid3 { grid-template-columns: 1fr; } }
.sub-static { font-size: 14px; color: #1A2331; padding: 9px 0; }
.sub-loading, .sub-empty, .sub-note { color: #5C6472; font-size: 14px; }
.sub-denied { background: #fff; border: 1px solid #E1E5EC; border-radius: 9px; padding: 24px; color: #C0392B; }
/* The subcontract pages used to carry their own .sub-head / .sub-crumb / .sub-sub — a second page-head
   pattern sitting alongside the canonical one. They now use .page-header / .page-crumb / .page-title /
   .page-subtitle like every other page; only the crumb's link colour is page-head specific. */
.page-crumb a { color: var(--brand); text-decoration: none; }
.page-crumb a:hover { text-decoration: underline; }
.sub-section { margin-bottom: 32px; }
.sub-section h2 { font-size: 17px; font-weight: 700; color: #1A2331; margin-bottom: 12px; }
.sub-table td.num, .sub-table th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.sub-dim { color: #5C6472; }
.sub-status { font-size: 14px; font-weight: 600; white-space: nowrap; }
.sub-status.ok { color: #2EA661; }
.sub-card { background: #fff; border: 1px solid #E1E5EC; border-radius: 9px; padding: 24px; }
.sub-label { display: block; font-size: 11.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: #5C6472; margin-bottom: 6px; }
.sub-acts { display: flex; gap: 10px; justify-content: flex-end; align-items: center; margin-top: 20px; }
.sub-fill { margin-right: auto; color: #5C6472; font-size: 13px; }
.sub-msg { font-size: 13px; margin-top: 10px; }
.sub-msg.ok { color: #2EA661; }
.sub-msg.err { color: #C0392B; }
.sub-cb { width: 16px; height: 16px; accent-color: #0174DA; }
.sub-link { color: #0174DA; text-decoration: none; font-size: 13.5px; }
.sub-link:hover { text-decoration: underline; }
.contract-sub-link { color: #0174DA; text-decoration: none; font-size: 13px; margin-left: 12px; }
.contract-sub-link:hover { text-decoration: underline; }
.sub-scope { background: #fff; border: 1px solid #E1E5EC; border-left: 4px solid #6FC3A8; border-radius: 8px; padding: 14px 18px; color: #5C6472; font-size: 13.5px; margin-bottom: 24px; }
.sub-scope b { color: #1A2331; }
.sub-table tr.sub-total td { background: #F7F9FC; font-weight: 700; }
.pc-input { max-width: 90px; text-align: right; }

/* ===== 028 organisation signup/onboarding (global: shared by both routes) ===== */
/* Centred in what is left below the header. Auto margins on the card rather than justify-content, so a
   card taller than the viewport scrolls instead of having its top clipped. */
.signup-container, .new-org-container {
    max-width: 460px; margin: 0 auto; padding: 1.5rem 1rem;
    min-height: calc(100dvh - 65px); display: flex; flex-direction: column;
}
.signup-container > .card, .new-org-container > .card { margin: auto 0; }
.signup-container .card, .new-org-container .card {
    background: #fff; border: 1px solid #e2e8f0; border-radius: 12px;
    padding: 2rem 2rem 1.75rem; box-shadow: 0 4px 16px rgba(15, 23, 42, .06);
}
.signup-container .page-title, .new-org-container .page-title {
    font-size: 1.5rem; font-weight: 700; color: #1e293b; margin: 0 0 .75rem;
    letter-spacing: -.01em;
}
.signup-summary, .new-org-summary { color: #64748b; line-height: 1.55; margin: 0 0 1.5rem; font-size: .9375rem; }
.setup-form { display: flex; flex-direction: column; gap: 1.1rem; }
.setup-form .form-group { display: flex; flex-direction: column; gap: .375rem; margin: 0; }
.setup-form .form-group label {
    font-size: .8125rem; font-weight: 600; color: #475569; text-transform: uppercase; letter-spacing: .03em;
}
.setup-form .field-note { margin: .1rem 0 0; font-size: .8125rem; line-height: 1.45; color: #94a3b8; }
.setup-form .validation-message { color: #b91c1c; font-size: .8125rem; }
/* One question, one action: a right-aligned button next to a single field reads like an afterthought. */
.setup-form .form-actions { display: flex; margin-top: .25rem; }
.setup-form .form-actions .btn { width: 100%; }
/* The router focuses the h1 on navigation, which paints a box around the title for mouse users. Keyboard
   users keep their ring via :focus-visible. */
.signup-container .page-title:focus:not(:focus-visible),
.new-org-container .page-title:focus:not(:focus-visible) { outline: none; }
.signup-alt {
    margin: 1.5rem 0 0; padding-top: 1.25rem; border-top: 1px solid #e2e8f0;
    font-size: .875rem; color: #64748b; text-align: center;
}
.setup-form .error-message {
    color: #b91c1c; background: #fee2e2; border-radius: 6px; padding: .6rem .8rem;
    margin: 0; font-size: .875rem;
}

/* ===== 031 landing page (global, for the same reason the block above is: a scoped .razor.css cannot
   reach .btn, which is defined here and rendered by the page). The landing page deliberately borrows
   this feature's card, title and summary rather than inventing a look — no walkthrough in
   specs/docs/Latest/ draws a landing or login page, so there is nothing to trace a new one to. ===== */
/* Full-width actions, matching .setup-form .form-actions: one decision, one full-width control, so the
   secondary action reads as an alternative rather than as an afterthought pinned to a corner. */
.landing-actions { display: flex; margin-top: .25rem; }
.landing-actions .btn { width: 100%; }
/* The signup offer keeps .signup-alt's rule (a hairline above it, centred, muted) and adds a real button.
   A text link there is what the old page had, and demoting signup must not amount to hiding it. */
.landing-alt .btn { display: flex; width: 100%; margin-top: .625rem; }
.landing-alt-lead { margin: 0; font-size: .875rem; color: #64748b; }

/* ================================================================================================
   030 SUBCONTRACT PACKAGES — the walkthrough's card-and-grid rhythm.

   Every structural class the five package screens were written against — .card, .note, .crumb,
   .acts, .kv, the stat row, the field grids — existed in the markup and nowhere in this sheet, so
   the screens rendered as unstyled stacked text. That is the 027 lesson arriving from the other
   direction: not a scoped stylesheet failing to reach a component, but a component reaching for
   classes nobody had defined. They are defined here, once, in the global sheet.

   The values are lifted from specs/docs/Latest/subbie-setup.html rather than approximated — the
   walkthrough is the design, and the demo class each rule comes from is named beside it so the two
   can be compared without guessing.
   ================================================================================================ */

/* The contract/package screens' title treatment (demo .ctitle / .ctsub). Deliberately an opt-in
   modifier on the canonical .page-title rather than a change to it: thirteen other pages share that
   definition, and whether the whole product moves to the blue caps treatment is a product decision,
   not this feature's to make. */

/* Breadcrumb above those titles (demo .cbrd). */
.crumb {
    color: var(--muted);
    font-size: 13.5px;
    margin-bottom: 20px;
}
.crumb b { color: #1F2937; font-weight: 600; }
.crumb a { color: var(--muted); text-decoration: none; }
.crumb a:hover { text-decoration: underline; }

/* Section heading inside these screens (demo h2.ch — 22px, sentence case, no tracking). Larger than
   the app's .section-title because these screens are built from a few big blocks rather than many
   small ones. */
.section-heading {
    font-size: 22px;
    font-weight: 700;
    color: var(--ink);
    margin: 0 0 16px;
    letter-spacing: 0;
    text-transform: none;
}

/* The white panel every block on these screens sits in (demo .card). Named .panel because .card is
   already spoken for by the signup/new-organisation containers. */
.panel {
    background: #fff;
    border: 1px solid var(--line);
    border-radius: 9px;
    padding: 24px;
    /* The section rhythm, and the demo's own 30px. The walkthrough carries it on `table.ct`, so the
       next `h2.ch` clears the table it follows — but every 030 table is wrapped in this card, and a
       margin on the table lands INSIDE the card where it can separate nothing from the heading below
       it. Every h2 on the subcontractor's claim after the first therefore sat flush against the card
       above it. The wrapper carries the gap because the wrapper is what the heading has to clear.

       Here rather than in a scoped sheet: .panel is shared by six 030 screens and a .razor.css can
       only reach the component it belongs to — the third time that has caught this feature out. */
    margin-bottom: 30px;
}

/* …and the card does not spend that 30px twice. A table or a note that ends a card already has the
   card's own 24px of padding under it; the demo's margin below it is what the wrapper now carries. */
.panel > .ct-table:last-child,
.panel > .note:last-child { margin-bottom: 0; }

/* The explanatory line under a card or table (demo .note). */
.note {
    color: var(--muted);
    font-size: 13px;
    margin-top: 12px;
    max-width: 940px;
}

/* A note about the table above it is part of that table's block, and the demo writes exactly this
   inline wherever it draws one (`style="margin:-18px 0 30px"`): pulled up under the table so the two
   read as one thing, and carrying the 30px on to whatever follows. Without it the packages list —
   whose tables are not in cards — ran its Subcontractor Claims heading straight into the note above. */
.ct-table + .note { margin: -18px 0 30px; }

/* Position: the five-box stat row (demo .dcard / .dsec / .dg.dg5 / .dl / .dv2). */
.stat-card {
    background: #F7F9FB;
    border: 1px solid #E4E8EE;
    border-radius: 10px;
    padding: 26px 30px;
    margin: 24px 0 36px;
}
.stat-card-title {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: #6B6257;
    margin-bottom: 18px;
}
.stat-grid { display: grid; gap: 22px 26px; }
.stat-grid-3 { grid-template-columns: repeat(3, 1fr); }
.stat-grid-5 { grid-template-columns: repeat(5, 1fr); }
.stat-label { color: #8A94A3; font-size: 12.5px; margin-bottom: 6px; }
.stat-value { color: var(--ink); font-size: 15px; font-weight: 700; }

/* Field grids inside a panel (demo .grid2 / .grid3). */
.form-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.form-grid3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }

/* A group of terms switched off: the inputs grey themselves, this carries their labels with them so the
   block reads as inactive rather than as live labels above dead fields. */
.terms-off .field-label { color: #94a3b8; }

/* The uppercase field label the demo uses inside these cards (demo label.k). */
.field-label {
    display: block;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 6px;
}

/* Key/value row — the balance line, the retention figures (demo .kv). */
.kv {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 11px 0;
    border-bottom: 1px solid var(--line2);
    font-size: 14px;
}
.kv:last-child { border-bottom: 0; }
.kv > span:first-child { color: var(--muted); }
.kv > span:last-child { font-weight: 600; text-align: right; color: var(--ink); }

/* Status words (demo .s / .s.ok / .s.warn). */
.s { font-size: 14px; font-weight: 600; white-space: nowrap; }
.s.ok { color: var(--ok, #2EA661); }
.s.warn { color: #E89720; }
.s.off { color: var(--muted); }

/* The action bar at the foot of a build screen (demo .acts). */
.acts {
    display: flex;
    gap: 10px;
    justify-content: flex-end;
    align-items: center;
    margin-top: 20px;
}
.acts .fill { margin-right: auto; color: var(--muted); font-size: 13px; }

/* Toggle row and switch (demo .tog / .sw). */
.tog {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    padding: 14px 0;
    border-bottom: 1px solid var(--line2);
    font-size: 14px;
}
.tog:last-child { border-bottom: 0; }
.dim { color: var(--muted); }
hr.dv { border: 0; border-top: 1px solid var(--line2); margin: 22px 0; }

/* The document drop zone (demo #dropZone). */
.drop-zone {
    border: 1.5px dashed #C4CEDA;
    border-radius: 9px;
    padding: 22px;
    text-align: center;
}

/* "To This Package": a compact right-aligned money field, and the whole control — the reference is
   what the field says (demo table.ct input, 74px and right-aligned, widened here because our figures
   carry cents). .cell-actions and .placed stood beside it while a Place button did the committing;
   with the field committing itself there is nothing left to lay out next to it. */
.money-input {
    width: 118px;
    text-align: right;
    font-variant-numeric: tabular-nums;
    display: inline-block;
}

/* Row status colours on the project list (demo table.mp .stA / .stC / .stD). */
.project-status { font-weight: 600; }
.project-status.status-active { color: #16A34A; }
.project-status.status-completed { color: #4A90D9; }
.project-status.status-draft { color: var(--muted); }
.action-cell { text-align: right; }
.client-cell { color: #2F7FE0; }

.empty-state-hint { color: var(--muted); font-size: 13px; margin-top: 8px; }

/* A text button that reads as a link inside a table cell. */
.btn-link {
    background: none;
    border: 0;
    padding: 0;
    color: var(--blue, #2D6CB8);
    font: inherit;
    font-size: 13.5px;
    cursor: pointer;
}
.btn-link:hover { text-decoration: underline; }

/* 030 / FR-038 — the Backup column on a subcontractor's claim line. The file input itself is hidden
   and the label is the control, because claim-flow (1).html draws "Attach" as a link and a browser's
   own file button cannot be made to look like one. */
.backup-cell { white-space: nowrap; }
.backup-count { margin-right: 8px; }
.backup-attach { color: var(--blue, #2D6CB8); font-size: 13.5px; cursor: pointer; }
.backup-attach:hover { text-decoration: underline; }
.backup-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
/* The files themselves, revealed under the count. One per line, because a file name is the only thing
   that tells the contractor which piece of evidence they are about to open. */
.backup-files { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; margin-top: 6px; }
.backup-file { max-width: 220px; overflow: hidden; text-overflow: ellipsis; }

/* ================================================================================================
   030 TABLES — Title Case headers, in the walkthrough's two treatments.

   Every table in subbie-setup.html and subbie-flow.html is Title Case. The app's shared table rules
   above render 11.5px UPPERCASE letter-spaced headers, so all fourteen 030 tables came out in a
   treatment the design never uses. These are the demo's own two, added as opt-in classes rather than
   as a change to .data-table / .projects-table / .claims-table: those three are shared with thirteen
   screens outside this feature, and restyling the product's tables is not this feature's call.

   The values are copied from the walkthrough, with the demo class each rule comes from named beside
   it. Two things had to be interpreted rather than copied, both because the demo writes bare markup
   and we write a <thead>:

     * The demo scopes to `> tbody > tr > th` because its rows are direct children of an implicit
       tbody with no header row of its own. Ours are `thead th` / `tbody td`, so the child combinator
       is dropped and the selectors are plain descendants.
     * The demo's `tr:first-child td{border-top:0}` means "the first row of the table". With a thead
       that is `tbody tr:first-child td`, which is what it says here.
   ================================================================================================ */

/* Last, so it beats the header's left-align at equal specificity — as it does in the demo. */

/* Space above a second section on a page that stacks several — My Claims under My Projects, and the
   subcontract tables under either. */
.section-gap { margin-top: 3rem; }

/* (b) DETAIL treatment (demo table.ct) — everything inside a page: schedules, review lines,
   variations, the claim overview. Bordered, centred, with the first two columns left-aligned. */
.ct-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: 9px;
    overflow: hidden;
    margin-bottom: 30px;
}
.ct-table th {
    background: var(--th);
    text-align: left;
    font-size: 11.5px;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--muted);
    padding: 14px 20px;
    font-weight: 700;
    white-space: nowrap;
    border-bottom: 1px solid var(--line);
}
.ct-table td {
    padding: 16px 20px;
    border-bottom: 1px solid var(--line2);
    vertical-align: middle;
    font-size: 14px;
    color: var(--ink);
    background: #fff;
}
.ct-table tr:last-child td { border-bottom: 0; }
.ct-table tr.tot td { background: var(--th); font-weight: 700; }
.ct-table td.num, .ct-table th.num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
/* The trailing action column (demo td.act), on a .ct table too — the package list is a detail table
   that still ends in a row action. */
.ct-table td.act, .ct-table th.act { text-align: right; padding-right: 14px; }
/* Two actions on one row — Edit beside Remove on the subcontractor's own schedule (FR-033). Here
   rather than in a scoped sheet because .ct-table itself is global and a .razor.css cannot reach it. */
.ct-table td.act .btn-link + .btn-link { margin-left: 14px; }
/* A field editing a cell fills it: the column is already the width the figure needs. */
.ct-table td .form-input { width: 100%; }
.ct-table td .money-input { width: 118px; }

@media (max-width: 900px) {
    .stat-grid-3, .stat-grid-5 { grid-template-columns: repeat(2, 1fr); }
    .form-grid2, .form-grid3 { grid-template-columns: 1fr; }
}

